mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
490 Commits
feature/fu
...
boost-1.64
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5363e099e4 | ||
|
|
65f98979ff | ||
|
|
496acc1161 | ||
|
|
30dff7f84a | ||
|
|
7cb5d5bb46 | ||
|
|
74c98b7fab | ||
|
|
2ed0c2ad5f | ||
|
|
c969a6cf9c | ||
|
|
c7348b29cf | ||
|
|
f79d51f099 | ||
|
|
0d850b47ab | ||
|
|
9bbf9bed80 | ||
|
|
aadf0acce3 | ||
|
|
bd0379af57 | ||
|
|
336259c36a | ||
|
|
544eda51bd | ||
|
|
e16705a72a | ||
|
|
61a26492c3 | ||
|
|
854c61f597 | ||
|
|
4d4ddcdc36 | ||
|
|
9347d9b731 | ||
|
|
0a4733c9ad | ||
|
|
b96d05461f | ||
|
|
41f19bb098 | ||
|
|
050a45aaa4 | ||
|
|
23cff22e5a | ||
|
|
a75995475a | ||
|
|
3ac5fd0916 | ||
|
|
56bce64d32 | ||
|
|
4385984215 | ||
|
|
3391bf87c6 | ||
|
|
bc6b31e1f7 | ||
|
|
425b9924f0 | ||
|
|
84720b7664 | ||
|
|
1309e9aa4b | ||
|
|
50a926e973 | ||
|
|
a0bda34054 | ||
|
|
3a9a296e55 | ||
|
|
184d7504b7 | ||
|
|
2f8b5794b7 | ||
|
|
7e7d3bf1a7 | ||
|
|
f8b76aa907 | ||
|
|
7eeae5b265 | ||
|
|
e71f52f9ed | ||
|
|
cd41de6e3f | ||
|
|
7879a4c286 | ||
|
|
c70647988d | ||
|
|
11f18980ca | ||
|
|
866ff746ae | ||
|
|
12e2c8aaca | ||
|
|
807f429e17 | ||
|
|
046d716bbf | ||
|
|
5450e98c6b | ||
|
|
5b9c1fad85 | ||
|
|
c52a34c2cf | ||
|
|
fc748dbddf | ||
|
|
58c6b384cc | ||
|
|
e34d343c12 | ||
|
|
7c1570328e | ||
|
|
eeb24a6a6a | ||
|
|
25b2062881 | ||
|
|
9d33a59542 | ||
|
|
41f93eb513 | ||
|
|
63484911c6 | ||
|
|
bb2c38aa61 | ||
|
|
8cf36f18cc | ||
|
|
97895e410f | ||
|
|
7ffdc5e10a | ||
|
|
25864ce33a | ||
|
|
f0c50a00c0 | ||
|
|
b511472614 | ||
|
|
13c15cd002 | ||
|
|
1296bf4de9 | ||
|
|
9c80dd207e | ||
|
|
0f2fed0577 | ||
|
|
96390e1b46 | ||
|
|
e2ff1e4c67 | ||
|
|
49ab2e8619 | ||
|
|
96b96b4e42 | ||
|
|
a774cac3f2 | ||
|
|
6ec16408fc | ||
|
|
850f3eced3 | ||
|
|
fde2e061f5 | ||
|
|
e5c086cef4 | ||
|
|
0b5e4f88b5 | ||
|
|
8d150587fa | ||
|
|
206ff0ba7c | ||
|
|
0ef1b1b760 | ||
|
|
ab9f931bce | ||
|
|
21b084384c | ||
|
|
ccca616330 | ||
|
|
2494f3fc7a | ||
|
|
2c3acef281 | ||
|
|
587ad42548 | ||
|
|
ef401d81db | ||
|
|
57f34e1ea4 | ||
|
|
daae305bf7 | ||
|
|
55a1325f30 | ||
|
|
46f0be2dce | ||
|
|
98dbc9da41 | ||
|
|
640e1acb98 | ||
|
|
7f2535015d | ||
|
|
aab2891cdb | ||
|
|
8bbe005bbc | ||
|
|
db5898ba46 | ||
|
|
c7a5122fd3 | ||
|
|
b932b8c015 | ||
|
|
411798367b | ||
|
|
e29a4129e8 | ||
|
|
159868ac77 | ||
|
|
f6febf8dfc | ||
|
|
f65e89a85a | ||
|
|
2fd8a8dd55 | ||
|
|
bb47c16939 | ||
|
|
9db70b803d | ||
|
|
47357de276 | ||
|
|
02fd2d041b | ||
|
|
382ac5a426 | ||
|
|
317a735836 | ||
|
|
ae22c68ab7 | ||
|
|
4fb88b29fa | ||
|
|
2661c06698 | ||
|
|
a45f36cbc6 | ||
|
|
5fba7f88a6 | ||
|
|
ad7b36dd34 | ||
|
|
408d82ded9 | ||
|
|
3f5c0bfb6c | ||
|
|
8a5cf38a3c | ||
|
|
0ddc3d40fa | ||
|
|
565c8e0bb8 | ||
|
|
6954e6ca64 | ||
|
|
568275dc5f | ||
|
|
1d04db8887 | ||
|
|
83f877a238 | ||
|
|
7beae6ac06 | ||
|
|
dc078f0394 | ||
|
|
47f615d073 | ||
|
|
6374e09021 | ||
|
|
9f55587ab0 | ||
|
|
7079a80edf | ||
|
|
674e1304ef | ||
|
|
4ad37504ee | ||
|
|
29849ca3ec | ||
|
|
a636c8d605 | ||
|
|
dbf28a4ac4 | ||
|
|
dbf0160b1e | ||
|
|
60a8cb9b5c | ||
|
|
8cba434c59 | ||
|
|
feab8add3f | ||
|
|
f36857ffef | ||
|
|
4ba8415b08 | ||
|
|
aa608685af | ||
|
|
ba43e202c3 | ||
|
|
3edbf67ef0 | ||
|
|
7b67789f98 | ||
|
|
3f7f34b634 | ||
|
|
c0fe04ecc9 | ||
|
|
eb6d819218 | ||
|
|
578bb1b3ed | ||
|
|
40b3dc0c2c | ||
|
|
55536c3e23 | ||
|
|
2866734b15 | ||
|
|
c0317c5206 | ||
|
|
06d2571ec6 | ||
|
|
fdaba4efe7 | ||
|
|
8a7cd83123 | ||
|
|
98a5e343f8 | ||
|
|
89d8e18c82 | ||
|
|
d9492530bd | ||
|
|
f6c732b124 | ||
|
|
dcc3227668 | ||
|
|
b3d237731a | ||
|
|
4321b59c1e | ||
|
|
67759325eb | ||
|
|
8153e2a652 | ||
|
|
7876163c68 | ||
|
|
805fa41a4e | ||
|
|
0e6376d93a | ||
|
|
bf1fc5158e | ||
|
|
1e4e9ab84c | ||
|
|
88ab663ac5 | ||
|
|
0ab63b9248 | ||
|
|
73053e4abe | ||
|
|
9a4fbbec5d | ||
|
|
b4744a2aa8 | ||
|
|
4169bcee44 | ||
|
|
baf516e82f | ||
|
|
cc309eef8d | ||
|
|
45cc1704ef | ||
|
|
278a06fd47 | ||
|
|
6ed577f4eb | ||
|
|
bf8459cf23 | ||
|
|
ad3cf1189e | ||
|
|
b8db8fef8b | ||
|
|
384c71dbe6 | ||
|
|
111574cf0c | ||
|
|
759601d08a | ||
|
|
c60d152102 | ||
|
|
6ff4fe1a89 | ||
|
|
2c0c4ead7f | ||
|
|
dacd6deb0a | ||
|
|
c7df715709 | ||
|
|
ddd26b5bb8 | ||
|
|
f0228ff559 | ||
|
|
4acaddd166 | ||
|
|
3a65295d7d | ||
|
|
773f8bfcb4 | ||
|
|
8afcbe22af | ||
|
|
450f34daed | ||
|
|
ea9eb62802 | ||
|
|
971c028c9a | ||
|
|
3f8618b42b | ||
|
|
9a8759a3dd | ||
|
|
9ac736a4c4 | ||
|
|
730cb550e6 | ||
|
|
8f5de1d7c3 | ||
|
|
0fdd4fc620 | ||
|
|
a86e2ebcc4 | ||
|
|
18cbf4b055 | ||
|
|
6029447774 | ||
|
|
205a1d7e2b | ||
|
|
2af9c7b98e | ||
|
|
baca517058 | ||
|
|
26486b0288 | ||
|
|
f8ff41e34b | ||
|
|
16ece266a4 | ||
|
|
4224a9f4df | ||
|
|
2e17e028b1 | ||
|
|
febe4a814d | ||
|
|
242cf35c51 | ||
|
|
c1ee2bfbd8 | ||
|
|
b30cde32d4 | ||
|
|
ac3f7eb037 | ||
|
|
9f883f6ad7 | ||
|
|
b332f17825 | ||
|
|
a3497e1ffc | ||
|
|
89b119f65f | ||
|
|
1ae07f3f3a | ||
|
|
0143748de8 | ||
|
|
ac603f6bd1 | ||
|
|
6aeac1e33e | ||
|
|
ff375e2780 | ||
|
|
5b1c755e42 | ||
|
|
b8dbe960b7 | ||
|
|
4f9a08c418 | ||
|
|
44272d3b7c | ||
|
|
ccd1cd5808 | ||
|
|
8c974800f9 | ||
|
|
6e002ae3ec | ||
|
|
2a375808c4 | ||
|
|
55c21919fc | ||
|
|
91e2cded63 | ||
|
|
b980b88474 | ||
|
|
7cb5211e25 | ||
|
|
958b773d05 | ||
|
|
4d45da6c06 | ||
|
|
e39703ff18 | ||
|
|
aafd5ca726 | ||
|
|
9b69912801 | ||
|
|
259c08473d | ||
|
|
6ca3a99cbc | ||
|
|
3dcd875944 | ||
|
|
58e8addad6 | ||
|
|
87615d54dd | ||
|
|
d322aba077 | ||
|
|
c0afe2d873 | ||
|
|
5488482a44 | ||
|
|
1480d6fc99 | ||
|
|
131c92a7d8 | ||
|
|
71d9a0a120 | ||
|
|
b7b2a463cf | ||
|
|
c50d0ac4ba | ||
|
|
1b2736012c | ||
|
|
5205fa71bf | ||
|
|
ba2988a8f7 | ||
|
|
650956bd3b | ||
|
|
e598796eaf | ||
|
|
bce7eabba2 | ||
|
|
0218136ed7 | ||
|
|
461bf803fc | ||
|
|
1bd78bbeea | ||
|
|
348da6b7e4 | ||
|
|
e850218c49 | ||
|
|
385eefd3b3 | ||
|
|
2ddf7aad0b | ||
|
|
c9433c2a5b | ||
|
|
8853a4cbdf | ||
|
|
6f53279b50 | ||
|
|
f25bc8bbab | ||
|
|
5c442e068c | ||
|
|
0bed674233 | ||
|
|
66193b0d38 | ||
|
|
45c9a1d7fd | ||
|
|
0d8ddfe378 | ||
|
|
74f479d5c9 | ||
|
|
dbf793e7eb | ||
|
|
b5c6f760c5 | ||
|
|
0f6a3ebbe5 | ||
|
|
a5c34e7be2 | ||
|
|
287100119a | ||
|
|
ba2f814342 | ||
|
|
5169a5414b | ||
|
|
82b9a4e28c | ||
|
|
e989d2f626 | ||
|
|
331f0b9325 | ||
|
|
ec6a1fcf80 | ||
|
|
dcebe26a11 | ||
|
|
d7721940f3 | ||
|
|
b678edb0d8 | ||
|
|
1371728e02 | ||
|
|
17d802db81 | ||
|
|
9fc06a8741 | ||
|
|
946fac633e | ||
|
|
af1c7d0c26 | ||
|
|
d9594e7fc8 | ||
|
|
0653efff3d | ||
|
|
566199e49b | ||
|
|
c7bb6fa318 | ||
|
|
c678b3794b | ||
|
|
e0ce8af1d9 | ||
|
|
c54dbe30a2 | ||
|
|
b8763b05ad | ||
|
|
3755af2063 | ||
|
|
41172e4814 | ||
|
|
25310eaf7c | ||
|
|
55f9563f60 | ||
|
|
ec770eeb6a | ||
|
|
b9ab307912 | ||
|
|
83ced837fa | ||
|
|
ce2b2801d6 | ||
|
|
1ae96b3820 | ||
|
|
889c178173 | ||
|
|
7ba9591015 | ||
|
|
b07f18facf | ||
|
|
7b1b1b5daa | ||
|
|
63fb28c7d4 | ||
|
|
67e18ff039 | ||
|
|
e715d74a95 | ||
|
|
393d214ac9 | ||
|
|
855e56076b | ||
|
|
0fa6038f6a | ||
|
|
cf1182ee99 | ||
|
|
a04497af24 | ||
|
|
821a93ca1a | ||
|
|
e0217424f3 | ||
|
|
cf76bc666c | ||
|
|
d00e39acc7 | ||
|
|
90ba3ae7c6 | ||
|
|
b68702b56d | ||
|
|
3b2322db96 | ||
|
|
6a427ac4b6 | ||
|
|
ffd856073f | ||
|
|
f1fafb117a | ||
|
|
e2cda49b0b | ||
|
|
d1aa2eec56 | ||
|
|
1db0ba4639 | ||
|
|
a4e7eba1d4 | ||
|
|
67778b3278 | ||
|
|
a5e6952a95 | ||
|
|
3c6a183aa3 | ||
|
|
9cc1357c95 | ||
|
|
b571686e5d | ||
|
|
9c67be287e | ||
|
|
f599783444 | ||
|
|
d628b8d36c | ||
|
|
65c519c22c | ||
|
|
05e492c56c | ||
|
|
3c2321c37a | ||
|
|
6c72a2527f | ||
|
|
1bd09085db | ||
|
|
d6c3f15947 | ||
|
|
5960985355 | ||
|
|
84e2b7869d | ||
|
|
401f69f108 | ||
|
|
4f57e3fb61 | ||
|
|
fdf20f1adc | ||
|
|
990474ff47 | ||
|
|
786d842ad1 | ||
|
|
441c89d304 | ||
|
|
63098e84a2 | ||
|
|
71997bd9aa | ||
|
|
45510facc7 | ||
|
|
cf539064d6 | ||
|
|
3431736c88 | ||
|
|
095b53b2a2 | ||
|
|
7a63c40a01 | ||
|
|
c1148a66cc | ||
|
|
5fa0a5d4c5 | ||
|
|
75a8280701 | ||
|
|
2891aff469 | ||
|
|
e74fd82060 | ||
|
|
c16ec42941 | ||
|
|
b77eac3e37 | ||
|
|
5a141ccf99 | ||
|
|
35d7ae0d2e | ||
|
|
d9c7f95617 | ||
|
|
06b3f6a9d7 | ||
|
|
895b4a0ac5 | ||
|
|
eb14d3d958 | ||
|
|
9cb72849ee | ||
|
|
2c028aa014 | ||
|
|
ab026e239c | ||
|
|
3a48148462 | ||
|
|
9b9590730f | ||
|
|
8edc37930b | ||
|
|
ef48908f35 | ||
|
|
28ead512c1 | ||
|
|
6b60943f3e | ||
|
|
1fcaa47efa | ||
|
|
aac441392a | ||
|
|
6a34fc9c33 | ||
|
|
69d01b9bfd | ||
|
|
7b91ce7b64 | ||
|
|
978884ff0d | ||
|
|
ac8ca6eb04 | ||
|
|
1c16c52fe6 | ||
|
|
9299d26acf | ||
|
|
5577128bd8 | ||
|
|
e62c576944 | ||
|
|
ce8049f83f | ||
|
|
035217985c | ||
|
|
dfe95b3f2c | ||
|
|
e98447f974 | ||
|
|
deffa9aaf7 | ||
|
|
b87d26a900 | ||
|
|
6c9115fe39 | ||
|
|
b5b25eab1c | ||
|
|
803ba458ce | ||
|
|
c0470893d4 | ||
|
|
b2c445a030 | ||
|
|
6e37c55221 | ||
|
|
e1039e61f3 | ||
|
|
063b59e511 | ||
|
|
a342d1ccee | ||
|
|
811f3df98d | ||
|
|
8e1be55c6d | ||
|
|
421469686d | ||
|
|
72dfa02269 | ||
|
|
4c48b2276c | ||
|
|
8c7275cb9e | ||
|
|
14c5cff2ee | ||
|
|
83f38ea52c | ||
|
|
06a9f9ab6d | ||
|
|
e7f140cab6 | ||
|
|
1b99fe5587 | ||
|
|
b9a70f7aca | ||
|
|
ca87cbf57b | ||
|
|
929dc55a5a | ||
|
|
b29d9f850c | ||
|
|
1c81d8a4b1 | ||
|
|
7de29f4d45 | ||
|
|
9b0705cb6f | ||
|
|
3abdb869df | ||
|
|
f90e76a59c | ||
|
|
d4c8185cc9 | ||
|
|
e6501b5485 | ||
|
|
1ae3cb65f7 | ||
|
|
a8ad389bdd | ||
|
|
69c1d40750 | ||
|
|
58698f44f1 | ||
|
|
37afdd2e9a | ||
|
|
c87b24923a | ||
|
|
1210fc4859 | ||
|
|
d8b6ae6266 | ||
|
|
04e2223d5e | ||
|
|
579748e7a0 | ||
|
|
41c3914aaf | ||
|
|
8693eec4a4 | ||
|
|
3f699750a8 | ||
|
|
4f8243cf59 | ||
|
|
4f01891da7 | ||
|
|
efab5af918 | ||
|
|
4d03b410a8 | ||
|
|
c1925df81c | ||
|
|
cbf9fe8a5c | ||
|
|
6fd7dc0d94 | ||
|
|
a2f2924298 | ||
|
|
49d485f1aa | ||
|
|
d7251f223e | ||
|
|
20a6ef7de8 | ||
|
|
d5c41e4c4a | ||
|
|
b96b9904b7 | ||
|
|
304240b206 | ||
|
|
c61c139933 | ||
|
|
c3b98129e4 | ||
|
|
3891eeef52 | ||
|
|
f1370b1255 | ||
|
|
69f2a1df72 | ||
|
|
700301e382 | ||
|
|
952aa44a98 |
@@ -6,3 +6,5 @@ Portable C++ multi-threading. C++11, C++14.
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
|
||||
|
||||
|
||||
@@ -60,30 +60,36 @@ project boost/thread
|
||||
<toolset>gcc:<cxxflags>-Wno-long-long
|
||||
#<toolset>gcc:<cxxflags>-ansi
|
||||
#<toolset>gcc:<cxxflags>-fpermissive
|
||||
<toolset>gcc:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>gcc-4:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>gcc-5:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>gcc:<cxxflags>-Wunused-local-typedefs
|
||||
<toolset>gcc:<cxxflags>-Wunused-function
|
||||
<toolset>gcc:<cxxflags>-Wno-unused-parameter
|
||||
|
||||
<toolset>darwin:<cxxflags>-Wextra
|
||||
<toolset>darwin:<cxxflags>-pedantic
|
||||
#<toolset>darwin:<cxxflags>-ansi
|
||||
<toolset>darwin:<cxxflags>-fpermissive
|
||||
<toolset>darwin:<cxxflags>-Wno-long-long
|
||||
<toolset>darwin:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>darwin:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>darwin-4:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>darwin-5:<cxxflags>-Wno-variadic-macros
|
||||
#<toolset>darwin:<cxxflags>-Wunused-local-typedefs
|
||||
<toolset>darwin:<cxxflags>-Wunused-function
|
||||
<toolset>darwin:<cxxflags>-Wno-unused-parameter
|
||||
|
||||
#<toolset>pathscale:<cxxflags>-Wextra
|
||||
<toolset>pathscale:<cxxflags>-Wno-long-long
|
||||
<toolset>pathscale:<cxxflags>-pedantic
|
||||
|
||||
<toolset>clang:<warnings>on
|
||||
<toolset>clang:<cxxflags>-Wextra
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
<toolset>clang:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>clang:<warnings>on
|
||||
<toolset>clang:<cxxflags>-Wno-unused-parameter
|
||||
|
||||
#<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
#<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
@@ -116,8 +122,12 @@ project boost/thread
|
||||
<toolset>intel:<cxxflags>-wd1418
|
||||
<toolset>intel:<cxxflags>-wd2415
|
||||
|
||||
<toolset>msvc:<cxxflags>/wd4100
|
||||
<toolset>msvc:<cxxflags>/wd4512
|
||||
<toolset>msvc:<cxxflags>/wd6246
|
||||
|
||||
<target-os>windows:<define>WIN32_LEAN_AND_MEAN
|
||||
<target-os>windows:<define>BOOST_USE_WINDOWS_H
|
||||
|
||||
# : default-build <threading>multi
|
||||
: usage-requirements # pass these requirement to dependents (i.e. users)
|
||||
@@ -308,3 +318,5 @@ lib boost_thread
|
||||
<link>static:<define>BOOST_THREAD_USE_LIB=1
|
||||
<conditional>@usage-requirements
|
||||
;
|
||||
|
||||
boost-install boost_thread ;
|
||||
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software
|
||||
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
#include "../../../boost/atomic.hpp"
|
||||
#include "../../../boost/static_assert.hpp"
|
||||
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software
|
||||
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
|
||||
return 0;
|
||||
}
|
||||
#include "../../../boost/atomic.hpp"
|
||||
#include "../../../boost/static_assert.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -29,4 +29,12 @@ boostbook standalone
|
||||
<xsl:param>boost.root=../../../..
|
||||
;
|
||||
|
||||
|
||||
###############################################################################
|
||||
alias boostdoc
|
||||
: thread
|
||||
:
|
||||
:
|
||||
: ;
|
||||
explicit boostdoc ;
|
||||
alias boostrelease ;
|
||||
explicit boostrelease ;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
(C) Copyright 2012-2015 Vicente J. Botet Escriba.
|
||||
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).
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
(C) Copyright 2013 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2013-2015 Vicente J. Botet Escriba.
|
||||
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).
|
||||
|
||||
200
doc/changes.qbk
200
doc/changes.qbk
@@ -1,6 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-14 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-16 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
@@ -8,6 +8,197 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[heading Version 4.7.2 - boost 1.63]
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* fix boost::synchronized_value<>::load()
|
||||
* fix relational operators of boost::synchronized_value<>
|
||||
* fix compile failed with boost::user_scheduler
|
||||
* Fix minor possibility of loosing the notify
|
||||
|
||||
[heading Version 4.7.1 - boost 1.62]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
|
||||
Please define BOOST_THREAD_PATCH to apply the patch that could unfortunately results is a regression as described in [@http://svn.boost.org/trac/boost/ticket/12049 #12049].
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last regression test snapshot.
|
||||
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11097 #11097] test_scheduled_tp - ThreadSanitizer: heap-use-after-free
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11951 #11951] Memory leak in boost::when_all
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12102 #12102] condition_variable_fwd.hpp fails to compile when BOOST_THREAD_PROVIDES_INTERRUPTIONS is disabled
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12120 #12120] Performance improvement in thread/barrier.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12146 #12146] make_exceptional_future is not mentioned in the docs
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12202 #12202] shared_lock should be in shared_mutex header
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12220 #12220] Memory leak in future::then()
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12293 #12293] boost::future::then lambda called before future is ready.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12350 #12350] shared_mutex (pthreads) unlocked too early in unlock_shared()
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12371 #12371] boost thread/future.hpp fails to build
|
||||
|
||||
|
||||
and several PR
|
||||
|
||||
* #88 fix typos in boost::upgrade_lock
|
||||
* #89 fix a bug in upgrade_to_unique_lock<>::operator=()
|
||||
* #90 fix a bug in try_lock_wrapper<>::operator=()
|
||||
* #91 Add shared_lock_guard to the included lock types
|
||||
* #92 Fixed compilation with MSVC-8.
|
||||
* #93 Fix variable shadowing warnings (Clang)
|
||||
* #94 fix bugs in boost::barrier
|
||||
* #95 fix a mistake in boost::completion_latch
|
||||
* #96 rename async_func.hpp to invoker.hpp.
|
||||
* #97 fix a mistake in sync_timed_queue<>::pull_until()
|
||||
|
||||
[heading Version 4.7.0 - boost 1.61]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
|
||||
Please define BOOST_THREAD_PATCH to apply the patch that could unfortunately results is a regression as described in [@http://svn.boost.org/trac/boost/ticket/12049 #12049].
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last regression test snapshot.
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11772 #11772] Add a launch::sync policy
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11494 #11494] boost::this_thread::yield() is marked as deprecated in the synopsis
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11562 #11562] (condition_variable_any::wait_until + recursive_mutex + steady_clock) timer expires after computer time is set forward on Ubuntu 64-bit
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12013 #12013] F_pass and FArgs_pass tests segfault
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12036 #12036] boost::physical_concurrency always returns 0 if BOOST_USE_WINAPI_VERSION is not defined
|
||||
|
||||
[heading Version 4.6.0 - boost 1.60]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10942 #10942] Boost.Thread fails to build on Cygwin.
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last regression test snapshot.
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11231 #11231] Allow to set continuation future's destructor behavior to non-blocking
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11424 #11424] Provide shared_timed_mutex as an alternative name for shared_mutex and deprecate the use of shared_mutex as a timed mutex
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11734 #11734] future::then(Cont) should be able to execute the continuation on undetermined thread
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11736 #11736] Allow to use launch::executor on future::then(launch::executor, cont)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11737 #11737] Add a launch::inherit policy that can be used on ::then() to use the policy of the parent future
|
||||
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6377 #6377] Condition variable blocks when changing time
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7665 #7665] this_thread::sleep_for no longer uses steady_clock in thread
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7720 #7720] exception lock_error while intensive locking/unlocking of mutex
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10788 #10788] GetLogicalProcessor isn't available for Windows platform less or equals to 0x0502
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11090 #11090] ex_future_unwrap- ThreadSanitizer: lock-order-inversion (potential deadlock)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11158 #11158] Pthread thread deadlock when faketime used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11174 #11174] boost::condition_variable::timed_wait with predicate unexpectedly wakes up while should wait infinite
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11185 #11185] Incorrect URL redirection
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11192 #11192] boost::future<>::then() with an executor doesn't compile when the callback returns a future
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11250 #11250] future made from make_exceptional fails on assertion in destructor
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11256 #11256] future<>::is_ready() == false in continuation function
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11261 #11261] bad use of scoped threads in basic_thread_pool
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11262 #11262] bad use of direct pointer in shared_state_nullary_task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11263 #11263] lock already locked lock
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11266 #11266] boost::packaged_task has invalid variadic signature
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11302 #11302] boost thread doesn't build with BOOST_THREAD_PATCH.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11322 #11322] sleep_for() nanoseconds overload will always return too early on windows
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11329 #11329] using declarative for GetProcessHeap, .... fails
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11368 #11368] boost thread's usage of CreateWaitableTimer wakes PC from sleep (doh)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11377 #11377] Boost condition variable always waits for system clock deadline
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11435 #11435] gcc compiler warning in future.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11555 #11555] devector.hpp assumes allocator_traits_type is always present
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11562 #11562] (condition_variable_any::wait_until + recursive_mutex + steady_clock) timer expires after computer time is set forward on Ubuntu 64-bit
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11672 #11672] Thread: Should use unique_ptr, not auto_ptr
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11688 #11688] thread::try_join_until: Avoid busy wait if system clock changes
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11672 #11716] ::then(f) should inherit the parent Executor
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11795 #11795] Incorrect version specification for documentation of thread destructor
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11796 #11796] Thread move assignment operator, does not detach previous thread data
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11817 #11817] 'sync_queue_is_closed' was not declared in boost/thread/executors/thread_executor.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11818 #11818] future.then will be blocked if promise is set after the invocation of then
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12049 #12049] Assertion failure from detached threads during shutdown
|
||||
|
||||
[heading Version 4.5.0 - boost 1.58]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10942 #10942] Boost.Thread fails to build on Cygwin.
|
||||
|
||||
[/
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10685 #10685] mfc_thread_init.hpp does not compile.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10967 #10967] Timed wait points inconsistently convert relative to absolute waits.
|
||||
]
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last regression test snapshot.
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries ( [@http://svn.boost.org/trac/boost/ticket/3926 #3926], ),
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9600 #9600] Async: Add task_region
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10611 #10611] Add emplace promise::set_value and emplace make_ready_future
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10826 #10826] Add scheduled executor operations
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11048 #11048] Add a serial_executor based on continuations
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6787 #6787] boost::thread::sleep() hangs if system time is rolled back
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10734 #10734] Submit method work differently on different executors, some throw exception and some silently ignore error (thread_executor and inline_executor)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10736 #10736] Task exceptions silently ignored. I think std::terminate solution from N3785 and std::thread is better choice and more consistent.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10737 #10737] In serial_executor we have infinite wait if task throw exception.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10822 #10822] Boost.Thread fails to compile on Android
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10824 #10824] Boost.Thread 1.57 breaks Windows XP compatibility for SP2 and below.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10963 #10963] future<future<T>>::then Has No Implementation
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10964 #10964] future<future<T>>::unwrap().then() Deadlocks
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10968 #10968] The futures returned by async() and future::then() are not blocking.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10971 #10971] shared_future::get()/get_or() must be const
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10972 #10972] shared_future::then() can be called multiple times.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10979 #10979] Support T& type deduction when the make_ready_future parameter is reference_wrapper<T>
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10996 #10996] Thread physical_concurrency() is failing on Windows
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11035 #11035] BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE not defined for Android
|
||||
* [@http://svn.boost.org/trac/boost/ticket/11053 #11053] The attached code results in a R6025 - pure virtual function call in run_thread_exit_callbacks
|
||||
|
||||
|
||||
[heading Version 4.4.0 - boost 1.57]
|
||||
|
||||
[*Know Bugs:]
|
||||
@@ -24,6 +215,7 @@
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10537 #10537] Application crash on throw exception
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler
|
||||
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
@@ -557,9 +749,6 @@ been moved to __thread_id__.
|
||||
|
||||
The following features will be included in next releases.
|
||||
|
||||
# Complete the C++11 missing features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
|
||||
|
||||
# Add some minor features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
|
||||
@@ -567,9 +756,6 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
|
||||
|
||||
# Add extensions related to fork-join as:
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9600 #9600] Async: Add task_region/task_run.
|
||||
|
||||
# And some additional extensions related to futures as:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic shared_future::then.
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
[/
|
||||
(C) Copyright 2011-2013 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-2015 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:compliance Conformance and Extension]
|
||||
[////////////////////////////////////////////]
|
||||
|
||||
[section:cpp11 C++11 standard Thread library]
|
||||
[///////////////////////////////////////////]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 - Standard for Programming Language C++]]]
|
||||
|
||||
@@ -88,6 +90,7 @@
|
||||
]
|
||||
[endsect]
|
||||
[section:cxx14 C++14 standard Thread library - accepted changes]
|
||||
[//////////////////////////////////////////////////////////////]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.html Working Draft, Standard for Programming Language C++]]
|
||||
|
||||
@@ -103,6 +106,7 @@
|
||||
|
||||
|
||||
[section:cxx1y C++14 TS Extensions for Concurrency V1 ]
|
||||
[/////////////////////////////////////////////////////]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4107.html N4107-Extensions for Concurrency]]
|
||||
|
||||
@@ -126,8 +130,10 @@
|
||||
[endsect]
|
||||
|
||||
[section:cxx1y C++1z TS Concurrency - On going proposals]
|
||||
[///////////////////////////////////////////////////////]
|
||||
|
||||
[section:latch C++ Latches and Barriers]
|
||||
[//////////////////////////////////////]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3600 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3817.html N3817 C++ Latches and Barriers]]
|
||||
@@ -140,6 +146,7 @@
|
||||
|
||||
[endsect]
|
||||
[section:queue C++ Concurrent Queues]
|
||||
[///////////////////////////////////]
|
||||
|
||||
[note [@ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html N3533 C++ Concurrent Queues]]
|
||||
|
||||
@@ -183,24 +190,25 @@
|
||||
[[X.3.4] [Managed Indirection] [No] [ - ]]
|
||||
]
|
||||
[endsect]
|
||||
[section:executors Asynchronous Executors]
|
||||
[section:executors Executors and Schedulers]
|
||||
[//////////////////////////////////////////]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3785.pdf N3785 Executors and Schedulers]]
|
||||
|
||||
[table Asynchronous Executors
|
||||
[table Executors and Schedulers
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[V.1.1] [Class executor] [Yes] [ - ]]
|
||||
[[V.1.1] [add] [Yes] [ renamed with a function template submit ]]
|
||||
[[V.1.1] [num_of_pendin_closures] [No] [ ]]
|
||||
[[V.1.1] [Class `executor`] [Yes] [ - ]]
|
||||
[[V.1.1] [`add`] [Yes] [ renamed with a function template `submit` ]]
|
||||
[[V.1.1] [`num_of_pendin_closures`] [No] [ ]]
|
||||
[[V.1.2] [Class sceduled_executor] [No] [ - ]]
|
||||
[[V.1.2] [add_at] [No] [ renamed with a function template submit_at ]]
|
||||
[[V.1.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
||||
[[V.1.2] [`add_at`] [No] [ renamed with a function template `scheduler::submit_at` ]]
|
||||
[[V.1.2] [`add_after`] [No] [ renamed with a function template `scheduler::submit_after` ]]
|
||||
[[V.2] [Concrete executor classes] [No] [ - ]]
|
||||
[[V.2.1] [thread_pool] [Yes] [ static version Basic_thread_pool, dynamic one execduler_adaptor<basic_thread_pool> ]]
|
||||
[[V.2.2] [serial_executor] [yes] [ - ]]
|
||||
[[V.2.3] [loop_executor] [Yes] [ static version loop_scheduler, dynamic one execduler_adaptor<loop_scheduler> ]]
|
||||
[[V.2.4] [inline_executor] [Yes] [ static version inline_executor, dynamic one execduler_adaptor<inline_executor> ]]
|
||||
[[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor<thread_executor> ]]
|
||||
[[V.2.1] [`thread_pool`] [Yes] [ static version `basic_thread_pool`, dynamic one `execduler_adaptor<basic_thread_pool>` ]]
|
||||
[[V.2.2] [`serial_executor`] [yes] [ - ]]
|
||||
[[V.2.3] [`loop_executor`] [Yes] [ static version loop_scheduler, dynamic one `execduler_adaptor<loop_scheduler>` ]]
|
||||
[[V.2.4] [`inline_executor`] [Yes] [ static version `inline_executor`, dynamic one `execduler_adaptor<inline_executor>` ]]
|
||||
[[V.2.5] [`thread_executor`] [Yes] [ static version `thread_executor`, dynamic one `execduler_adaptor<thread_executor>` ]]
|
||||
]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3784.pdf N3784-Improvements to `std::future<T> and Related APIs]]
|
||||
@@ -212,8 +220,31 @@
|
||||
[[30.6.8] [`async`] [Yes] [ - ]]
|
||||
]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4143.pdf N4143-Executors and schedulers, revision 4]]
|
||||
|
||||
[table Executors and Schedulers - revision 4
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[VI.A] [Executor Concept] [Yes] [ `wrapper_type` renamed by `work` and `spawn by `submit` ]]
|
||||
[[VI.A.1] [`thread_per_task_executor] [Yes] [ renamed `thread_executor`]]
|
||||
[[VI.A.2] [`thread_pool_executor`] [Yes] [ renamed `basic_thread_pool`]]
|
||||
[[VI.A.3] [`system_executor`] [No] [ - ]]
|
||||
[[VI.A.4] [`loop_executor`] [Yes] [ - ]]
|
||||
[[VI.A.5] [`serial_executor`] [yes] [ - ]]
|
||||
[[VI.B] [`executor_ref`] [yes] [ - ]]
|
||||
[[VI.C] [`executor`] [yes] [ renamed `gen_executor_ref` ]]
|
||||
[[VI.D] [Free Functions and Helper Objects] [partial] [ - ]]
|
||||
[[VI.D] [`make_package`] [No] [ - ]]
|
||||
[[VI.D] [`spawn_future`] [No] [ `async(Ex&, ...)` is similar but returns a blocking future. ]]
|
||||
[[VI.D] [`spawn`] [No] [ - ]]
|
||||
[[VI.D] [`task_wrapper`] [No] [ renamed `resubmitter` ]]
|
||||
[[VI.D] [`set_executor`] [No] [ renamed `resubmit` ]]
|
||||
[[VI.D] [`function_wrapper`] [Partial] [ renamed `work` ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[//////////////////////////////////////////////////////////////
|
||||
[section:stream_mutex C++ Stream Mutexes - C++ Stream Guards]
|
||||
[/////////////////////////////////////////////////////////////]
|
||||
|
||||
While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard.
|
||||
|
||||
@@ -241,7 +272,7 @@ While Boost.Thread implementation of stream mutexes differ in the approach, it i
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
///////////////////////////////]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
(C) Copyright 20012 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2012-2015 Vicente J. Botet Escriba.
|
||||
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).
|
||||
@@ -23,6 +23,7 @@
|
||||
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] ]
|
||||
|
||||
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_EXECUTORS] [-] [NO] [NO] [NO] ]
|
||||
[[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] ]
|
||||
@@ -80,7 +81,7 @@ When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `
|
||||
|
||||
[section:move Boost.Atomic]
|
||||
|
||||
Boost.Thread uses by default an Boost.Atomic in POSIX platforms to implement call_once..
|
||||
Boost.Thread uses by default Boost.Atomic in POSIX platforms to implement call_once..
|
||||
|
||||
Define `BOOST_THREAD_USES_ATOMIC ` if you want to use Boost.Atomic.
|
||||
Define `BOOST_THREAD_DONT_USE_ATOMIC ` if you don't want to use Boost.Atomic or if it is not supported in your platform.
|
||||
|
||||
@@ -260,14 +260,14 @@ Locks provide an explicit bool conversion operator when the compiler provides th
|
||||
|
||||
The library provides un implicit conversion to an undefined type that can be used as a conditional expression.
|
||||
|
||||
#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS)
|
||||
#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
|
||||
operator ``['unspecified-bool-type]``() const;
|
||||
bool operator!() const;
|
||||
#else
|
||||
explicit operator bool() const;
|
||||
#endif
|
||||
|
||||
The user should use the lock.owns_lock() when a explicit conversion is required.
|
||||
The user should use the lock.owns_lock() when an explicit conversion is required.
|
||||
|
||||
[section:bool_conversion `operator `['unspecified-bool-type]`() const`]
|
||||
|
||||
@@ -324,7 +324,7 @@ the library declare these types as
|
||||
}
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
|
||||
|
||||
These macros allows to use 'future_errc' in almost all the cases as an scoped enum.
|
||||
These macros allows to use 'future_errc' in almost all the cases as a scoped enum.
|
||||
|
||||
There are however some limitations:
|
||||
|
||||
@@ -346,14 +346,14 @@ use
|
||||
|
||||
And instead of
|
||||
|
||||
#ifdef BOOST_NO_SCOPED_ENUMS
|
||||
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type { };
|
||||
#endif
|
||||
|
||||
use
|
||||
|
||||
#ifdef BOOST_NO_SCOPED_ENUMS
|
||||
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
|
||||
#endif
|
||||
|
||||
@@ -98,7 +98,7 @@ or inheriting from a class which add these lockable functions.
|
||||
The `basic_lockable_adapter` class helps to define the `BankAccount` class as
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<thread_mutex>
|
||||
: public basic_lockable_adapter<boost::mutex>
|
||||
{
|
||||
int balance_;
|
||||
public:
|
||||
@@ -138,7 +138,7 @@ Notice that now acct is being locked by Withdraw after it has already been locke
|
||||
As `boost::mutex` is not recursive, we need to use its recursive version `boost::recursive_mutex`.
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<recursive_mutex>
|
||||
: public basic_lockable_adapter<boost::recursive_mutex>
|
||||
{
|
||||
|
||||
// ...
|
||||
@@ -147,7 +147,7 @@ As `boost::mutex` is not recursive, we need to use its recursive version `boost:
|
||||
The caller-ensured locking approach is more flexible and the most efficient, but very dangerous. In an implementation using caller-ensured locking, BankAccount still holds a mutex, but its member functions don't manipulate it at all. Deposit and Withdraw are not thread-safe anymore. Instead, the client code is responsible for locking BankAccount properly.
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<boost:mutex> {
|
||||
: public basic_lockable_adapter<boost::mutex> {
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount) {
|
||||
@@ -271,7 +271,7 @@ Now that we have such a strict `strict_lock`, how do we harness its power in def
|
||||
A little code is worth 1,000 words, a (hacked into) saying goes, so here's the new BankAccount class:
|
||||
|
||||
class BankAccount
|
||||
: public basic_lockable_adapter<boost:recursive_mutex>
|
||||
: public basic_lockable_adapter<boost::mutex>
|
||||
{
|
||||
int balance_;
|
||||
public:
|
||||
@@ -280,7 +280,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n
|
||||
balance_ += amount;
|
||||
}
|
||||
void Deposit(int amount) {
|
||||
strict_lock<boost:mutex> guard(*this); // Internally locked
|
||||
strict_lock<BankAccount> guard(*this); // Internally locked
|
||||
Deposit(amount, guard);
|
||||
}
|
||||
void Withdraw(int amount, strict_lock<BankAccount>&) {
|
||||
@@ -288,7 +288,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n
|
||||
balance_ -= amount;
|
||||
}
|
||||
void Withdraw(int amount) {
|
||||
strict_lock<boost:mutex> guard(*this); // Internally locked
|
||||
strict_lock<BankAccount> guard(*this); // Internally locked
|
||||
Withdraw(amount, guard);
|
||||
}
|
||||
};
|
||||
@@ -327,7 +327,7 @@ The scheme is useful because the likelihood of a programmer forgetting about any
|
||||
Using `strict_lock` permits compile-time checking of the most common source of errors, and runtime checking of the less frequent problem.
|
||||
|
||||
Let's see how to enforce that the appropriate BankAccount object is locked. First, we need to add a member function to the `strict_lock` class template.
|
||||
The `bool strict_lock<T>::owns_lock(Loclable*)` function returns a reference to the locked object.
|
||||
The `bool strict_lock<T>::owns_lock(Lockable*)` function returns a reference to the locked object.
|
||||
|
||||
template <class Lockable> class strict_lock {
|
||||
... as before ...
|
||||
@@ -338,7 +338,7 @@ The `bool strict_lock<T>::owns_lock(Loclable*)` function returns a reference to
|
||||
Second, BankAccount needs to use this function compare the locked object against this:
|
||||
|
||||
class BankAccount {
|
||||
: public basic_lockable_adapter<boost::recursive_mutex>
|
||||
: public basic_lockable_adapter<boost::mutex>
|
||||
int balance_;
|
||||
public:
|
||||
void Deposit(int amount, strict_lock<BankAccount>& guard) {
|
||||
@@ -403,7 +403,7 @@ The solution is to use a little bridge template `externally_locked` that control
|
||||
T& get(strict_lock<Lockable>& lock) {
|
||||
|
||||
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if (!lock.owns_lock(&lockable_)) throw lock_error(); run time check throw if not locks the same
|
||||
if (!lock.owns_lock(&lockable_)) throw lock_error(); //run time check throw if not locks the same
|
||||
#endif
|
||||
return obj_;
|
||||
}
|
||||
@@ -421,10 +421,10 @@ The solution is to use a little bridge template `externally_locked` that control
|
||||
Instead of making `checkingAcct_` and `savingsAcct_` of type `BankAccount`, `AccountManager` holds objects of type `externally_locked<BankAccount, AccountManager>`:
|
||||
|
||||
class AccountManager
|
||||
: public basic_lockable_adapter<thread_mutex>
|
||||
: public basic_lockable_adapter<boost::mutex>
|
||||
{
|
||||
public:
|
||||
typedef basic_lockable_adapter<thread_mutex> lockable_base_type;
|
||||
typedef basic_lockable_adapter<boost::mutex> lockable_base_type;
|
||||
AccountManager()
|
||||
: checkingAcct_(*this)
|
||||
, savingsAcct_(*this)
|
||||
@@ -498,7 +498,7 @@ Now we need to state that both classes are `strict_lock`s.
|
||||
|
||||
Well let me show what this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
|
||||
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction it will restore the ownership. Note the use of `lock_traits` and that the `Locker` needs to have a reference to the mutex otherwise and exception is thrown.
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction it will restore the ownership. Note the use of `lock_traits` and that the `Locker` needs to have a reference to the mutex otherwise an exception is thrown.
|
||||
|
||||
template <typename Locker >
|
||||
class nested_strict_lock
|
||||
@@ -510,7 +510,7 @@ First `nested_strict_lock` class will store on a temporary lock the `Locker`, an
|
||||
|
||||
nested_strict_lock(Locker& lock)
|
||||
: lock_(lock) // Store reference to locker
|
||||
, tmp_lock_(lock.move()) // Move ownership to temporaty locker
|
||||
, tmp_lock_(lock.move()) // Move ownership to temporary locker
|
||||
{
|
||||
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
if (tmp_lock_.mutex()==0) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2008-11 Anthony Williams.
|
||||
(C) Copyright 2012-2015 Vicente J. Botet Escriba.
|
||||
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).
|
||||
@@ -28,9 +29,11 @@
|
||||
|
||||
enum class launch
|
||||
{
|
||||
none = unspecified,
|
||||
async = unspecified,
|
||||
deferred = unspecified,
|
||||
executor = unspecified,
|
||||
inherit = unspecified,
|
||||
any = async | deferred
|
||||
};
|
||||
|
||||
@@ -124,10 +127,10 @@
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<void> make_ready_future(); // EXTENSION
|
||||
|
||||
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional_future(exception_ptr ex); // EXTENSION
|
||||
template <typename E>
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(); // EXTENSION
|
||||
exceptional_ptr make_exceptional_future(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional_future(); // EXTENSION
|
||||
|
||||
|
||||
template <typename T>
|
||||
@@ -164,14 +167,27 @@
|
||||
|
||||
enum class launch
|
||||
{
|
||||
none = unspecified,
|
||||
async = unspecified,
|
||||
deferred = unspecified,
|
||||
executor = unspecified,
|
||||
inherit = unspecified,
|
||||
any = async | deferred
|
||||
};
|
||||
|
||||
The enum type launch is a bitmask type with launch::async and launch::deferred denoting individual bits.
|
||||
|
||||
A future created with `promise<>` or with a `packaged_task<>` or with `make_ready_future`/`make_exceptional_future` (has no associated launch policy), has an implicit a launch policy of `launch::none`.
|
||||
|
||||
A future created by `async(launch::async, ...)` or `::then(launch::async, ...)` has associated a launch policy `launch::async`.
|
||||
A future created by `async(launch::deferred, ...)` or `::then(launch::deferred, ...)` has associated a launch policy `launch::deferred`.
|
||||
A future created by `async(Executor, ...)` or `::then(Executor, ...)` or `::then(launch::executor, ...)` has associated a launch policy `launch::executor`.
|
||||
A future created by `async(...)` or `::then(...)` has associated a launch policy `launch::none`.
|
||||
|
||||
A future created by `::then(launch::inherit, ...)` has associated a launch policy parent future.
|
||||
|
||||
The `executor` and the `inherit` launch policies have a sense only can be user only on `then()`.
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////////////////////////////////////////////////]
|
||||
[section:is_error_code_enum Specialization `is_error_code_enum<future_errc>`]
|
||||
@@ -333,7 +349,7 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
|
||||
// move support
|
||||
__unique_future__(__unique_future__ && other) noexcept;
|
||||
__unique_future__(__unique_future__<__unique_future__<R>>&& rhs); // EXTENSION
|
||||
explicit __unique_future__(__unique_future__<__unique_future__<R>>&& rhs); // EXTENSION
|
||||
__unique_future__& operator=(__unique_future__ && other) noexcept;
|
||||
|
||||
// factories
|
||||
@@ -344,7 +360,7 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION
|
||||
then(Ex& executor, F&& func); // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
@@ -437,7 +453,7 @@ associated with `*this`. `other` is not associated with any shared state.]]
|
||||
[///////////////////////////////////////////////////////////////////]
|
||||
[section:unwrap_move_constructor Unwrap Move Constructor - EXTENSION]
|
||||
|
||||
__unique_future__(__unique_future__<__unique_future__<R>>&& other); // EXTENSION
|
||||
explicit __unique_future__(__unique_future__<__unique_future__<R>>&& other); // EXTENSION
|
||||
|
||||
[warning This constructor is experimental and subject to change in future versions.
|
||||
There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
@@ -832,7 +848,7 @@ stored exception, `false` otherwise.]]
|
||||
[[Effects:] [If `*this` is associated with a shared state, waits until the result is ready. If the result is not ready on
|
||||
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
|
||||
|
||||
[[Returns:] [a exception_ptr, storring or not an exception.]]
|
||||
[[Returns:] [an exception_ptr, storing or not an exception.]]
|
||||
|
||||
[[Remarks:] [The result of this function is not stable and the future could lost its exception even if the function returned a valid `exception_ptr` or vice-versa.]]
|
||||
|
||||
@@ -884,7 +900,7 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(S& scheduler, F&& func); // EXTENSION
|
||||
then(Ex& executor, F&& func); // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(launch policy, F&& func); // EXTENSION
|
||||
@@ -897,29 +913,41 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
[variablelist
|
||||
|
||||
[[Notes:] [The three functions differ only by input parameters. The first only takes a callable object which accepts a
|
||||
future object as a parameter. The second function takes a scheduler as the first parameter and a callable object as
|
||||
future object as a parameter. The second function takes an executor as the first parameter and a callable object as
|
||||
the second parameter. The third function takes a launch policy as the first parameter and a callable object as the
|
||||
second parameter.]]
|
||||
|
||||
[[Requires:] [`INVOKE(DECAY_COPY (std::forward<F>(func)), std::move(*this))` shall be a valid expression.]]
|
||||
|
||||
[[Effects:] [
|
||||
|
||||
All the functions create a shared state that is associated with the returned future object. The further behavior of the functions is as follows.
|
||||
All the functions create a shared state that is associated with the returned future object. Additionally,
|
||||
|
||||
- The continuation is called when the object's shared state is ready (has a value or exception stored).
|
||||
- When the object's shared state is ready, the continuation
|
||||
`INVOKE(DECAY_COPY(std::forward<F>(func)), std::move(*this))` is called depending on the overload (see below) with the call to DECAY_COPY() being evaluated in the thread that called then.
|
||||
|
||||
- The continuation launches according to the specified policy or scheduler.
|
||||
- Any value returned from the continuation is stored as the result in the shared state of the resulting `future`.
|
||||
Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting `future`.
|
||||
|
||||
- When the scheduler or launch policy is not provided the continuation inherits the
|
||||
parent's launch policy or scheduler.
|
||||
|
||||
- Any value returned from the continuation is stored as the result in the shared state of the resulting `future`. Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting `future`.
|
||||
The continuation launches according to the specified policy or executor or noting.
|
||||
|
||||
- If the parent was created with `promise<>` or with a `packaged_task<>` (has no associated launch policy), the
|
||||
continuation behaves the same as the third overload with a policy argument of `launch::async | launch::deferred` and
|
||||
the same argument for `func`.
|
||||
- When the launch policy is `launch::none` the continuation is called on an unspecified thread of execution.
|
||||
|
||||
- If the parent has a policy of `launch::deferred` and the continuation does not have a specified launch policy or
|
||||
scheduler, then the parent is filled by immediately calling `.wait()`, and the policy of the antecedent is
|
||||
- When the launch policy is `launch::async` the continuation is called on a new thread of execution.
|
||||
|
||||
- When the launch policy is `launch::deferred` the continuation is called on demand.
|
||||
|
||||
- When the launch policy is `launch::executor` the continuation is called on one of the thread of execution of the executor.
|
||||
|
||||
- When the launch policy is `launch::inherit` the continuation inherits the parent's launch policy or executor.
|
||||
|
||||
- When the executor or launch policy is not provided (first overload) is if as if launch::none was specified.
|
||||
|
||||
- When the executor is provided (second overload) the continuation is called on one of the thread of execution of the executor.
|
||||
|
||||
- If the parent has a policy of `launch::deferred` and the continuation does not have a specified launch policy
|
||||
executor, then the parent is filled by immediately calling `.wait()`, and the policy of the antecedent is
|
||||
`launch::deferred`.
|
||||
|
||||
]]
|
||||
@@ -1020,7 +1048,7 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
void swap(shared_future& other);
|
||||
|
||||
// retrieving the value
|
||||
see below get();
|
||||
see below get() const;
|
||||
|
||||
exception_ptr get_exception_ptr(); // EXTENSION
|
||||
|
||||
@@ -1066,9 +1094,9 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
[///////////////////////////////////]
|
||||
[section:get Member function `get()`]
|
||||
|
||||
const R& get();
|
||||
R& get();
|
||||
void get();
|
||||
const R& get() const;
|
||||
R& get() const;
|
||||
void get() const;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -1329,7 +1357,7 @@ stored exception, `false` otherwise.]]
|
||||
[[Effects:] [If `*this` is associated with a shared state, waits until the result is ready. If the result is not ready on
|
||||
entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]]
|
||||
|
||||
[[Returns:] [a exception_ptr, storring or not an exception.]]
|
||||
[[Returns:] [an exception_ptr, storing or not an exception.]]
|
||||
|
||||
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
|
||||
|
||||
@@ -1361,7 +1389,7 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
then(F&& func) const; // EXTENSION
|
||||
template<typename S, typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(S& scheduler, F&& func) const; // EXTENSION
|
||||
then(Ex& executor, F&& func) const; // EXTENSION
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(launch policy, F&& func) const; // EXTENSION
|
||||
@@ -1375,26 +1403,42 @@ There are not too much tests yet, so it is possible that you can find out some t
|
||||
[variablelist
|
||||
|
||||
[[Notes:] [The three functions differ only by input parameters. The first only takes a callable object which accepts a
|
||||
shared_future object as a parameter. The second function takes a scheduler as the first parameter and a callable object as
|
||||
shared_future object as a parameter. The second function takes an executor as the first parameter and a callable object as
|
||||
the second parameter. The third function takes a launch policy as the first parameter and a callable object as the
|
||||
second parameter.]]
|
||||
|
||||
[[Requires:] [`INVOKE(DECAY_COPY (std::forward<F>(func)), *this)` shall be a valid expression.]]
|
||||
|
||||
[[Effects:] [
|
||||
|
||||
- The continuation is called when the object's shared state is ready (has a value or exception stored).
|
||||
All the functions create a shared state that is associated with the returned future object. Additionally,
|
||||
|
||||
- The continuation launches according to the specified policy or scheduler.
|
||||
- When the object's shared state is ready, the continuation
|
||||
`INVOKE(DECAY_COPY(std::forward<F>(func)), *this)` is called depending on the overload (see below) with the call to DECAY_COPY() being evaluated in the thread that called then.
|
||||
|
||||
- When the scheduler or launch policy is not provided the continuation inherits the
|
||||
parent's launch policy or scheduler.
|
||||
- Any value returned from the continuation is stored as the result in the shared state of the resulting `future`.
|
||||
Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting `future`.
|
||||
|
||||
- If the parent was created with `promise` or with a `packaged_task` (has no associated launch policy), the
|
||||
continuation behaves the same as the third overload with a policy argument of `launch::async | launch::deferred` and
|
||||
the same argument for func.
|
||||
|
||||
- If the parent has a policy of `launch::deferred` and the continuation does not have a specified launch policy or
|
||||
scheduler, then the parent is filled by immediately calling `.wait()`, and the policy of the antecedent is
|
||||
`launch::deferred`
|
||||
The continuation launches according to the specified policy or executor or noting.
|
||||
|
||||
- When the launch policy is `launch::none` the continuation is called on an unspecified thread of execution.
|
||||
|
||||
- When the launch policy is `launch::async` the continuation is called on a new thread of execution.
|
||||
|
||||
- When the launch policy is `launch::deferred` the continuation is called on demand.
|
||||
|
||||
- When the launch policy is `launch::executor` the continuation is called on one of the thread of execution of the executor.
|
||||
|
||||
- When the launch policy is `launch::inherit` the continuation inherits the parent's launch policy or executor.
|
||||
|
||||
- When the executor or launch policy is not provided (first overload) is if as if launch::none was specified.
|
||||
|
||||
- When the executor is provided (second overload) the continuation is called on one of the thread of execution of the executor.
|
||||
|
||||
- If the parent has a policy of `launch::deferred` and the continuation does not have a specified launch policy
|
||||
executor, then the parent is filled by immediately calling `.wait()`, and the policy of the antecedent is
|
||||
`launch::deferred`.
|
||||
|
||||
]]
|
||||
|
||||
@@ -2362,7 +2406,7 @@ All `R` types must be the same. If any of the `future<R>` or `shared_future<R>`
|
||||
[section:make_ready_future Non-member function `make_ready_future()` EXTENSION]
|
||||
|
||||
template <typename T>
|
||||
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
|
||||
future<V> make_ready_future(T&& value); // EXTENSION
|
||||
future<void> make_ready_future(); // EXTENSION
|
||||
template <typename T>
|
||||
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
|
||||
@@ -2371,11 +2415,15 @@ All `R` types must be the same. If any of the `future<R>` or `shared_future<R>`
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Remark:][
|
||||
where `V` is determined as follows: Let `U` be `decay_t<T>`. Then `V` is `X&`
|
||||
if `U` equals `reference_wrapper<X>`, otherwise `V` is `U`.
|
||||
]]
|
||||
[[Effects:] [
|
||||
- value prototype: The value that is passed into the function is moved to the shared state of the returned function if it is an rvalue.
|
||||
Otherwise the value is copied to the shared state of the returned function.
|
||||
- value prototype: The value that is passed into the function is moved to the shared state of the returned future if it is an rvalue.
|
||||
Otherwise the value is copied to the shared state of the returned future.
|
||||
|
||||
- exception: The exception that is passed into the function is copied to the shared state of the returned function.
|
||||
- exception: The exception that is passed into the function is copied to the shared state of the returned future.
|
||||
|
||||
.]]
|
||||
|
||||
@@ -2403,12 +2451,12 @@ Otherwise the value is copied to the shared state of the returned function.
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////////////////////////////////////////////]
|
||||
[section:make_exceptional Non-member function `make_exceptional()` EXTENSION]
|
||||
[section:make_exceptional_future Non-member function `make_exceptional_future()` EXTENSION]
|
||||
|
||||
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional_future(exception_ptr ex); // EXTENSION
|
||||
template <typename E>
|
||||
exceptional_ptr make_exceptional(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional(); // EXTENSION
|
||||
exceptional_ptr make_exceptional_future(E ex); // EXTENSION
|
||||
exceptional_ptr make_exceptional_future(); // EXTENSION
|
||||
|
||||
[variablelist
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2008-11 Anthony Williams.
|
||||
(C) Copyright 2012-2015 Vicente J. Botet Escriba.
|
||||
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).
|
||||
@@ -93,7 +94,7 @@ the result is ready, it is returned from __unique_future_get__ by rvalue-referen
|
||||
appropriate for the type.
|
||||
|
||||
On the other hand, many instances of __shared_future__ may reference the same result. Instances can be freely copied and assigned,
|
||||
and __shared_future_get__ returns a non `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
|
||||
and __shared_future_get__ returns a `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
|
||||
instance of __unique_future__ into an instance of __shared_future__, thus transferring ownership of the associated asynchronous
|
||||
result, but not vice-versa.
|
||||
|
||||
@@ -325,7 +326,7 @@ Using a `shared_future` solves the issue
|
||||
|
||||
[heading share()]
|
||||
|
||||
Namming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists.
|
||||
Naming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists.
|
||||
Here `share()` could be used to simplify the code
|
||||
|
||||
void better_second_use( type arg ) {
|
||||
@@ -343,7 +344,7 @@ Here `share()` could be used to simplify the code
|
||||
|
||||
[heading Writing on get()]
|
||||
|
||||
The user can either read or write the future avariable.
|
||||
The user can either read or write the future variable.
|
||||
|
||||
void write_to_get( type arg ) {
|
||||
|
||||
@@ -364,7 +365,7 @@ The user can either read or write the future avariable.
|
||||
This works because the `shared_future<>::get()` function returns a non-const reference to the appropriate storage.
|
||||
Of course the access to this storage must be ensured by the user. The library doesn't ensure the access to the internal storage is thread safe.
|
||||
|
||||
There has been some work by the C++ standard committe on an `atomic_future` that behaves as an `atomic` variable, that is is thread_safe,
|
||||
There has been some work by the C++ standard committee on an `atomic_future` that behaves as an `atomic` variable, that is thread_safe,
|
||||
and a `shared_future` that can be shared between several threads, but there were not enough consensus and time to get it ready for C++11.
|
||||
|
||||
[endsect]
|
||||
@@ -443,10 +444,10 @@ Input Parameters:
|
||||
success and one for error handling. However this option has not been retained for the moment.
|
||||
The lambda function takes a future as its input which carries the exception
|
||||
through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
|
||||
* Scheduler: Providing an overload to `.then`, to take a scheduler reference places great flexibility over the execution
|
||||
* Executor: Providing an overload to `.then`, to take an executor reference places great flexibility over the execution
|
||||
of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful
|
||||
asynchronous operations. The lifetime of the scheduler must outlive the continuation.
|
||||
* Launch policy: if the additional flexibility that the scheduler provides is not required.
|
||||
asynchronous operations. The lifetime of the executor must outlive the continuation.
|
||||
* Launch policy: if the additional flexibility that the executor provides is not required.
|
||||
|
||||
Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using
|
||||
`.then()`. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning
|
||||
|
||||
@@ -240,9 +240,9 @@ The following class describes a so-called monitor pattern.
|
||||
template <
|
||||
typename Lockable=mutex
|
||||
>
|
||||
class basic_monitor : protected basic_lockable_adapter<Lockable> { // behaves like an BasicLockable for the derived classes
|
||||
class basic_monitor : protected basic_lockable_adapter<Lockable> { // behaves like a BasicLockable for the derived classes
|
||||
protected:
|
||||
typedef unspecified synchronizer; // is an strict lock guard
|
||||
typedef unspecified synchronizer; // is a strict lock guard
|
||||
};
|
||||
|
||||
[/shared_monitor]
|
||||
|
||||
@@ -869,7 +869,7 @@ any other threads have shared ownership, blocks until exclusive ownership can be
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [The calling thread shall hold a upgrade lock on the mutex.]]
|
||||
[[Precondition:] [The calling thread shall hold an upgrade lock on the mutex.]]
|
||||
|
||||
[[Effects:] [The function attempts to atomically convert the ownership from upgrade to exclusive for the calling thread without blocking.
|
||||
For this conversion to be successful, this thread must be the only thread holding any ownership of the lock.
|
||||
@@ -893,7 +893,7 @@ If the conversion is not successful, the upgrade ownership of m is retained.]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [The calling thread shall hold a upgrade lock on the mutex.]]
|
||||
[[Precondition:] [The calling thread shall hold an upgrade lock on the mutex.]]
|
||||
|
||||
[[Effects:] [If the tick period of `rel_time` is not exactly convertible to the native tick period, the duration shall be rounded up to the nearest native tick period.
|
||||
The function attempts to atomically convert the ownership from upgrade to exclusive for the calling thread within the relative timeout specified by `rel_time`.
|
||||
@@ -919,7 +919,7 @@ If the conversion is not successful, the upgrade ownership of m is retained.]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [The calling thread shall hold a upgrade lock on the mutex.]]
|
||||
[[Precondition:] [The calling thread shall hold an upgrade lock on the mutex.]]
|
||||
|
||||
[[Effects:] [The function attempts to atomically convert the ownership from upgrade to exclusive for the calling thread within the absolute timeout specified by `abs_time`.
|
||||
If `abs_time` has already passed, the function attempts to obtain exclusive ownership without blocking (as if by calling `__try_unlock_upgrade_and_lock()`).
|
||||
@@ -2150,7 +2150,7 @@ object passed to the constructor.]]
|
||||
__nested_strict_lock is a model of __StrictLock.
|
||||
|
||||
A nested strict lock is a scoped lock guard ensuring a mutex is locked on its
|
||||
scope, by taking ownership of an nesting lock, locking the mutex on construction if not already locked
|
||||
scope, by taking ownership of a nesting lock, locking the mutex on construction if not already locked
|
||||
and restoring the ownership to the nesting lock on destruction.
|
||||
|
||||
|
||||
@@ -2664,7 +2664,7 @@ Only the specificities respect to __Lockable are described here.
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:get2 `get(strict_lock<nested_strict_lock<Lock>>&)`]
|
||||
[section:get2 `get(nested_strict_lock<Lock>&)`]
|
||||
|
||||
template <class Lock>
|
||||
T& get(nested_strict_lock<Lock>& lk);
|
||||
@@ -2684,7 +2684,7 @@ Only the specificities respect to __Lockable are described here.
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:get3 `get(strict_lock<nested_strict_lock<Lock>>&)`]
|
||||
[section:get3 `get(Lock&)`]
|
||||
|
||||
template <class Lock>
|
||||
T& get(Lock& lk);
|
||||
@@ -2826,7 +2826,7 @@ Only the specificities respect to __Lockable are described here.
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////]
|
||||
[section:get2 `get(strict_lock<nested_strict_lock<Lock>>&)`]
|
||||
[section:get2 `get(nested_strict_lock<Lock>&)`]
|
||||
|
||||
template <class Lock>
|
||||
T& get(nested_strict_lock<Lock>& lk);
|
||||
@@ -2846,7 +2846,7 @@ Only the specificities respect to __Lockable are described here.
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////]
|
||||
[section:get3 `get(strict_lock<nested_strict_lock<Lock>>&)`]
|
||||
[section:get3 `get(Lock&)`]
|
||||
|
||||
template <class Lock>
|
||||
T& get(Lock& lk);
|
||||
@@ -3034,8 +3034,8 @@ An instance of __reverse_lock doesn't ['own] the lock never.
|
||||
[[Effects:] [Locks the __lockable_concept_type__ objects supplied as
|
||||
arguments in an unspecified and indeterminate order in a way that
|
||||
avoids deadlock. It is safe to call this function concurrently from
|
||||
multiple threads with the same mutexes (or other lockable objects) in
|
||||
different orders without risk of deadlock. If any of the __lock_ref__
|
||||
multiple threads for any set of mutexes (or other lockable objects) in
|
||||
any order without risk of deadlock. If any of the __lock_ref__
|
||||
or __try_lock_ref__ operations on the supplied
|
||||
__lockable_concept_type__ objects throws an exception any locks
|
||||
acquired by the function will be released before the function exits.]]
|
||||
@@ -3062,8 +3062,8 @@ are locked by the calling thread.]]
|
||||
[[Effects:] [Locks all the __lockable_concept_type__ objects in the
|
||||
supplied range in an unspecified and indeterminate order in a way that
|
||||
avoids deadlock. It is safe to call this function concurrently from
|
||||
multiple threads with the same mutexes (or other lockable objects) in
|
||||
different orders without risk of deadlock. If any of the __lock_ref__
|
||||
multiple threads for any set of mutexes (or other lockable objects) in
|
||||
any order without risk of deadlock. If any of the __lock_ref__
|
||||
or __try_lock_ref__ operations on the __lockable_concept_type__
|
||||
objects in the supplied range throws an exception any locks acquired
|
||||
by the function will be released before the function exits.]]
|
||||
|
||||
482
doc/parallel.qbk
Normal file
482
doc/parallel.qbk
Normal file
@@ -0,0 +1,482 @@
|
||||
[/
|
||||
/ Copyright (c) 2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:parallel Parallel - Fork-Join -- EXPERIMENTAL]
|
||||
|
||||
[section:fork_join Fork-Join]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4088.pdf [* n4088 - Task Region R3]] C++1y proposal from P. Halpern, A. Robison, A. Laksberg, H. Sutter, et al. The text that follows has been adapted from this paper to show the differences.]
|
||||
|
||||
The major difference respect to the standard proposal is that we are able to use a common executor for several task regions.
|
||||
|
||||
[note
|
||||
Up to now, Boost.Thread doesn't implement the parallel algorithms as defined in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4105.pdf [* n4105 - Information technology – Programming languages, their environments and system software interfaces – Technical Specification for C++ Extensions for Parallelism]].
|
||||
]
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
|
||||
This module introduces a C++11/c++14 library function template `task_region` and a library class `task_region_handle`
|
||||
with member functions `run` and `wait` that together enable developers to write expressive and portable fork-join
|
||||
parallel code.
|
||||
|
||||
The working draft for the Parallelism TS [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4105.pdf [*N4105]] augments the STL algorithms with the inclusion of parallel execution policies. Programmers use these as a basis to write additional high-level algorithms that can be implemented in terms of the provided parallel algorithms. However, the scope of n4105 does not include lower-level mechanisms to express arbitrary fork-join parallelism
|
||||
|
||||
The `task_region`, `run` and the `wait` functions provided by this library are based on the `task_group` concept that is a part of the common subset of the PPL and the TBB libraries.
|
||||
|
||||
[endsect] [/ Introduction]
|
||||
|
||||
|
||||
[/////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Consider an example of a parallel traversal of a tree, where a user-provided function compute is applied to each node of the tree, returning the sum of the results:
|
||||
|
||||
template<typename Func>
|
||||
int traverse(node *n, Func&& compute)
|
||||
{
|
||||
int left = 0, right = 0;
|
||||
task_region([&](task_region_handle& tr) {
|
||||
if (n->left)
|
||||
tr.run([&] { left = traverse(n->left, compute); });
|
||||
if (n->right)
|
||||
tr.run([&] { right = traverse(n->right, compute); });
|
||||
});
|
||||
return compute(n) + left + right;
|
||||
}
|
||||
|
||||
The example above demonstrates the use of two of the functions proposed in this paper, `task_region` and
|
||||
`task_region_handle::run`.
|
||||
The `task_region` function delineates a region in a program code potentially containing invocations of tasks
|
||||
spawned by the `run` member function of the `task_region_handle` class.
|
||||
|
||||
The run function spawns a task, a unit of work that is allowed to execute in parallel with respect to the caller.
|
||||
Any parallel tasks spawned by `run` within the `task_region` are joined back to a single thread of execution at
|
||||
the end of the `task_region`.
|
||||
|
||||
`run` takes a user-provided function object `f` and starts it asynchronously - i.e. it may return before the
|
||||
execution of `f` completes. The implementation's scheduler may choose to run `f` immediately or delay running
|
||||
`f` until compute resources become available.
|
||||
|
||||
A `task_region_handle` can be constructed only by `task_region` because it has no public constructors.
|
||||
Thus, `run` can be invoked (directly or indirectly) only from a user-provided function passed to `task_region`:
|
||||
|
||||
void g();
|
||||
void f(task_region_handle& tr)
|
||||
{
|
||||
tr.run(g); // OK, invoked from within task_region in h
|
||||
}
|
||||
void h()
|
||||
{
|
||||
task_region(f);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
task_region_handle tr; // Error: no public constructor
|
||||
tr.run(g); // No way to call run outside of a task_region
|
||||
return 0;
|
||||
}
|
||||
|
||||
[endsect] [/ Tutorial]
|
||||
|
||||
[////////////////]
|
||||
[section:examples Examples]
|
||||
|
||||
[section:fib Parallel Fibonacci]
|
||||
|
||||
|
||||
This is surely the worst implementation of the Fibonacci function. Anyway, here it is, as it is simple and shows the fork-join structure clearly. `Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)`, so the task decomposition is trivial.
|
||||
|
||||
int fib_task_region(int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region(i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
[endsect] [/ Fib]
|
||||
[section:fibex Parallel Fibonacci - Specific executor]
|
||||
|
||||
The previous example make use of an implementation defined way to spawn the tasks. Often the user wants to master how the task must be spawned. There is an overload of `task_region` that accept an additional `Executor` parameter and a function that takes as parameter a `task_region_handle_gen<Executor>`. `task_region_handle_gen<Executor>` run uses this executor to spawn the tasks.
|
||||
|
||||
template <class Ex>
|
||||
int fib_task_region_gen( Ex& ex, int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle_gen;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region(ex, [&](task_region_handle_gen<Ex>& trh) // (2)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::basic_thread_pool tp; // (1)
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region_gen(tp,i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
The specific executor is declared in line (1) and it is used in line (2).
|
||||
|
||||
[endsect] [/ Fib ex]
|
||||
|
||||
|
||||
|
||||
|
||||
[section:quick_sort Parallel Accumulate]
|
||||
|
||||
|
||||
[endsect] [/ Accumulate]
|
||||
|
||||
[section:quick_sort Parallel Quick Sort]
|
||||
|
||||
|
||||
|
||||
[endsect] [/ QuickSort]
|
||||
[endsect] [/ Examples]
|
||||
|
||||
|
||||
[////////////////////////]
|
||||
[section:rationale Design Rationale]
|
||||
|
||||
|
||||
[endsect] [/ Design Rationale]
|
||||
[endsect] [/ Fork-Join]
|
||||
|
||||
[/////////////////////]
|
||||
[section:ref Reference -- EXPERIMENTAL]
|
||||
|
||||
[/////////////////////////]
|
||||
[section:v1 Parallel V1]
|
||||
|
||||
[section:exception_list Header `<experimental/exception_list.hpp>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
|
||||
class exception_list;
|
||||
|
||||
} // v1
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[/////////////////////////]
|
||||
[section:exception_list Class `exception_list`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
|
||||
class exception_list: public std::exception
|
||||
{
|
||||
public:
|
||||
typedef 'implementation defined' const_iterator;
|
||||
|
||||
~exception_list() noexcept {}
|
||||
|
||||
void add(exception_ptr const& e);
|
||||
size_t size() const noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const char* what() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // v1
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[endsect] [/ exception_list]
|
||||
|
||||
[endsect] [/ exception_list.hpp]
|
||||
|
||||
[endsect] [/ Parallel V1]
|
||||
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:v2 Parallel V2]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:concepts Concepts]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:regionCallable Concept `Region_Callable`]
|
||||
|
||||
[endsect] [/ Region_Callable]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:taskCallable Concept `Task_Callable`]
|
||||
|
||||
|
||||
[endsect] [/ Task_Callable]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[endsect] [/ Concepts]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region Header `<experimental/task_region.hpp>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_canceled_exception;
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen;
|
||||
|
||||
using default_executor = 'implementation defined';
|
||||
|
||||
class task_region_handle;
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region_final(F&& f);
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_canceled_exception Class `task_canceled_exception `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_canceled_exception: public std::exception
|
||||
{
|
||||
public:
|
||||
task_canceled_exception() noexcept;
|
||||
task_canceled_exception(const task_canceled_exception&) noexcept;
|
||||
task_canceled_exception& operator=(const task_canceled_exception&) noexcept;
|
||||
virtual const char* what() const noexcept;
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_canceled_exception]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_handle_gen Template Class `task_region_handle_gen<>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen
|
||||
{
|
||||
protected:
|
||||
task_region_handle_gen(Executor& ex);
|
||||
|
||||
~task_region_handle_gen();
|
||||
|
||||
public:
|
||||
task_region_handle_gen(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen& operator=(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen* operator&() const = delete;
|
||||
|
||||
template<typename F>
|
||||
void run(F&& f);
|
||||
|
||||
void wait();
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_handle_gen]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:default_executor Class `default_executor `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
using default_executor = 'implementation defined';
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ default_executor]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_handle Class `task_region_handle `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_region_handle :
|
||||
public task_region_handle_gen<default_executor>
|
||||
{
|
||||
protected:
|
||||
task_region_handle();
|
||||
task_region_handle(const task_region_handle&) = delete;
|
||||
task_region_handle& operator=(const task_region_handle&) = delete;
|
||||
task_region_handle* operator&() const = delete;
|
||||
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_handle]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_final Template Function `task_region_final `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region_final(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_final]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region Template Function `task_region `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region]
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect] [/ task_region.hpp]
|
||||
[endsect] [/ Parallel V2]
|
||||
[endsect] [/ Reference]
|
||||
|
||||
[endsect] [/ Parallel]
|
||||
@@ -15,24 +15,25 @@
|
||||
struct detach;
|
||||
struct join_if_joinable;
|
||||
struct interrupt_and_join_if_joinable;
|
||||
template <class CallableThread = join_if_joinable>
|
||||
template <class CallableThread = join_if_joinable, class Thread = thread>
|
||||
class strict_scoped_thread;
|
||||
template <class CallableThread = join_if_joinable>
|
||||
template <class CallableThread = join_if_joinable, class Thread = thread>
|
||||
class scoped_thread;
|
||||
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
|
||||
template <class CallableThread, class Thread = thread>
|
||||
void swap(scoped_thread<Callable, Thread>& lhs, scoped_threadCallable, Thread>& rhs) noexcept;
|
||||
|
||||
[section:motovation Motivation]
|
||||
[section:motivation Motivation]
|
||||
Based on the scoped_thread class defined in C++ Concurrency in Action Boost.Thread defines a thread wrapper class that instead of calling terminate if the thread is joinable on destruction, call a specific action given as template parameter.
|
||||
|
||||
While the scoped_thread class defined in C++ Concurrency in Action is closer to strict_scoped_thread class that doesn't allows any change in the wrapped thread, Boost.Thread provides a class scoped_thread that provides the same non-deprecated interface than __thread.
|
||||
While the scoped_thread class defined in C++ Concurrency in Action is closer to strict_scoped_thread class that doesn't allows any change in the wrapped thread, Boost.Thread provides a class scoped_thread that provides the same non-deprecated interface as __thread.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Scoped Threads are wrappers around a thread that allows the user to state what to do at destruction time. One of the common uses is to join the thread at destruction time so this is the default behavior. This is the single difference respect to a thread. While thread call std::terminate() on the destructor is the thread is joinable, strict_scoped_thread<> or scoped_thread<> join the thread if joinable.
|
||||
Scoped Threads are wrappers around a thread that allows the user to state what to do at destruction time. One of the common uses is to join the thread at destruction time so this is the default behavior. This is the single difference respect to a thread. While thread call std::terminate() on the destructor if the thread is joinable, strict_scoped_thread<> or scoped_thread<> join the thread if joinable.
|
||||
|
||||
The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface than __thread and forwards all the operations.
|
||||
The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface as __thread and forwards all the operations.
|
||||
|
||||
boost::strict_scoped_thread<> t1((boost::thread(f)));
|
||||
//t1.detach(); // compile fails
|
||||
@@ -54,7 +55,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
|
||||
struct detach
|
||||
{
|
||||
void operator()(thread& t)
|
||||
template <class Thread>
|
||||
void operator()(Thread& t)
|
||||
{
|
||||
t.detach();
|
||||
}
|
||||
@@ -64,7 +66,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
|
||||
struct join_if_joinable
|
||||
{
|
||||
void operator()(thread& t)
|
||||
template <class Thread>
|
||||
void operator()(Thread& t)
|
||||
{
|
||||
if (t.joinable())
|
||||
{
|
||||
@@ -79,7 +82,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
|
||||
struct interrupt_and_join_if_joinable
|
||||
{
|
||||
void operator()(thread& t)
|
||||
template <class Thread>
|
||||
void operator()(Thread& t)
|
||||
{
|
||||
t.interrupt();
|
||||
if (t.joinable())
|
||||
@@ -96,7 +100,7 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
|
||||
// #include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
template <class CallableThread = join_if_joinable>
|
||||
template <class CallableThread = join_if_joinable, class Thread = ::boost::thread>
|
||||
class strict_scoped_thread
|
||||
{
|
||||
thread t_; // for exposition purposes only
|
||||
@@ -105,7 +109,7 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
strict_scoped_thread(strict_scoped_thread const&) = delete;
|
||||
strict_scoped_thread& operator=(strict_scoped_thread const&) = delete;
|
||||
|
||||
explicit strict_scoped_thread(thread&& t) noexcept;
|
||||
explicit strict_scoped_thread(Thread&& t) noexcept;
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
|
||||
@@ -114,15 +118,15 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
|
||||
};
|
||||
|
||||
|
||||
RAI __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
RAII __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
|
||||
CallableThread: A callable `void(thread&)`.
|
||||
|
||||
The default is a `join_if_joinable`.
|
||||
|
||||
|
||||
`std/boost::thread` destructor terminates the program if the __thread is not joinable.
|
||||
This wrapper can be used to join the thread before destroying it seems a natural need.
|
||||
Thread destructor terminates the program if the __thread is joinable.
|
||||
This wrapper can be used to join the thread before destroying it.
|
||||
|
||||
[heading Example]
|
||||
|
||||
@@ -130,7 +134,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
[section:default_constructor Constructor from a __thread]
|
||||
|
||||
explicit strict_scoped_thread(thread&& t) noexcept;
|
||||
explicit strict_scoped_thread(Thread&& t) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -150,7 +154,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a internal thread in place.]]
|
||||
[[Effects:] [Construct an internal thread in place.]]
|
||||
|
||||
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
|
||||
|
||||
@@ -180,7 +184,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
template <class CallableThread>
|
||||
template <class CallableThread, class Thread = thread>
|
||||
class scoped_thread
|
||||
{
|
||||
thread t_; // for exposition purposes only
|
||||
@@ -230,16 +234,17 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
};
|
||||
|
||||
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
|
||||
template <class CallableThread, class Thread = thread>
|
||||
void swap(scoped_thread<CallableThread,Thread>& lhs,scoped_thread<CallableThread,Thread>& rhs) noexcept;
|
||||
|
||||
|
||||
RAI __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
RAII __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
|
||||
|
||||
CallableThread: A callable void(thread&).
|
||||
The default is join_if_joinable.
|
||||
|
||||
thread std::thread destructor terminates the program if the thread is not joinable.
|
||||
Having a wrapper that can join the thread before destroying it seems a natural need.
|
||||
Thread destructor terminates the program if the thread is joinable.
|
||||
This wrapper can be used to join the thread before destroying it.
|
||||
|
||||
Remark: `scoped_thread` is not a __thread as __thread is not designed to be derived from as a polymorphic type.
|
||||
|
||||
@@ -291,16 +296,14 @@ same non-deprecated interface with the exception of the construction.
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if
|
||||
any) to `*this`.
|
||||
any) to `*this` after having called to `CallableThread()(t_)`.
|
||||
|
||||
- if defined `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE`: If there was a `scoped_thread` previously associated with `*this` then that `scoped_thread` is detached, DEPRECATED
|
||||
|
||||
- if defined `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE`: If the `scoped_thread` is joinable calls to std::terminate.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
@@ -312,9 +315,9 @@ any) to `*this`.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [move the thread to own `t_`.]]
|
||||
[[Effects:] [Transfers ownership of the thread managed by `other` (if any) to the newly constructed scoped_thread instance.]]
|
||||
|
||||
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
|
||||
[[Postconditions:] [other.get_id()==thread::id() and get_id() returns the value of other.get_id() prior to the construction.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
@@ -329,7 +332,7 @@ any) to `*this`.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a internal thread in place.]]
|
||||
[[Effects:] [Construct an internal thread in place.]]
|
||||
|
||||
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
|
||||
|
||||
@@ -506,7 +509,8 @@ any) to `*this`.
|
||||
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
|
||||
template <class CallableThread, class Thread = thread>
|
||||
void swap(scoped_thread<Callable, Thread>& lhs, scoped_threadCallable, Thread>& rhs) noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
|
||||
@@ -110,10 +110,10 @@ where
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `lve` denotes an lvalue reference of type Q::value_type,
|
||||
* `rve` denotes an rvalue reference of type Q::value_type:
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
* `qs` denotes a variable of of type `queus_op_status`,
|
||||
* `qs` denotes a variable of of type `queue_op_status`,
|
||||
|
||||
|
||||
[/////////////////////////////////////]
|
||||
@@ -181,7 +181,7 @@ where
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety.]]
|
||||
[[Requires:] [Q::value_type is no throw move constructible. This is needed to ensure the exception safety.]]
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element.]]
|
||||
|
||||
@@ -206,7 +206,7 @@ where
|
||||
|
||||
[variablelist
|
||||
|
||||
[/[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety. ]]
|
||||
[/[Requires:] [Q::value_type is no throw move assignable. This is needed to ensure the exception safety. ]]
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element into a shared_ptr.]]
|
||||
|
||||
@@ -246,8 +246,8 @@ where
|
||||
* `e` denotes a value of type `Q::value_type`,
|
||||
* `s` denotes a value of type `queue_status`,
|
||||
* `u` denotes a value of type `Q::size_type`,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `lve` denotes an lvalue reference of type Q::value_type,
|
||||
* `rve` denotes an rvalue reference of type Q::value_type:
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
|
||||
|
||||
@@ -314,7 +314,7 @@ where
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [If the queue is not empty pulls the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -357,8 +357,8 @@ where
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `s` denotes a value of type `queue_status`,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `lve` denotes an lvalue reference of type Q::value_type,
|
||||
* `rve` denotes an rvalue reference of type Q::value_type:
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
|
||||
|
||||
@@ -393,7 +393,7 @@ where
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_push_back_m `s = q.nonblocking_push_back(rve());`]
|
||||
[section:nonblocking_push_back_m `s = q.nonblocking_push_back(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -427,7 +427,7 @@ where
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [If the queue is not empty pulls the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -545,7 +545,7 @@ Closed queues add the following valid expressions
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is closed retun `queue_op_status::closed`,
|
||||
- If the queue is closed return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
|
||||
@@ -636,12 +636,12 @@ Closed queues add the following valid expressions
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
template <typename ValueType, class SizeType=std::size_t>
|
||||
class queue_base
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef SizeType size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base() {};
|
||||
@@ -671,7 +671,7 @@ Closed queues add the following valid expressions
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
virtual queue_op_status wait_pull_front(value_type& elem) = 0;
|
||||
|
||||
};
|
||||
}
|
||||
@@ -685,11 +685,11 @@ Closed queues add the following valid expressions
|
||||
namespace boost
|
||||
{
|
||||
template <typename Queue>
|
||||
class queue_adaptor : public queue_base<typename Queue::value_type>
|
||||
class queue_adaptor : public queue_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
@@ -769,22 +769,14 @@ Closed queues add the following valid expressions
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
void pull(value_type& x);
|
||||
value_type pull();
|
||||
|
||||
queue_op_status try_push(const value_type& x);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status try_pull(value_type& x);
|
||||
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x);
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x);
|
||||
|
||||
queue_op_status wait_push(const value_type& x);
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status wait_pull_front(value_type& x);
|
||||
|
||||
};
|
||||
|
||||
@@ -812,24 +804,13 @@ Closed queues add the following valid expressions
|
||||
// Modifiers
|
||||
void close();
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
void pull(value_type& x);
|
||||
value_type pull();
|
||||
|
||||
queue_op_status try_push(const value_type& x);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status try_pull(value_type& x);
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x);
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x);
|
||||
|
||||
queue_op_status wait_push(const value_type& x);
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
queue_op_status wait_pull(value_type& x);
|
||||
|
||||
};
|
||||
@@ -1002,13 +983,13 @@ Closed queues add the following valid expressions
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <typename ValueType>
|
||||
template <typename ValueType, class Container = csbl::devector<ValueType>>
|
||||
class sync_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef csbl::deque<ValueType> underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef Container underlying_queue_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
|
||||
sync_queue(sync_queue const&) = delete;
|
||||
sync_queue& operator=(sync_queue const&) = delete;
|
||||
|
||||
@@ -156,7 +156,7 @@ object passed to the constructor.]]
|
||||
};
|
||||
}
|
||||
|
||||
`externally_locked_stream` cloaks a reference to an stream of type `Stream`, and actually
|
||||
`externally_locked_stream` cloaks a reference to a stream of type `Stream`, and actually
|
||||
provides full access to that object through the `get` member functions, provided you
|
||||
pass a reference to a strict lock object.
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
[@http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost.
|
||||
|
||||
[@http://web.archive.org/web/20140531071228/http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost.
|
||||
|
||||
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html Mutex, Lock, Condition Variable Rationale] adds rationale for the design decisions made for mutexes, locks and condition variables.
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ Both forms of pointer dereference return a proxy object rather than a real refer
|
||||
|
||||
The pointer-like semantics work very well for simple accesses such as assignment and calls to member functions. However, sometimes you need to perform an operation that requires multiple accesses under protection of the same lock, and that's what the synchronize() method provides.
|
||||
|
||||
By calling synchronize() you obtain an strict_lock_ptr object that holds a lock on the mutex protecting the data, and which can be used to access the protected data. The lock is held until the strict_lock_ptr object is destroyed, so you can safely perform multi-part operations. The strict_lock_ptr object also acts as a pointer-to-T, just like synchronized_value does, but this time the lock is already held. For example, the following function adds a trailing slash to a path held in a synchronized_value. The use of the strict_lock_ptr object ensures that the string hasn't changed in between the query and the update.
|
||||
By calling synchronize() you obtain a strict_lock_ptr object that holds a lock on the mutex protecting the data, and which can be used to access the protected data. The lock is held until the strict_lock_ptr object is destroyed, so you can safely perform multi-part operations. The strict_lock_ptr object also acts as a pointer-to-T, just like synchronized_value does, but this time the lock is already held. For example, the following function adds a trailing slash to a path held in a synchronized_value. The use of the strict_lock_ptr object ensures that the string hasn't changed in between the query and the update.
|
||||
|
||||
void addTrailingSlashIfMissing(boost::synchronized_value<std::string> & path)
|
||||
{
|
||||
|
||||
@@ -88,9 +88,9 @@
|
||||
typedef T value_type;
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
synchronized_value() noexept(is_nothrow_default_constructible<T>::value);
|
||||
synchronized_value(T const& other) noexept(is_nothrow_copy_constructible<T>::value);
|
||||
synchronized_value(T&& other) noexept(is_nothrow_move_constructible<T>::value);
|
||||
synchronized_value() noexcept(is_nothrow_default_constructible<T>::value);
|
||||
synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value);
|
||||
synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value);
|
||||
synchronized_value(synchronized_value const& rhs);
|
||||
synchronized_value(synchronized_value&& other);
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
|
||||
[section:constructor `synchronized_value()`]
|
||||
|
||||
synchronized_value() noexept(is_nothrow_default_constructible<T>::value);
|
||||
synchronized_value() noexcept(is_nothrow_default_constructible<T>::value);
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
|
||||
[section:constructor_vt `synchronized_value(T const&)`]
|
||||
|
||||
synchronized_value(T const& other) noexept(is_nothrow_copy_constructible<T>::value);
|
||||
synchronized_value(T const& other) noexcept(is_nothrow_copy_constructible<T>::value);
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -175,11 +175,11 @@
|
||||
|
||||
[section:move_vt `synchronized_value(T&&)`]
|
||||
|
||||
synchronized_value(T&& other) noexept(is_nothrow_move_constructible<T>::value);
|
||||
synchronized_value(T&& other) noexcept(is_nothrow_move_constructible<T>::value);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyMovable `.]]
|
||||
[[Requires:] [`T` is `MoveConstructible `.]]
|
||||
[[Effects:] [Move constructs the cloaked value_type]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(value_type&&)`.]]
|
||||
@@ -194,7 +194,7 @@
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `CopyMovable `.]]
|
||||
[[Requires:] [`T` is `MoveConstructible `.]]
|
||||
[[Effects:] [Move constructs the cloaked value_type]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]]
|
||||
@@ -209,7 +209,7 @@
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Assignale`.]]
|
||||
[[Requires:] [`T` is `Assignable`.]]
|
||||
[[Effects:] [Copies the underlying value on a scope protected by the two mutexes. The mutex is not copied. The locks are acquired avoiding deadlock. For example, there is no problem if one thread assigns `a = b` and the other assigns `b = a`.]]
|
||||
[[Return:] [`*this`]]
|
||||
|
||||
@@ -224,7 +224,7 @@
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Assignale`.]]
|
||||
[[Requires:] [`T` is `Assignable`.]]
|
||||
[[Effects:] [Copies the value on a scope protected by the mutex.]]
|
||||
[[Return:] [`*this`]]
|
||||
|
||||
@@ -273,7 +273,7 @@
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`T` is `Assignale`.]]
|
||||
[[Requires:] [`T` is `Assignable`.]]
|
||||
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]]
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 4.4.0]
|
||||
[version 4.7.2]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-14 Vicente J. Botet Escriba]
|
||||
[copyright 2011-16 Vicente J. Botet Escriba]
|
||||
[purpose C++ Library for launching threads and synchronizing data between them]
|
||||
[category text]
|
||||
[license
|
||||
@@ -244,7 +244,6 @@
|
||||
[include futures.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
[include tss.qbk]
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
@@ -253,6 +252,8 @@
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
[include parallel.qbk]
|
||||
|
||||
[include time.qbk]
|
||||
|
||||
[include emulations.qbk]
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
{
|
||||
thread::id get_id() noexcept;
|
||||
template<typename TimeDuration>
|
||||
void yield() noexcept; // DEPRECATED
|
||||
void yield() noexcept;
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
template <class Rep, class Period>
|
||||
@@ -125,7 +125,7 @@ the user to set the platform specific attributes. Boost.Thread stay in the middl
|
||||
thread::attributes which allows to set at least in a portable way the stack size as follows:
|
||||
|
||||
boost::thread::attributes attrs;
|
||||
attrs.set_size(4096*10);
|
||||
attrs.set_stack_size(4096*10);
|
||||
boost::thread deep_thought_2(attrs, find_the_question, 42);
|
||||
|
||||
Even for this simple attribute there could be portable issues as some platforms could require that the stack size
|
||||
@@ -147,7 +147,7 @@ Next follows how the user could set the stack size and the scheduling policy on
|
||||
// ... window version
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
// ... pthread version
|
||||
pthread_attr_setschedpolicy(attr.get_native_handle(), SCHED_RR);
|
||||
pthread_attr_setschedpolicy(attr.native_handle(), SCHED_RR);
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
@@ -255,7 +255,7 @@ does not complete when the specified time has elapsed or reached respectively.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor1 Destructor V1]
|
||||
[section:destructor1 Destructor V1-2]
|
||||
|
||||
When the __thread__ object that represents a thread of execution is destroyed the thread becomes ['detached]. Once a thread is
|
||||
detached, it will continue executing until the invocation of the function or callable object supplied on construction has completed,
|
||||
@@ -264,7 +264,7 @@ object. In this case, the __thread__ object ceases to represent the now-detached
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor2 Destructor V2]
|
||||
[section:destructor2 Destructor V3-X]
|
||||
|
||||
When the __thread__ object that represents a thread of execution is destroyed the program terminates if the thread is __joinable__.
|
||||
|
||||
@@ -280,7 +280,7 @@ You can use a thread_joiner to ensure that the thread has been joined at the thr
|
||||
{
|
||||
boost::thread t(my_func);
|
||||
boost::thread_joiner g(t);
|
||||
// do someting else
|
||||
// do something else
|
||||
} // here the thread_joiner destructor will join the thread before it is destroyed.
|
||||
|
||||
[endsect]
|
||||
@@ -289,9 +289,11 @@ You can use a thread_joiner to ensure that the thread has been joined at the thr
|
||||
|
||||
A running thread can be ['interrupted] by invoking the __interrupt__ member function of the corresponding __thread__ object. When the
|
||||
interrupted thread next executes one of the specified __interruption_points__ (or if it is currently __blocked__ whilst executing one)
|
||||
with interruption enabled, then a __thread_interrupted__ exception will be thrown in the interrupted thread. If not caught,
|
||||
this will cause the execution of the interrupted thread to terminate. As with any other exception, the stack will be unwound, and
|
||||
destructors for objects of automatic storage duration will be executed.
|
||||
with interruption enabled, then a __thread_interrupted__ exception will be thrown in the interrupted thread. Unless this exception is
|
||||
caught inside the interrupted thread's thread-main function, the stack unwinding process (as with any other exception) causes the
|
||||
destructors with automatic storage duration to be executed. Unlike other exceptions, when __thread_interrupted__ is propagated out of
|
||||
thread-main function, this does not cause the call to `std::terminate`; the effect is as though the thread-main function has returned
|
||||
normally.
|
||||
|
||||
If a thread wishes to avoid being interrupted, it can create an instance of __disable_interruption__. Objects of this class disable
|
||||
interruption for the thread that created them on construction, and restore the interruption state to whatever it was before on
|
||||
@@ -410,7 +412,7 @@ Of course all the synchronization facilities provided by Boost.Thread are also a
|
||||
|
||||
The `boost::this_thread` interrupt related functions behave in a degraded mode when called from a thread created using the native interface, i.e. `boost::this_thread::interruption_enabled()` returns false. As consequence the use of `boost::this_thread::disable_interruption` and `boost::this_thread::restore_interruption` will do nothing and calls to `boost::this_thread::interruption_point()` will be just ignored.
|
||||
|
||||
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` wiil returns false for the native threads.
|
||||
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` will return false for the native threads.
|
||||
|
||||
[heading `pthread_exit` POSIX limitation]
|
||||
|
||||
@@ -432,12 +434,14 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
class attributes; // EXTENSION
|
||||
|
||||
thread() noexcept;
|
||||
~thread();
|
||||
|
||||
thread(const thread&) = delete;
|
||||
thread& operator=(const thread&) = delete;
|
||||
|
||||
// move support
|
||||
thread(thread&&) noexcept;
|
||||
thread& operator=(thread&&) noexcept;
|
||||
~thread();
|
||||
|
||||
template <class F>
|
||||
explicit thread(F f);
|
||||
@@ -456,10 +460,6 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
template <class F, class ...Args>
|
||||
explicit thread(attributes& attrs, F&& f, Args&&... args);
|
||||
|
||||
// move support
|
||||
thread(thread && x) noexcept;
|
||||
thread& operator=(thread && x) noexcept;
|
||||
|
||||
void swap(thread& x) noexcept;
|
||||
|
||||
class id;
|
||||
@@ -713,7 +713,7 @@ are copied into internal storage for access by the new thread.]]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Note:] [The reason to moving to std::terminate is that either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. Join the thread before destroying or use an scoped thread.]]
|
||||
[[Note:] [The reason to moving to std::terminate is that either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. Join the thread before destroying or use a scoped thread.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -955,7 +955,7 @@ a default-constructed __thread_id__.]]
|
||||
|
||||
[[Effects:] [If `*this` refers to a thread of execution, request that the thread will be interrupted the next time it enters one of
|
||||
the predefined __interruption_points__ with interruption enabled, or if it is currently __blocked__ in a call to one of the
|
||||
predefined __interruption_points__ with interruption enabled .]]
|
||||
predefined __interruption_points__ with interruption enabled. Otherwise do noting.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
@@ -966,7 +966,7 @@ predefined __interruption_points__ with interruption enabled .]]
|
||||
|
||||
[section:hardware_concurrency Static member function `hardware_concurrency()`]
|
||||
|
||||
unsigned hardware_concurrency() noexecpt;
|
||||
unsigned hardware_concurrency() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -981,7 +981,7 @@ or 0 if this information is not available.]]
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
unsigned physical_concurrency() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -1292,7 +1292,7 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a thread atrributes instance with its default values.]]
|
||||
[[Effects:] [Constructs a thread attributes instance with its default values.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
@@ -1306,7 +1306,7 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Stores the stack size to be used to create a thread. This is an hint that the implementation can choose a better size if to small or too big or not aligned to a page.]]
|
||||
[[Effects:] [Stores the stack size to be used to create a thread. This is a hint that the implementation can choose a better size if to small or too big or not aligned to a page.]]
|
||||
|
||||
[[Postconditions:] [`this-> get_stack_size()` returns the chosen stack size.]]
|
||||
|
||||
@@ -1534,7 +1534,7 @@ do not throw exceptions. __thread_interrupted__ if the current thread of executi
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Suspends the current thread until the duration specified by
|
||||
[[Effects:] [Suspends the current thread until the duration specified
|
||||
by `rel_time` has elapsed.]]
|
||||
|
||||
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted.]]
|
||||
|
||||
61
example/default_executor.cpp
Normal file
61
example/default_executor.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// 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>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
|
||||
|
||||
boost::generic_executor_ref default_executor()
|
||||
{
|
||||
static boost::basic_thread_pool tp(4);
|
||||
return boost::generic_executor_ref(tp);
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void p1()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
default_executor().submit(&p2);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(400));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
|
||||
default_executor().submit(&p1);
|
||||
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(5));
|
||||
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
@@ -7,6 +7,7 @@
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#include <iostream>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
@@ -27,6 +28,12 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
boost::future<void> p(boost::future<void> f) {
|
||||
assert(f.is_ready());
|
||||
return boost::make_ready_future();
|
||||
}
|
||||
|
||||
void p1()
|
||||
{
|
||||
@@ -42,8 +49,9 @@ void p2()
|
||||
|
||||
int f1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
return 1;
|
||||
}
|
||||
int f2(int i)
|
||||
@@ -72,61 +80,95 @@ void at_th_entry(boost::basic_thread_pool& )
|
||||
|
||||
int test_executor_adaptor()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::executor_adaptor < boost::basic_thread_pool > ea(4);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
submit_some( ea);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
#if 1
|
||||
// fixme
|
||||
// ERROR= tr1::bad_weak_ptr
|
||||
{
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
boost::future<int> t2 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
submit_some(ea);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea3(1);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::future<int> t1 = boost::async(ea3, &f1);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::future<int> t2 = boost::async(ea3, &f1);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
//boost::future<int> t2 = boost::async(ea3, f2, 1); // todo this doesn't compiles yet on C++11
|
||||
//boost::future<int> t2 = boost::async(ea3, boost::bind(f2, 1)); // todo this doesn't compiles yet on C++98
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
#endif
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
submit_some(ea);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::loop_executor > ea2;
|
||||
submit_some( ea2);
|
||||
ea2.underlying_executor().run_queued_closures();
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::basic_thread_pool > ea1(4);
|
||||
boost::executor_adaptor < boost::serial_executor > ea2(ea1);
|
||||
submit_some(ea2);
|
||||
}
|
||||
#endif
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::inline_executor > ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::thread_executor > ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
#if 1
|
||||
// fixme
|
||||
// ERROR= tr1::bad_weak_ptr
|
||||
{
|
||||
boost::basic_thread_pool ea(4, at_th_entry);
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
}
|
||||
#endif
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::async(&f1);
|
||||
}
|
||||
#if 1
|
||||
// fixme
|
||||
// ERROR= tr1::bad_weak_ptr
|
||||
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea(1);
|
||||
boost::async(ea,&f1);
|
||||
}
|
||||
#endif
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
@@ -147,4 +189,19 @@ int test_executor_adaptor()
|
||||
int main()
|
||||
{
|
||||
return test_executor_adaptor();
|
||||
|
||||
#if 0 && defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& defined BOOST_THREAD_PROVIDES_EXECUTORS \
|
||||
&& ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
boost::basic_thread_pool executor;
|
||||
// compiles
|
||||
boost::make_ready_future().then(&p);
|
||||
|
||||
// ??
|
||||
boost::make_ready_future().then(executor, &p);
|
||||
|
||||
// doesn't compile
|
||||
boost::make_ready_future().then(executor, &p);
|
||||
#endif
|
||||
}
|
||||
|
||||
91
example/fib_task_region.cpp
Normal file
91
example/fib_task_region.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// 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>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
|
||||
#include <boost/thread/experimental/task_region.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR && ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
|
||||
int fib_task_region(int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
template <class Ex>
|
||||
int fib_task_region_gen( Ex& ex, int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle_gen;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region(ex, [&](task_region_handle_gen<Ex>& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region(i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
boost::basic_thread_pool tp;
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region_gen(tp,i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -35,31 +35,83 @@ int p1()
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
const int number_of_tests = 200;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f1.wait();
|
||||
BOOST_ASSERT(f1.get()==1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
//boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(&p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.fallback_to(-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f2.wait();
|
||||
//std::cout << __FILE__ << "["<< __LINE__<<"] " << std::endl;
|
||||
BOOST_ASSERT(f2.get()==1);
|
||||
//std::cout << __FILE__ << "["<< __LINE__<<"] " << std::endl;
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1_ex);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f1.wait();
|
||||
BOOST_ASSERT(f1.get_or(-1)==-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
@@ -75,18 +127,20 @@ int main()
|
||||
boost::future<int> f2 = f1.fallback_to(-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f2.wait();
|
||||
//std::cout << __FILE__ << "["<< __LINE__<<"] " << std::endl;
|
||||
BOOST_ASSERT(f2.get()==-1);
|
||||
//std::cout << __FILE__ << "["<< __LINE__<<"] " << std::endl;
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
std::cout << __FILE__ << "["<< __LINE__<<"] " << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -41,10 +41,28 @@ int main()
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
|
||||
boost::future<int> inner_future = outer_future.unwrap();
|
||||
int ii = inner_future.get();
|
||||
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
{
|
||||
boost::future<int> inner_future = boost::async(boost::launch::async, &p2).unwrap();
|
||||
inner_future.wait();
|
||||
int ii = inner_future.get();
|
||||
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
|
||||
boost::future<int> inner_future = outer_future.unwrap();
|
||||
inner_future.wait();
|
||||
int ii = inner_future.get();
|
||||
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
|
||||
boost::future<int> inner_future = outer_future.unwrap();
|
||||
int ii = inner_future.get();
|
||||
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
|
||||
@@ -58,6 +58,8 @@ int p2(boost::future<int> f)
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "P2>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
|
||||
}
|
||||
int p2s(boost::shared_future<int> f)
|
||||
{
|
||||
@@ -81,6 +83,7 @@ int p2s(boost::shared_future<int> f)
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "P2>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main()
|
||||
|
||||
@@ -73,7 +73,7 @@ void at_th_entry(boost::basic_thread_pool& )
|
||||
|
||||
int test_generic_executor_ref()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -83,8 +83,8 @@ int test_generic_executor_ref()
|
||||
{
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
boost::future<int> t2 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
submit_some(ea);
|
||||
{
|
||||
@@ -93,41 +93,51 @@ int test_generic_executor_ref()
|
||||
boost::future<int> t2 = boost::async(ea3, &f1);
|
||||
//boost::future<int> t2 = boost::async(ea3, f2, 1); // todo this doesn't compiles yet on C++11
|
||||
//boost::future<int> t2 = boost::async(ea3, boost::bind(f2, 1)); // todo this doesn't compiles yet on C++98
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
submit_some(ea);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::loop_executor ea2;
|
||||
submit_some( ea2);
|
||||
ea2.run_queued_closures();
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea1(4);
|
||||
boost::serial_executor ea2(ea1);
|
||||
submit_some(ea2);
|
||||
}
|
||||
#endif
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::inline_executor ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
//boost::thread_executor ea1;
|
||||
//submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea(4, at_th_entry);
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
}
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea(4, at_th_entry);
|
||||
boost::async(ea, &f1);
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
|
||||
@@ -42,6 +42,14 @@ int main()
|
||||
int result = f2.get();
|
||||
BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if ! defined BOOST_NO_CXX14_GENERIC_LAMBDAS
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
|
||||
boost::future<int> f2 = f1.then([](auto f) {return 2*f.get(); });
|
||||
int result = f2.get();
|
||||
BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
|
||||
@@ -94,6 +94,11 @@ int main()
|
||||
f.get();
|
||||
}
|
||||
#endif
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int> f = compute(-1);
|
||||
f.wait();
|
||||
}
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int> f = compute(0);
|
||||
@@ -104,11 +109,31 @@ int main()
|
||||
boost::future<int&> f = compute_ref(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
// {
|
||||
// std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
// boost::future<int> f = compute(2);
|
||||
// std::cout << f.get() << std::endl;
|
||||
// }
|
||||
#if __cplusplus > 201103L
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
int i = 0;
|
||||
boost::future<int&> f = boost::make_ready_future(std::ref(i));
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
int i = 0;
|
||||
boost::future<int&> f = boost::make_ready_future(boost::ref(i));
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
const int i = 0;
|
||||
boost::future<int const&> f = boost::make_ready_future(boost::cref(i));
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int> f = compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::shared_future<int> f = shared_compute(0);
|
||||
|
||||
@@ -22,32 +22,32 @@
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
|
||||
void producer(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
void producer(the_ostream & /*mos*/, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
sbq.push_back(i);
|
||||
sbq.push(i);
|
||||
//sbq << i;
|
||||
mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
|
||||
//mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(
|
||||
the_ostream &mos,
|
||||
the_ostream & /*mos*/,
|
||||
boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
@@ -55,58 +55,58 @@ void consumer(
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull_front(r);
|
||||
sbq.pull(r);
|
||||
//sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
//mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
void consumer2(the_ostream &/*mos*/, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status st = sbq.try_pull_front(r);
|
||||
queue_op_status st = sbq.try_pull(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
//mos << i << " pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
void consumer3(the_ostream &/*mos*/, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status res = sbq.wait_pull_front(r);
|
||||
queue_op_status res = sbq.wait_pull(r);
|
||||
if (res==queue_op_status::closed) break;
|
||||
mos << i << " wait_pull_front(" << r << ")\n";
|
||||
//mos << i << " wait_pull(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_adaptor.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_views.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
void producer(the_ostream &mos, boost::queue_back<int> sbq)
|
||||
void producer(the_ostream &/*mos*/, boost::queue_back<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
@@ -35,22 +35,22 @@ void producer(the_ostream &mos, boost::queue_back<int> sbq)
|
||||
{
|
||||
sbq.push(i);
|
||||
//sbq << i;
|
||||
mos << "push(" << i << ") " << sbq.size() <<"\n";
|
||||
//mos << "push(" << i << ") " << sbq.size() <<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(
|
||||
the_ostream &mos,
|
||||
the_ostream &/*mos*/,
|
||||
boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
@@ -60,21 +60,21 @@ void consumer(
|
||||
int r;
|
||||
sbq.pull(r);
|
||||
//sbq >> r;
|
||||
mos << i << " pull(" << r << ") " << sbq.size() <<"\n";
|
||||
//mos << i << " pull(" << r << ") " << sbq.size() <<"\n";
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
void consumer2(the_ostream &/*mos*/, boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
@@ -84,17 +84,17 @@ void consumer2(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
queue_op_status st = sbq.try_pull(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
mos << i << " try_pull(" << r << ")\n";
|
||||
//mos << i << " try_pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer3(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
void consumer3(the_ostream &/*mos*/, boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
@@ -103,13 +103,13 @@ void consumer3(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
int r;
|
||||
queue_op_status res = sbq.wait_pull(r);
|
||||
if (res==queue_op_status::closed) break;
|
||||
mos << i << " wait_pull(" << r << ")\n";
|
||||
//mos << i << " wait_pull(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ counter c;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
std::cout << "count == " << c.increment() << std::endl;
|
||||
//std::cout << "count == " << c.increment() << std::endl;
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
|
||||
@@ -39,36 +39,23 @@ void do_something_in_current_thread()
|
||||
{
|
||||
}
|
||||
|
||||
//void do_something_with_current_thread(boost::thread&& th)
|
||||
//{
|
||||
// th.join();
|
||||
//}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
int some_local_state;
|
||||
int some_local_state=0;
|
||||
boost::strict_scoped_thread<> t( (boost::thread(func(some_local_state))));
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state;
|
||||
int some_local_state=0;
|
||||
boost::thread t(( func(some_local_state) ));
|
||||
boost::strict_scoped_thread<> g( (boost::move(t)) );
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
// {
|
||||
// int some_local_state;
|
||||
// boost::thread t(( func(some_local_state) ));
|
||||
// boost::strict_scoped_thread<> g( (boost::move(t)) );
|
||||
//
|
||||
// do_something_in_current_thread();
|
||||
// do_something_with_current_thread(boost::thread(g));
|
||||
// }
|
||||
{
|
||||
int some_local_state;
|
||||
int some_local_state=0;
|
||||
boost::scoped_thread<> t( (boost::thread(func(some_local_state))));
|
||||
|
||||
if (t.joinable())
|
||||
@@ -77,10 +64,11 @@ int main()
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state;
|
||||
int some_local_state=0;
|
||||
boost::thread t(( func(some_local_state) ));
|
||||
boost::scoped_thread<> g( (boost::move(t)) );
|
||||
t.detach();
|
||||
if (g.joinable())
|
||||
g.detach();
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
|
||||
107
example/serial_executor.cpp
Normal file
107
example/serial_executor.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright (C) 2015 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/serial_executor.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
#include <boost/thread/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
void p1()
|
||||
{
|
||||
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(30));
|
||||
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
||||
//std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
int f1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 1;
|
||||
}
|
||||
int f2(int i)
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
void submit_some(boost::serial_executor& tp)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
tp.submit(&p2);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
tp.submit(&p1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
void at_th_entry(boost::basic_thread_pool& )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int test_executor_adaptor()
|
||||
{
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
{
|
||||
boost::basic_thread_pool ea1(4);
|
||||
boost::serial_executor ea2(ea1);
|
||||
submit_some(ea2);
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
return test_executor_adaptor();
|
||||
}
|
||||
113
example/serial_executor_cont.cpp
Normal file
113
example/serial_executor_cont.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (C) 2015 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/serial_executor_cont.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
#include <boost/thread/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
void p1()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(30));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(10));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
int f1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 1;
|
||||
}
|
||||
int f2(int i)
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
void submit_some(boost::serial_executor_cont& tp)
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
tp.submit(&p2);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
tp.submit(&p1);
|
||||
}
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void at_th_entry(boost::basic_thread_pool& )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int test_executor_adaptor()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea1(4);
|
||||
boost::serial_executor_cont ea2(ea1);
|
||||
submit_some(ea2);
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
}
|
||||
#endif
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
return test_executor_adaptor();
|
||||
}
|
||||
112
example/std_scoped_thread.cpp
Normal file
112
example/std_scoped_thread.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// (C) Copyright 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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)
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_VERSION 3
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <thread>
|
||||
#include <cassert>
|
||||
|
||||
void do_something(int& i)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
void f(int, int)
|
||||
{
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
int& i;
|
||||
|
||||
func(int& i_) :
|
||||
i(i_)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
for (unsigned j = 0; j < 1000000; ++j)
|
||||
{
|
||||
do_something(i);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void do_something_in_current_thread()
|
||||
{
|
||||
}
|
||||
|
||||
using strict_scoped_thread = boost::strict_scoped_thread<boost::join_if_joinable, std::thread>;
|
||||
using scoped_thread = boost::scoped_thread<boost::join_if_joinable, std::thread>;
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
int some_local_state=0;
|
||||
strict_scoped_thread t( (std::thread(func(some_local_state))));
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state=0;
|
||||
std::thread t(( func(some_local_state) ));
|
||||
strict_scoped_thread g( (boost::move(t)) );
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state=0;
|
||||
std::thread t(( func(some_local_state) ));
|
||||
strict_scoped_thread g( (std::move(t)) );
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
{
|
||||
int some_local_state=1;
|
||||
scoped_thread t( (std::thread(func(some_local_state))));
|
||||
|
||||
if (t.joinable()) {
|
||||
t.join();
|
||||
assert( ! t.joinable() );
|
||||
}
|
||||
else
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
#if ! defined __clang__
|
||||
try
|
||||
{
|
||||
int some_local_state=1;
|
||||
std::thread t(( func(some_local_state) ));
|
||||
scoped_thread g( (boost::move(t)) );
|
||||
if (g.joinable()) {
|
||||
// CLANG crash here
|
||||
g.detach();
|
||||
assert( ! g.joinable() );
|
||||
}
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
catch (...) {
|
||||
assert( false);
|
||||
}
|
||||
#endif
|
||||
{
|
||||
scoped_thread g( &f, 1, 2 );
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
66
example/std_thread_guard.cpp
Normal file
66
example/std_thread_guard.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
// (C) Copyright 2009-2012 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// 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)
|
||||
|
||||
#if __cplusplus < 201103L
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/thread_guard.hpp>
|
||||
#include <thread>
|
||||
|
||||
void do_something(int& i)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
int& i;
|
||||
|
||||
func(int& i_):i(i_){}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
for(unsigned j=0;j<1000000;++j)
|
||||
{
|
||||
do_something(i);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
func& operator=(func const&);
|
||||
|
||||
};
|
||||
|
||||
void do_something_in_current_thread()
|
||||
{}
|
||||
|
||||
using thread_guard = boost::thread_guard<boost::join_if_joinable, std::thread>;
|
||||
|
||||
|
||||
void f()
|
||||
{
|
||||
int some_local_state;
|
||||
func my_func(some_local_state);
|
||||
std::thread t(my_func);
|
||||
thread_guard g(t);
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
f();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -39,7 +39,7 @@ const char* player_name(int state)
|
||||
if (state == PLAYER_B)
|
||||
return "PLAYER-B";
|
||||
throw "bad player";
|
||||
return 0;
|
||||
//return 0;
|
||||
}
|
||||
|
||||
void player(int active)
|
||||
@@ -50,7 +50,7 @@ void player(int active)
|
||||
|
||||
while (state < GAME_OVER)
|
||||
{
|
||||
std::cout << player_name(active) << ": Play." << std::endl;
|
||||
//std::cout << player_name(active) << ": Play." << std::endl;
|
||||
state = other;
|
||||
cond.notify_all();
|
||||
do
|
||||
|
||||
86
example/this_executor.cpp
Normal file
86
example/this_executor.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// 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>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
|
||||
struct current_executor_state_type {
|
||||
boost::shared_ptr<boost::generic_executor_ref> current_executor_ptr;
|
||||
|
||||
template <class Executor>
|
||||
void set_current_executor(Executor& ex)
|
||||
{
|
||||
current_executor_ptr = boost::make_shared<boost::generic_executor_ref>(ex);
|
||||
}
|
||||
boost::generic_executor_ref current_executor()
|
||||
{
|
||||
if (current_executor_ptr)
|
||||
return *current_executor_ptr;
|
||||
else
|
||||
throw "";
|
||||
}
|
||||
};
|
||||
|
||||
thread_local current_executor_state_type current_executor_state;
|
||||
|
||||
boost::generic_executor_ref current_executor()
|
||||
{
|
||||
return current_executor_state.current_executor();
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void p1()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
current_executor().submit(&p2);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(400));
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
|
||||
boost::basic_thread_pool tp(4,
|
||||
// at_thread_entry
|
||||
[](boost::basic_thread_pool& pool)
|
||||
{
|
||||
current_executor_state.set_current_executor(pool);
|
||||
}
|
||||
);
|
||||
|
||||
tp.submit(&p1);
|
||||
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(5));
|
||||
|
||||
std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
@@ -59,6 +59,7 @@ int main()
|
||||
threads.remove_thread(th);
|
||||
BOOST_TEST(! threads.is_thread_in(th));
|
||||
th->join();
|
||||
delete th;
|
||||
}
|
||||
{
|
||||
{
|
||||
|
||||
@@ -24,6 +24,7 @@ void thread_proc()
|
||||
increment();
|
||||
int* p = value.get();
|
||||
assert(*p == i+1);
|
||||
(void)(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace boost
|
||||
unsigned int count,
|
||||
BOOST_THREAD_RV_REF(F) funct,
|
||||
typename enable_if<
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
typename is_void<typename result_of<F()>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
@@ -160,7 +160,7 @@ namespace boost
|
||||
unsigned int count,
|
||||
F &funct,
|
||||
typename enable_if<
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
typename is_void<typename result_of<F()>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
@@ -176,7 +176,7 @@ namespace boost
|
||||
unsigned int count,
|
||||
BOOST_THREAD_RV_REF(F) funct,
|
||||
typename enable_if<
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
typename is_same<typename result_of<F()>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
@@ -189,7 +189,7 @@ namespace boost
|
||||
unsigned int count,
|
||||
F& funct,
|
||||
typename enable_if<
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
typename is_same<typename result_of<F()>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
@@ -225,6 +225,7 @@ namespace boost
|
||||
m_generation++;
|
||||
m_count = static_cast<unsigned int>(fct_());
|
||||
BOOST_ASSERT(m_count != 0);
|
||||
lock.unlock();
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2013,2015 Vicente J. Botet Escriba
|
||||
// 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)
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
#endif
|
||||
#include <boost/current_function.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
@@ -43,9 +44,11 @@ namespace boost
|
||||
#endif
|
||||
{
|
||||
io::ios_flags_saver ifs(os);
|
||||
os << ctx.filename << "["
|
||||
os << std::setw(50) << ctx.filename << "["
|
||||
<< std::setw(4) << std::right << std::dec<< ctx.lineno << "] ";
|
||||
#if defined BOOST_THREAD_USES_LOG_CURRENT_FUNCTION
|
||||
os << ctx.func << " " ;
|
||||
#endif
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -96,7 +96,6 @@ namespace boost
|
||||
leavers_(0)
|
||||
{
|
||||
}
|
||||
template <typename F>
|
||||
completion_latch(std::size_t count, void(*funct)()) :
|
||||
count_(count), funct_(funct), waiters_(0), leavers_(0)
|
||||
{
|
||||
|
||||
209
include/boost/thread/concurrent_queues/deque_adaptor.hpp
Normal file
209
include/boost/thread/concurrent_queues/deque_adaptor.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_DEQUE_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_DEQUE_ADAPTOR_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/concurrent_queues/deque_base.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Queue>
|
||||
class deque_adaptor_copyable_only :
|
||||
public boost::deque_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
deque_adaptor_copyable_only() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
};
|
||||
template <typename Queue>
|
||||
class deque_adaptor_movable_only :
|
||||
public boost::deque_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
deque_adaptor_movable_only() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class deque_adaptor_copyable_and_movable :
|
||||
public boost::deque_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
deque_adaptor_copyable_and_movable() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
|
||||
template <class Q, class T,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__ && ! defined __clang__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // __GNUC__
|
||||
#elif defined _MSC_VER
|
||||
#if _MSC_VER < 1700
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif
|
||||
#else
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = has_move_emulation_enabled<T>::value
|
||||
#endif
|
||||
>
|
||||
struct deque_adaptor;
|
||||
|
||||
template <class Q, class T>
|
||||
struct deque_adaptor<Q, T, true, true> {
|
||||
typedef deque_adaptor_copyable_and_movable<Q> type;
|
||||
};
|
||||
template <class Q, class T>
|
||||
struct deque_adaptor<Q, T, true, false> {
|
||||
typedef deque_adaptor_copyable_only<Q> type;
|
||||
};
|
||||
template <class Q, class T>
|
||||
struct deque_adaptor<Q, T, false, true> {
|
||||
typedef deque_adaptor_movable_only<Q> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename Queue>
|
||||
class deque_adaptor :
|
||||
public detail::deque_adaptor<Queue, typename Queue::value_type>::type
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~deque_adaptor() {};
|
||||
};
|
||||
}
|
||||
using concurrent::deque_adaptor;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
202
include/boost/thread/concurrent_queues/deque_base.hpp
Normal file
202
include/boost/thread/concurrent_queues/deque_base.hpp
Normal file
@@ -0,0 +1,202 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_DEQUE_BASE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_DEQUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/is_copy_constructible.hpp>
|
||||
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename ValueType, class SizeType>
|
||||
class deque_base_copyable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef SizeType size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~deque_base_copyable_only() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(value_type& elem) = 0;
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType, class SizeType>
|
||||
class deque_base_movable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef SizeType size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~deque_base_movable_only() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_pull_front(value_type& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename ValueType, class SizeType>
|
||||
class deque_base_copyable_and_movable
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef SizeType size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~deque_base_copyable_and_movable() {};
|
||||
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(value_type& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
template <class T, class ST,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__ && ! defined __clang__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // __GNUC__
|
||||
#elif defined _MSC_VER
|
||||
#if _MSC_VER < 1700
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif
|
||||
#else
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = has_move_emulation_enabled<T>::value
|
||||
#endif
|
||||
>
|
||||
struct deque_base;
|
||||
|
||||
template <class T, class ST>
|
||||
struct deque_base<T, ST, true, true> {
|
||||
typedef deque_base_copyable_and_movable<T, ST> type;
|
||||
};
|
||||
template <class T, class ST>
|
||||
struct deque_base<T, ST, true, false> {
|
||||
typedef deque_base_copyable_only<T, ST> type;
|
||||
};
|
||||
template <class T, class ST>
|
||||
struct deque_base<T, ST, false, true> {
|
||||
typedef deque_base_movable_only<T, ST> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <class ValueType, class SizeType=std::size_t>
|
||||
class deque_base :
|
||||
public detail::deque_base<ValueType, SizeType>::type
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef SizeType size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~deque_base() {};
|
||||
};
|
||||
|
||||
}
|
||||
using concurrent::deque_base;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
165
include/boost/thread/concurrent_queues/deque_views.hpp
Normal file
165
include/boost/thread/concurrent_queues/deque_views.hpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_VIEWS_HPP
|
||||
#define BOOST_THREAD_QUEUE_VIEWS_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/concurrent_queues/deque_base.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
|
||||
template <typename Queue>
|
||||
class deque_back_view
|
||||
{
|
||||
Queue* queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
deque_back_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue->empty(); }
|
||||
bool full() const { return queue->full(); }
|
||||
size_type size() const { return queue->size(); }
|
||||
bool closed() const { return queue->closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_back(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_back(x); }
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_back(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); }
|
||||
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class deque_front_view
|
||||
{
|
||||
Queue* queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
deque_front_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue->empty(); }
|
||||
bool full() const { return queue->full(); }
|
||||
size_type size() const { return queue->size(); }
|
||||
bool closed() const { return queue->closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_front(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_front(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_front(forward<value_type>(x)); }
|
||||
|
||||
};
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_TEMPLATE_ALIASES
|
||||
|
||||
template <class T>
|
||||
using deque_back = deque_back_view<deque_base<T> > ;
|
||||
template <class T>
|
||||
using deque_front = deque_front_view<deque_base<T> > ;
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
struct deque_back : deque_back_view<deque_base<T> >
|
||||
{
|
||||
typedef deque_back_view<deque_base<T> > base_type;
|
||||
deque_back(deque_base<T>& q) BOOST_NOEXCEPT : base_type(q) {}
|
||||
};
|
||||
template <class T>
|
||||
struct deque_front : deque_front_view<deque_base<T> >
|
||||
{
|
||||
typedef deque_front_view<deque_base<T> > base_type;
|
||||
deque_front(deque_base<T>& q) BOOST_NOEXCEPT : base_type(q) {}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// template <class Queue>
|
||||
// deque_back_view<Queue> back(Queue & q) { return deque_back_view<Queue>(q); }
|
||||
// template <class Queue>
|
||||
// deque_front_view<Queue> front(Queue & q) { return deque_front_view<Queue>(q); }
|
||||
//#if 0
|
||||
// template <class T>
|
||||
// deque_back<T> back(deque_base<T> & q) { return deque_back<T>(q); }
|
||||
// template <class T>
|
||||
// deque_front<T> front(deque_base<T> & q) { return deque_front<T>(q); }
|
||||
//#else
|
||||
// template <class T>
|
||||
// typename deque_back<T>::type back(deque_base<T> & q) { return typename deque_back<T>::type(q); }
|
||||
// template <class T>
|
||||
// typename deque_front<T>::type front(deque_base<T> & q) { return typename deque_front<T>::type(q); }
|
||||
//#endif
|
||||
}
|
||||
|
||||
using concurrent::deque_back_view;
|
||||
using concurrent::deque_front_view;
|
||||
using concurrent::deque_back;
|
||||
using concurrent::deque_front;
|
||||
//using concurrent::back;
|
||||
//using concurrent::front;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,223 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_DEQUE_BASE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_DEQUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
class sync_deque_base
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef Queue underlying_queue_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
typedef queue_op_status op_status;
|
||||
|
||||
typedef typename chrono::steady_clock clock;
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_deque_base)
|
||||
inline sync_deque_base();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_deque(Range range);
|
||||
inline ~sync_deque_base();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
inline underlying_queue_type underlying_queue() {
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return boost::move(data_);
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
underlying_queue_type data_;
|
||||
bool closed_;
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
inline bool closed(unique_lock<mutex>& lk) const;
|
||||
inline bool closed(lock_guard<mutex>& lk) const;
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline void throw_if_closed(lock_guard<mutex>&);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&);
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
inline void notify_not_empty_if_needed(lock_guard<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_deque_base<ValueType, Queue>::sync_deque_base() :
|
||||
data_(), closed_(false)
|
||||
{
|
||||
BOOST_ASSERT(data_.empty());
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_deque_base<ValueType, Queue>::~sync_deque_base()
|
||||
{
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_deque_base<ValueType, Queue>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::closed(unique_lock<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::closed(lock_guard<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::full() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
typename sync_deque_base<ValueType, Queue>::size_type sync_deque_base<ValueType, Queue>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_deque_base<ValueType, Queue>::throw_if_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_deque_is_closed() );
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
void sync_deque_base<ValueType, Queue>::throw_if_closed(lock_guard<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_deque_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_deque_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
throw_if_closed(lk);
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
if (closed(lk)) return true;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&tp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) return queue_op_status::success;
|
||||
throw_if_closed(lk);
|
||||
if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // detail
|
||||
} // concurrent
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,223 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
class sync_queue_base
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef Queue underlying_queue_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
typedef queue_op_status op_status;
|
||||
|
||||
typedef typename chrono::steady_clock clock;
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue_base)
|
||||
inline sync_queue_base();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue_base();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
inline underlying_queue_type underlying_queue() {
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return boost::move(data_);
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
underlying_queue_type data_;
|
||||
bool closed_;
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
inline bool closed(unique_lock<mutex>& lk) const;
|
||||
inline bool closed(lock_guard<mutex>& lk) const;
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline void throw_if_closed(lock_guard<mutex>&);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&);
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
inline void notify_not_empty_if_needed(lock_guard<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_queue_base<ValueType, Queue>::sync_queue_base() :
|
||||
data_(), closed_(false)
|
||||
{
|
||||
BOOST_ASSERT(data_.empty());
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_queue_base<ValueType, Queue>::~sync_queue_base()
|
||||
{
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed(unique_lock<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed(lock_guard<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::full() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
typename sync_queue_base<ValueType, Queue>::size_type sync_queue_base<ValueType, Queue>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::throw_if_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::throw_if_closed(lock_guard<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
throw_if_closed(lk);
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
if (closed(lk)) return true;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&tp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) return queue_op_status::success;
|
||||
throw_if_closed(lk);
|
||||
if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // detail
|
||||
} // concurrent
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -27,12 +27,12 @@ namespace detail
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor_copyable_only :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
public boost::queue_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_adaptor_copyable_only() {}
|
||||
@@ -46,29 +46,29 @@ namespace detail
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
void push(const value_type& x) { queue.push(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
void pull(value_type& x) { queue.pull(x); };
|
||||
value_type pull() { return queue.pull(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
queue_op_status try_push(const value_type& x) { return queue.try_push(x); }
|
||||
queue_op_status try_pull(value_type& x) { return queue.try_pull(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue.nonblocking_push(x); }
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue.nonblocking_pull(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
queue_op_status wait_push(const value_type& x) { return queue.wait_push(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue.wait_pull(x); }
|
||||
|
||||
};
|
||||
template <typename Queue>
|
||||
class queue_adaptor_movable_only :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
public boost::queue_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
@@ -84,30 +84,30 @@ namespace detail
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
void pull(value_type& x) { queue.pull(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
value_type pull() { return queue.pull(); }
|
||||
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
queue_op_status try_pull(value_type& x) { return queue.try_pull(x); }
|
||||
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue.nonblocking_pull(x); }
|
||||
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue.wait_pull(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue.push(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor_copyable_and_movable :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
public boost::queue_base<typename Queue::value_type, typename Queue::size_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
@@ -123,31 +123,31 @@ namespace detail
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
void push(const value_type& x) { queue.push(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
void pull(value_type& x) { queue.pull(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
value_type pull() { return queue.pull(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
queue_op_status try_push(const value_type& x) { return queue.try_push(x); }
|
||||
queue_op_status try_pull(value_type& x) { return queue.try_pull(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue.nonblocking_push(x); }
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue.nonblocking_pull(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
queue_op_status wait_push(const value_type& x) { return queue.wait_push(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue.wait_pull(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue.push(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push(boost::move(x)); }
|
||||
};
|
||||
|
||||
|
||||
template <class Q, class T,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__
|
||||
#if defined __GNUC__ && ! defined __clang__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
@@ -195,7 +195,7 @@ namespace detail
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_adaptor() {};
|
||||
};
|
||||
|
||||
@@ -27,12 +27,12 @@ namespace concurrent
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename ValueType>
|
||||
template <typename ValueType, class SizeType>
|
||||
class queue_base_copyable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef SizeType size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_copyable_only() {};
|
||||
@@ -46,28 +46,28 @@ namespace detail
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
virtual void push(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual value_type pull_front() = 0;
|
||||
virtual void pull(value_type&) = 0;
|
||||
virtual value_type pull() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
virtual queue_op_status try_push(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
virtual queue_op_status nonblocking_push(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
virtual queue_op_status wait_push(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull(ValueType& elem) = 0;
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
template <typename ValueType, class SizeType>
|
||||
class queue_base_movable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef SizeType size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_movable_only() {};
|
||||
|
||||
@@ -80,29 +80,29 @@ namespace detail
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual void pull(value_type&) = 0;
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
virtual value_type pull() = 0;
|
||||
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
virtual queue_op_status try_pull(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
virtual queue_op_status nonblocking_pull(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
virtual queue_op_status wait_pull(value_type& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual void push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
template <typename ValueType, class SizeType>
|
||||
class queue_base_copyable_and_movable
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef SizeType size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_copyable_and_movable() {};
|
||||
|
||||
@@ -116,30 +116,30 @@ namespace detail
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
virtual void push(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual void pull(value_type&) = 0;
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
virtual value_type pull() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
virtual queue_op_status try_push(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
virtual queue_op_status nonblocking_push(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
virtual queue_op_status wait_push(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull(value_type& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual void push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
template <class T,
|
||||
template <class T, class ST,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__
|
||||
#if defined __GNUC__ && ! defined __clang__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
@@ -166,28 +166,28 @@ namespace detail
|
||||
>
|
||||
struct queue_base;
|
||||
|
||||
template <class T>
|
||||
struct queue_base<T, true, true> {
|
||||
typedef queue_base_copyable_and_movable<T> type;
|
||||
template <class T, class ST>
|
||||
struct queue_base<T, ST, true, true> {
|
||||
typedef queue_base_copyable_and_movable<T, ST> type;
|
||||
};
|
||||
template <class T>
|
||||
struct queue_base<T, true, false> {
|
||||
typedef queue_base_copyable_only<T> type;
|
||||
template <class T, class ST>
|
||||
struct queue_base<T, ST, true, false> {
|
||||
typedef queue_base_copyable_only<T, ST> type;
|
||||
};
|
||||
template <class T>
|
||||
struct queue_base<T, false, true> {
|
||||
typedef queue_base_movable_only<T> type;
|
||||
template <class T, class ST>
|
||||
struct queue_base<T, ST, false, true> {
|
||||
typedef queue_base_movable_only<T, ST> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
template <typename ValueType, class SizeType=std::size_t>
|
||||
class queue_base :
|
||||
public detail::queue_base<ValueType>::type
|
||||
public detail::queue_base<ValueType, SizeType>::type
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef SizeType size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base() {};
|
||||
};
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace concurrent
|
||||
{
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
|
||||
{ success = 0, empty, full, closed, busy }
|
||||
{ success = 0, empty, full, closed, busy, timeout, not_ready }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
struct sync_queue_is_closed : std::exception
|
||||
|
||||
@@ -43,27 +43,17 @@ namespace concurrent
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_back(x); }
|
||||
void push(const value_type& x) { queue->push(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_back(x); }
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_back(); }
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push(x); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); }
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push(x); }
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); }
|
||||
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
@@ -86,26 +76,15 @@ namespace concurrent
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_front(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_front(x); };
|
||||
void pull(value_type& x) { queue->pull(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_front(); }
|
||||
value_type pull() { return queue->pull(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); }
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); }
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_front(forward<value_type>(x)); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull(x); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
725
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
725
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
@@ -0,0 +1,725 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_bounded_queue)
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type capacity() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
condition_variable not_full_;
|
||||
size_type waiting_full_;
|
||||
size_type waiting_empty_;
|
||||
value_type* data_;
|
||||
size_type in_;
|
||||
size_type out_;
|
||||
size_type capacity_;
|
||||
bool closed_;
|
||||
|
||||
inline size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (idx + 1) % capacity_;
|
||||
}
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity_-1;
|
||||
}
|
||||
inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT
|
||||
{
|
||||
if (full(lk)) return capacity(lk);
|
||||
return ((out_+capacity(lk)-in_) % capacity(lk));
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>&) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
inline void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_full_ > 0)
|
||||
{
|
||||
--waiting_full_;
|
||||
lk.unlock();
|
||||
not_full_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
|
||||
inline void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
in_ = in;
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = elem;
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = boost::move(elem);
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) :
|
||||
waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
closed_(false)
|
||||
{
|
||||
BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) :
|
||||
// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
// closed_(false)
|
||||
// {
|
||||
// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size");
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// size_type in = 0;
|
||||
// for (iterator_t cur = first; cur != end; ++cur, ++in)
|
||||
// {
|
||||
// data_[in] = *cur;
|
||||
// }
|
||||
// set_in(in);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::~sync_bounded_queue()
|
||||
{
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
not_full_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::full() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return full(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return capacity(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
// template <typename ValueType>
|
||||
// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
// {
|
||||
// unique_lock<mutex> lk(mtx_);
|
||||
// wait_until_not_empty(lk, closed);
|
||||
// if (closed) {return;}
|
||||
// pull(elem, lk);
|
||||
// }
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 != out_) // ! full()
|
||||
{
|
||||
return in_p_1;
|
||||
}
|
||||
++waiting_full_;
|
||||
not_full_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
}
|
||||
using concurrent::sync_bounded_queue;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
327
include/boost/thread/concurrent_queues/sync_deque.hpp
Normal file
327
include/boost/thread/concurrent_queues/sync_deque.hpp
Normal file
@@ -0,0 +1,327 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_DEQUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_DEQUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/devector.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <class ValueType, class Container = csbl::devector<ValueType> >
|
||||
class sync_deque
|
||||
: public detail::sync_queue_base<ValueType, Container >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, Container > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_deque)
|
||||
inline sync_deque();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_deque(Range range);
|
||||
inline ~sync_deque();
|
||||
|
||||
// Modifiers
|
||||
inline void push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
|
||||
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_deque<ValueType, Container>::sync_deque() :
|
||||
super()
|
||||
{
|
||||
}
|
||||
|
||||
// template <class ValueType, class Container>
|
||||
// template <class Range>
|
||||
// explicit sync_deque<ValueType, Container>::sync_deque(Range range) :
|
||||
// data_(), closed_(false)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// for (iterator_t cur = first; cur != end; ++cur)
|
||||
// {
|
||||
// data_.push(boost::move(*cur));;
|
||||
// }
|
||||
// notify_not_empty_if_needed(lk);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_deque<ValueType, Container>::~sync_deque()
|
||||
{
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
void sync_deque<ValueType, Container>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <class ValueType, class Container>
|
||||
ValueType sync_deque<ValueType, Container>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
void sync_deque<ValueType, Container>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_deque<ValueType, Container>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
void sync_deque<ValueType, Container>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_deque<ValueType, Container>& operator<<(sync_deque<ValueType, Container>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_deque<ValueType, Container>& operator<<(sync_deque<ValueType, Container>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_deque<ValueType, Container>& operator>>(sync_deque<ValueType, Container>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
using concurrent::sync_deque;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
369
include/boost/thread/concurrent_queues/sync_priority_queue.hpp
Normal file
369
include/boost/thread/concurrent_queues/sync_priority_queue.hpp
Normal file
@@ -0,0 +1,369 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_SYNC_PRIORITY_QUEUE
|
||||
#define BOOST_THREAD_SYNC_PRIORITY_QUEUE
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
template <
|
||||
class Type,
|
||||
class Container = csbl::vector<Type>,
|
||||
class Compare = std::less<Type>
|
||||
>
|
||||
class priority_queue
|
||||
{
|
||||
private:
|
||||
Container _elements;
|
||||
Compare _compare;
|
||||
public:
|
||||
typedef Type value_type;
|
||||
typedef typename Container::size_type size_type;
|
||||
|
||||
explicit priority_queue(const Compare& compare = Compare())
|
||||
: _elements(), _compare(compare)
|
||||
{ }
|
||||
|
||||
size_type size() const
|
||||
{
|
||||
return _elements.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return _elements.empty();
|
||||
}
|
||||
|
||||
void push(Type const& element)
|
||||
{
|
||||
_elements.push_back(element);
|
||||
std::push_heap(_elements.begin(), _elements.end(), _compare);
|
||||
}
|
||||
void push(BOOST_RV_REF(Type) element)
|
||||
{
|
||||
_elements.push_back(boost::move(element));
|
||||
std::push_heap(_elements.begin(), _elements.end(), _compare);
|
||||
}
|
||||
|
||||
void pop()
|
||||
{
|
||||
std::pop_heap(_elements.begin(), _elements.end(), _compare);
|
||||
_elements.pop_back();
|
||||
}
|
||||
Type pull()
|
||||
{
|
||||
Type result = boost::move(_elements.front());
|
||||
pop();
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
Type const& top()
|
||||
{
|
||||
return _elements.front();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace concurrent
|
||||
{
|
||||
template <class ValueType,
|
||||
class Container = csbl::vector<ValueType>,
|
||||
class Compare = std::less<typename Container::value_type> >
|
||||
class sync_priority_queue
|
||||
: public detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
typedef chrono::steady_clock clock;
|
||||
protected:
|
||||
|
||||
public:
|
||||
sync_priority_queue() {}
|
||||
|
||||
~sync_priority_queue()
|
||||
{
|
||||
if(!super::closed())
|
||||
{
|
||||
super::close();
|
||||
}
|
||||
}
|
||||
|
||||
void push(const ValueType& elem);
|
||||
void push(BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
queue_op_status try_push(const ValueType& elem);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
ValueType pull();
|
||||
|
||||
void pull(ValueType&);
|
||||
|
||||
queue_op_status pull_until(const clock::time_point&, ValueType&);
|
||||
queue_op_status pull_for(const clock::duration&, ValueType&);
|
||||
|
||||
queue_op_status try_pull(ValueType& elem);
|
||||
queue_op_status wait_pull(ValueType& elem);
|
||||
queue_op_status nonblocking_pull(ValueType&);
|
||||
|
||||
private:
|
||||
void push(unique_lock<mutex>&, const ValueType& elem);
|
||||
void push(lock_guard<mutex>&, const ValueType& elem);
|
||||
void push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
void push(lock_guard<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
queue_op_status try_push(unique_lock<mutex>&, const ValueType& elem);
|
||||
queue_op_status try_push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
ValueType pull(unique_lock<mutex>&);
|
||||
ValueType pull(lock_guard<mutex>&);
|
||||
|
||||
void pull(unique_lock<mutex>&, ValueType&);
|
||||
void pull(lock_guard<mutex>&, ValueType&);
|
||||
|
||||
queue_op_status try_pull(lock_guard<mutex>& lk, ValueType& elem);
|
||||
queue_op_status try_pull(unique_lock<mutex>& lk, ValueType& elem);
|
||||
|
||||
queue_op_status wait_pull(unique_lock<mutex>& lk, ValueType& elem);
|
||||
|
||||
queue_op_status nonblocking_pull(unique_lock<mutex>& lk, ValueType&);
|
||||
|
||||
sync_priority_queue(const sync_priority_queue&);
|
||||
sync_priority_queue& operator= (const sync_priority_queue&);
|
||||
sync_priority_queue(BOOST_THREAD_RV_REF(sync_priority_queue));
|
||||
sync_priority_queue& operator= (BOOST_THREAD_RV_REF(sync_priority_queue));
|
||||
}; //end class
|
||||
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, const T& elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, const T& elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(const T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
push(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
push(lk, boost::move(elem));
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(const T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(lk, boost::move(elem));
|
||||
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&)
|
||||
{
|
||||
return super::data_.pull();
|
||||
}
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&)
|
||||
{
|
||||
return super::data_.pull();
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&, T& elem)
|
||||
{
|
||||
elem = super::data_.pull();
|
||||
}
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&, T& elem)
|
||||
{
|
||||
elem = super::data_.pull();
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_until(const clock::time_point& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
|
||||
return queue_op_status::timeout;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_for(const clock::duration& dura, T& elem)
|
||||
{
|
||||
return pull_until(clock::now() + dura, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::nonblocking_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} //end concurrent namespace
|
||||
|
||||
using concurrent::sync_priority_queue;
|
||||
|
||||
} //end boost namespace
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
335
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
335
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
@@ -0,0 +1,335 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/devector.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <class ValueType, class Container = csbl::devector<ValueType> >
|
||||
class sync_queue
|
||||
: public detail::sync_queue_base<ValueType, Container >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, Container > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue)
|
||||
inline sync_queue();
|
||||
//template <class Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue();
|
||||
|
||||
// Modifiers
|
||||
|
||||
inline void push(const value_type& x);
|
||||
inline queue_op_status try_push(const value_type& x);
|
||||
inline queue_op_status nonblocking_push(const value_type& x);
|
||||
inline queue_op_status wait_push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
inline void pull(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
|
||||
inline queue_op_status try_pull(value_type&);
|
||||
inline queue_op_status nonblocking_pull(value_type&);
|
||||
inline queue_op_status wait_pull(ValueType& elem);
|
||||
|
||||
private:
|
||||
|
||||
inline queue_op_status try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
|
||||
inline void push(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_queue<ValueType, Container>::sync_queue() :
|
||||
super()
|
||||
{
|
||||
}
|
||||
|
||||
// template <class ValueType, class Container>
|
||||
// template <class Range>
|
||||
// explicit sync_queue<ValueType, Container>::sync_queue(Range range) :
|
||||
// data_(), closed_(false)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// for (iterator_t cur = first; cur != end; ++cur)
|
||||
// {
|
||||
// data_.push(boost::move(*cur));;
|
||||
// }
|
||||
// notify_not_empty_if_needed(lk);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_queue<ValueType, Container>::~sync_queue()
|
||||
{
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::wait_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
if (super::empty(lk))
|
||||
{
|
||||
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
pull(elem, lk);
|
||||
//std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::wait_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::nonblocking_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
void sync_queue<ValueType, Container>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <class ValueType, class Container>
|
||||
ValueType sync_queue<ValueType, Container>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::wait_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::wait_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::nonblocking_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
void sync_queue<ValueType, Container>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::wait_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::wait_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
queue_op_status sync_queue<ValueType, Container>::nonblocking_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
void sync_queue<ValueType, Container>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_queue<ValueType, Container>& operator<<(sync_queue<ValueType, Container>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_queue<ValueType, Container>& operator<<(sync_queue<ValueType, Container>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <class ValueType, class Container>
|
||||
sync_queue<ValueType, Container>& operator>>(sync_queue<ValueType, Container>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
using concurrent::sync_queue;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
468
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
468
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
@@ -0,0 +1,468 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_SYNC_TIMED_QUEUE_HPP
|
||||
#define BOOST_THREAD_SYNC_TIMED_QUEUE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/concurrent_queues/sync_priority_queue.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class T, class Clock = chrono::steady_clock>
|
||||
struct scheduled_type
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef Clock clock;
|
||||
typedef typename clock::time_point time_point;
|
||||
T data;
|
||||
time_point time;
|
||||
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(scheduled_type)
|
||||
|
||||
scheduled_type(T const& pdata, time_point tp) : data(pdata), time(tp) {}
|
||||
scheduled_type(BOOST_THREAD_RV_REF(T) pdata, time_point tp) : data(boost::move(pdata)), time(tp) {}
|
||||
|
||||
scheduled_type(scheduled_type const& other) : data(other.data), time(other.time) {}
|
||||
scheduled_type& operator=(BOOST_THREAD_COPY_ASSIGN_REF(scheduled_type) other) {
|
||||
data = other.data;
|
||||
time = other.time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scheduled_type(BOOST_THREAD_RV_REF(scheduled_type) other) : data(boost::move(other.data)), time(other.time) {}
|
||||
scheduled_type& operator=(BOOST_THREAD_RV_REF(scheduled_type) other) {
|
||||
data = boost::move(other.data);
|
||||
time = other.time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool time_not_reached() const
|
||||
{
|
||||
return time > clock::now();
|
||||
}
|
||||
|
||||
bool operator <(const scheduled_type<T> other) const
|
||||
{
|
||||
return this->time > other.time;
|
||||
}
|
||||
}; //end struct
|
||||
|
||||
} //end detail namespace
|
||||
|
||||
template <class T, class Clock = chrono::steady_clock>
|
||||
class sync_timed_queue
|
||||
: private sync_priority_queue<detail::scheduled_type<T, Clock> >
|
||||
{
|
||||
typedef detail::scheduled_type<T, Clock> stype;
|
||||
typedef sync_priority_queue<stype> super;
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef Clock clock;
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
sync_timed_queue() : super() {};
|
||||
~sync_timed_queue() {}
|
||||
|
||||
using super::size;
|
||||
using super::empty;
|
||||
using super::full;
|
||||
using super::close;
|
||||
using super::closed;
|
||||
|
||||
T pull();
|
||||
void pull(T& elem);
|
||||
|
||||
template <class Duration>
|
||||
queue_op_status pull_until(chrono::time_point<clock,Duration> const& tp, T& elem);
|
||||
template <class Rep, class Period>
|
||||
queue_op_status pull_for(chrono::duration<Rep,Period> const& dura, T& elem);
|
||||
|
||||
queue_op_status try_pull(T& elem);
|
||||
queue_op_status wait_pull(T& elem);
|
||||
queue_op_status nonblocking_pull(T& elem);
|
||||
|
||||
template <class Duration>
|
||||
void push(const T& elem, chrono::time_point<clock,Duration> const& tp);
|
||||
template <class Rep, class Period>
|
||||
void push(const T& elem, chrono::duration<Rep,Period> const& dura);
|
||||
|
||||
template <class Duration>
|
||||
void push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp);
|
||||
template <class Rep, class Period>
|
||||
void push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura);
|
||||
|
||||
template <class Duration>
|
||||
queue_op_status try_push(const T& elem, chrono::time_point<clock,Duration> const& tp);
|
||||
template <class Rep, class Period>
|
||||
queue_op_status try_push(const T& elem, chrono::duration<Rep,Period> const& dura);
|
||||
|
||||
template <class Duration>
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp);
|
||||
template <class Rep, class Period>
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura);
|
||||
|
||||
private:
|
||||
T pull(unique_lock<mutex>&);
|
||||
T pull(lock_guard<mutex>&);
|
||||
|
||||
void pull(unique_lock<mutex>&, T& elem);
|
||||
void pull(lock_guard<mutex>&, T& elem);
|
||||
|
||||
queue_op_status try_pull(unique_lock<mutex>&, T& elem);
|
||||
queue_op_status try_pull(lock_guard<mutex>&, T& elem);
|
||||
|
||||
queue_op_status wait_pull(unique_lock<mutex>& lk, T& elem);
|
||||
|
||||
bool wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>&);
|
||||
T pull_when_time_reached(unique_lock<mutex>&);
|
||||
template <class Duration>
|
||||
queue_op_status pull_when_time_reached_until(unique_lock<mutex>&, chrono::time_point<clock,Duration> const& tp, T& elem);
|
||||
bool time_not_reached(unique_lock<mutex>&);
|
||||
bool time_not_reached(lock_guard<mutex>&);
|
||||
bool empty_or_time_not_reached(unique_lock<mutex>&);
|
||||
bool empty_or_time_not_reached(lock_guard<mutex>&);
|
||||
|
||||
sync_timed_queue(const sync_timed_queue&);
|
||||
sync_timed_queue& operator=(const sync_timed_queue&);
|
||||
sync_timed_queue(BOOST_THREAD_RV_REF(sync_timed_queue));
|
||||
sync_timed_queue& operator=(BOOST_THREAD_RV_REF(sync_timed_queue));
|
||||
}; //end class
|
||||
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Duration>
|
||||
void sync_timed_queue<T, Clock>::push(const T& elem, chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
super::push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Rep, class Period>
|
||||
void sync_timed_queue<T, Clock>::push(const T& elem, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
push(elem, clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Duration>
|
||||
void sync_timed_queue<T, Clock>::push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
super::push(stype(boost::move(elem),tp));
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Rep, class Period>
|
||||
void sync_timed_queue<T, Clock>::push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
push(boost::move(elem), clock::now() + dura);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Duration>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_push(const T& elem, chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
return super::try_push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_push(const T& elem, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
return try_push(elem,clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Duration>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_push(BOOST_THREAD_RV_REF(T) elem, chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
return super::try_push(stype(boost::move(elem), tp));
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_push(BOOST_THREAD_RV_REF(T) elem, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
return try_push(boost::move(elem), clock::now() + dura);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
bool sync_timed_queue<T, Clock>::time_not_reached(unique_lock<mutex>&)
|
||||
{
|
||||
return super::data_.top().time_not_reached();
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
bool sync_timed_queue<T, Clock>::time_not_reached(lock_guard<mutex>&)
|
||||
{
|
||||
return super::data_.top().time_not_reached();
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
bool sync_timed_queue<T, Clock>::wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (super::closed(lk)) return true;
|
||||
while (! super::empty(lk)) {
|
||||
if (! time_not_reached(lk)) return false;
|
||||
time_point tp = super::data_.top().time;
|
||||
super::not_empty_.wait_until(lk, tp);
|
||||
if (super::closed(lk)) return true;
|
||||
}
|
||||
if (super::closed(lk)) return true;
|
||||
super::not_empty_.wait(lk);
|
||||
}
|
||||
//return false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
T sync_timed_queue<T, Clock>::pull_when_time_reached(unique_lock<mutex>& lk)
|
||||
{
|
||||
while (time_not_reached(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
time_point tp = super::data_.top().time;
|
||||
super::not_empty_.wait_until(lk,tp);
|
||||
super::wait_until_not_empty(lk);
|
||||
}
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
template <class Duration>
|
||||
queue_op_status
|
||||
sync_timed_queue<T, Clock>::pull_when_time_reached_until(unique_lock<mutex>& lk, chrono::time_point<clock,Duration> const& tp, T& elem)
|
||||
{
|
||||
chrono::time_point<clock,Duration> tpmin = (tp < super::data_.top().time) ? tp : super::data_.top().time;
|
||||
while (time_not_reached(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
if (cv_status::timeout == super::not_empty_.wait_until(lk, tpmin)) {
|
||||
if (time_not_reached(lk)) return queue_op_status::not_ready;
|
||||
return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
bool sync_timed_queue<T, Clock>::empty_or_time_not_reached(unique_lock<mutex>& lk)
|
||||
{
|
||||
if ( super::empty(lk) ) return true;
|
||||
if ( time_not_reached(lk) ) return true;
|
||||
return false;
|
||||
}
|
||||
template <class T, class Clock>
|
||||
bool sync_timed_queue<T, Clock>::empty_or_time_not_reached(lock_guard<mutex>& lk)
|
||||
{
|
||||
if ( super::empty(lk) ) return true;
|
||||
if ( time_not_reached(lk) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
T sync_timed_queue<T, Clock>::pull(unique_lock<mutex>&)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
return boost::move(super::data_.pull().data);
|
||||
#else
|
||||
return super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
T sync_timed_queue<T, Clock>::pull(lock_guard<mutex>&)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
return boost::move(super::data_.pull().data);
|
||||
#else
|
||||
return super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
template <class T, class Clock>
|
||||
T sync_timed_queue<T, Clock>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull_when_time_reached(lk);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
void sync_timed_queue<T, Clock>::pull(unique_lock<mutex>&, T& elem)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
elem = boost::move(super::data_.pull().data);
|
||||
#else
|
||||
elem = super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
void sync_timed_queue<T, Clock>::pull(lock_guard<mutex>&, T& elem)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
elem = boost::move(super::data_.pull().data);
|
||||
#else
|
||||
elem = super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
void sync_timed_queue<T, Clock>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
elem = pull_when_time_reached(lk);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Clock>
|
||||
template <class Duration>
|
||||
queue_op_status
|
||||
sync_timed_queue<T, Clock>::pull_until(chrono::time_point<clock,Duration> const& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
|
||||
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
|
||||
return queue_op_status::timeout;
|
||||
return pull_when_time_reached_until(lk, tp, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Clock>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status
|
||||
sync_timed_queue<T, Clock>::pull_for(chrono::duration<Rep,Period> const& dura, T& elem)
|
||||
{
|
||||
return pull_until(clock::now() + dura, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if ( super::empty(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
if ( time_not_reached(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <class T, class Clock>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if ( super::empty(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
if ( time_not_reached(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
queue_op_status sync_timed_queue<T, Clock>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
queue_op_status sync_timed_queue<T, Clock>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = wait_until_not_empty_time_reached_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Clock>
|
||||
queue_op_status sync_timed_queue<T, Clock>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
// ///////////////////////////
|
||||
// template <class T, class Clock>
|
||||
// queue_op_status sync_timed_queue<T, Clock>::wait_pull(unique_lock<mutex> &lk, T& elem)
|
||||
// {
|
||||
// if (super::empty(lk))
|
||||
// {
|
||||
// if (super::closed(lk)) return queue_op_status::closed;
|
||||
// }
|
||||
// bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
// if (has_been_closed) return queue_op_status::closed;
|
||||
// pull(lk, elem);
|
||||
// return queue_op_status::success;
|
||||
// }
|
||||
// template <class T>
|
||||
// queue_op_status sync_timed_queue<T, Clock>::wait_pull(T& elem)
|
||||
// {
|
||||
// unique_lock<mutex> lk(super::mtx_);
|
||||
// return wait_pull(lk, elem);
|
||||
// }
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock>
|
||||
queue_op_status sync_timed_queue<T, Clock>::nonblocking_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (! lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
} //end concurrent namespace
|
||||
|
||||
using concurrent::sync_timed_queue;
|
||||
|
||||
} //end boost namespace
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -19,7 +19,7 @@
|
||||
// [
|
||||
// _Ty=non_copyable
|
||||
// ]
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827)
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827)
|
||||
#ifndef BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#define BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#endif
|
||||
|
||||
102
include/boost/thread/csbl/devector.hpp
Normal file
102
include/boost/thread/csbl/devector.hpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_DEVECTOR_HPP
|
||||
#define BOOST_CSBL_DEVECTOR_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/move/detail/move_helpers.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
template <class T>
|
||||
class devector
|
||||
{
|
||||
typedef csbl::vector<T> vector_type;
|
||||
vector_type data_;
|
||||
std::size_t front_index_;
|
||||
|
||||
BOOST_COPYABLE_AND_MOVABLE(devector)
|
||||
|
||||
template <class U>
|
||||
void priv_push_back(BOOST_FWD_REF(U) x)
|
||||
{ data_.push_back(boost::forward<U>(x)); }
|
||||
|
||||
public:
|
||||
typedef typename vector_type::size_type size_type;
|
||||
typedef typename vector_type::reference reference;
|
||||
typedef typename vector_type::const_reference const_reference;
|
||||
|
||||
|
||||
devector() : front_index_(0) {}
|
||||
devector(devector const& x) BOOST_NOEXCEPT
|
||||
: data_(x.data_),
|
||||
front_index_(x.front_index_)
|
||||
{}
|
||||
devector(BOOST_RV_REF(devector) x) BOOST_NOEXCEPT
|
||||
: data_(boost::move(x.data_)),
|
||||
front_index_(x.front_index_)
|
||||
{}
|
||||
|
||||
devector& operator=(BOOST_COPY_ASSIGN_REF(devector) x)
|
||||
{
|
||||
if (&x != this)
|
||||
{
|
||||
data_ = x.data_;
|
||||
front_index_ = x.front_index_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
devector& operator=(BOOST_RV_REF(devector) x)
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR
|
||||
BOOST_NOEXCEPT_IF(vector_type::allocator_traits_type::propagate_on_container_move_assignment::value)
|
||||
#endif
|
||||
{
|
||||
data_ = boost::move(x.data_);
|
||||
front_index_ = x.front_index_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT
|
||||
{ return data_.size() == front_index_; }
|
||||
|
||||
size_type size() const BOOST_NOEXCEPT
|
||||
{ return data_.size() - front_index_; }
|
||||
|
||||
reference front() BOOST_NOEXCEPT
|
||||
{ return data_[front_index_]; }
|
||||
|
||||
const_reference front() const BOOST_NOEXCEPT
|
||||
{ return data_[front_index_]; }
|
||||
|
||||
reference back() BOOST_NOEXCEPT
|
||||
{ return data_.back(); }
|
||||
|
||||
const_reference back() const BOOST_NOEXCEPT
|
||||
{ return data_.back(); }
|
||||
|
||||
BOOST_MOVE_CONVERSION_AWARE_CATCH(push_back, T, void, priv_push_back)
|
||||
|
||||
void pop_front()
|
||||
{
|
||||
++front_index_;
|
||||
if (empty()) {
|
||||
data_.clear();
|
||||
front_index_=0;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_LIST
|
||||
#define BOOST_THREAD_USES_BOOST_LIST
|
||||
#endif
|
||||
|
||||
45
include/boost/thread/csbl/queue.hpp
Normal file
45
include/boost/thread/csbl/queue.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2015 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_QUEUE_HPP
|
||||
#define BOOST_CSBL_QUEUE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
// MSVC has some trouble instantiating a non_copyable type
|
||||
//C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(606) : error C2248: 'non_copyable::non_copyable' : cannot access private member declared in class 'non_copyable'
|
||||
// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(24) : see declaration of 'non_copyable::non_copyable'
|
||||
// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(23) : see declaration of 'non_copyable'
|
||||
// C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
|
||||
// with
|
||||
// [
|
||||
// _Ty=non_copyable
|
||||
// ]
|
||||
#if defined BOOST_THREAD_USES_BOOST_QUEUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827)
|
||||
#ifndef BOOST_THREAD_USES_BOOST_QUEUE
|
||||
#define BOOST_THREAD_USES_BOOST_QUEUE
|
||||
#endif
|
||||
#include <boost/container/queue.hpp>
|
||||
#else
|
||||
#include <queue>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_QUEUE
|
||||
using ::boost::container::queue;
|
||||
|
||||
#else
|
||||
using ::std::queue;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
|
||||
#ifndef BOOST_THREAD_USES_BOOST_VECTOR
|
||||
#define BOOST_THREAD_USES_BOOST_VECTOR
|
||||
#endif
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
//#define BOOST_THREAD_USEFIXES_TIMESPEC
|
||||
//#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
|
||||
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
// ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
@@ -100,8 +102,8 @@
|
||||
#if !defined BOOST_THREAD_VERSION
|
||||
#define BOOST_THREAD_VERSION 2
|
||||
#else
|
||||
#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 && BOOST_THREAD_VERSION!=4
|
||||
#error "BOOST_THREAD_VERSION must be 2, 3 or 4"
|
||||
#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 && BOOST_THREAD_VERSION!=4 && BOOST_THREAD_VERSION!=5
|
||||
#error "BOOST_THREAD_VERSION must be 2, 3, 4 or 5"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -304,6 +306,13 @@
|
||||
|
||||
#endif // BOOST_THREAD_VERSION>=4
|
||||
|
||||
|
||||
#if BOOST_THREAD_VERSION>=5
|
||||
//#define BOOST_THREAD_FUTURE_BLOCKING
|
||||
#else
|
||||
//#define BOOST_THREAD_FUTURE_BLOCKING
|
||||
#define BOOST_THREAD_ASYNC_FUTURE_WAITS
|
||||
#endif
|
||||
// INTERRUPTIONS
|
||||
#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
|
||||
@@ -72,13 +72,21 @@ namespace boost
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker& operator=(BOOST_THREAD_RV_REF(invoker) f)
|
||||
{
|
||||
f_ = boost::move(BOOST_THREAD_RV(f).f_);
|
||||
if (this != &f)
|
||||
{
|
||||
f_ = boost::move(BOOST_THREAD_RV(f).f_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker& operator=( BOOST_THREAD_COPY_ASSIGN_REF(invoker) f)
|
||||
{
|
||||
f_ = f.f_;
|
||||
if (this != &f)
|
||||
{
|
||||
f_ = f.f_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
result_type operator()()
|
||||
@@ -91,7 +99,7 @@ namespace boost
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
return detail::invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -128,13 +136,13 @@ namespace boost
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
return detail::invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
#else
|
||||
|
||||
#if ! defined BOOST_MSVC
|
||||
#if ! defined BOOST_MSVC && defined(BOOST_THREAD_PROVIDES_INVOKE)
|
||||
|
||||
#define BOOST_THREAD_RV_REF_ARG_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(Arg##n)
|
||||
#define BOOST_THREAD_RV_REF_A_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(A##n)
|
||||
@@ -182,7 +190,7 @@ namespace boost
|
||||
{} \
|
||||
\
|
||||
result_type operator()() { \
|
||||
return invoke(boost::move(fp_) \
|
||||
return detail::invoke(boost::move(fp_) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \
|
||||
); \
|
||||
} \
|
||||
@@ -307,7 +315,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -373,7 +381,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -434,7 +442,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -490,7 +498,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -541,7 +549,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -587,7 +595,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -628,7 +636,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
@@ -664,7 +672,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
);
|
||||
@@ -695,7 +703,7 @@ namespace boost
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
return detail::invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,11 @@ namespace boost
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \
|
||||
namespace detail { \
|
||||
template <typename T1, typename T2> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, false> \
|
||||
{}; \
|
||||
@@ -115,6 +120,11 @@ namespace boost
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \
|
||||
namespace detail { \
|
||||
template <typename T1, typename T2> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, false> \
|
||||
{}; \
|
||||
@@ -136,6 +146,11 @@ namespace boost
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \
|
||||
namespace detail { \
|
||||
template <typename T1, typename T2> \
|
||||
struct enable_move_utility_emulation_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, false> \
|
||||
{}; \
|
||||
@@ -161,6 +176,10 @@ struct enable_move_utility_emulation< TYPE > \
|
||||
template <typename T> \
|
||||
struct enable_move_utility_emulation<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG2(T1, T2) \
|
||||
template <typename T1, typename T2> \
|
||||
struct enable_move_utility_emulation<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
{ \
|
||||
static const bool value = false; \
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace boost
|
||||
|
||||
};
|
||||
}
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::nullary_function<F> BOOST_THREAD_DCL_MOVABLE_END
|
||||
BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::nullary_function<F> BOOST_THREAD_DCL_MOVABLE_END
|
||||
}
|
||||
|
||||
#endif // header
|
||||
|
||||
@@ -72,7 +72,7 @@ namespace boost
|
||||
void run2(tuple_indices<Indices...>)
|
||||
{
|
||||
|
||||
invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
|
||||
detail::invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
|
||||
}
|
||||
void run()
|
||||
{
|
||||
@@ -173,7 +173,6 @@ namespace boost
|
||||
private:
|
||||
bool start_thread_noexcept();
|
||||
bool start_thread_noexcept(const attributes& attr);
|
||||
//public:
|
||||
void start_thread()
|
||||
{
|
||||
if (!start_thread_noexcept())
|
||||
@@ -355,6 +354,8 @@ namespace boost
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
if (joinable()) std::terminate();
|
||||
#else
|
||||
detach();
|
||||
#endif
|
||||
thread_info=BOOST_THREAD_RV(other).thread_info;
|
||||
BOOST_THREAD_RV(other).thread_info.reset();
|
||||
@@ -481,13 +482,20 @@ namespace boost
|
||||
return try_join_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC) && defined(BOOST_THREAD_USEFIXES_TIMESPEC)
|
||||
typedef chrono::steady_clock my_clock_t;
|
||||
#else
|
||||
typedef chrono::system_clock my_clock_t;
|
||||
#endif
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
bool joined= false;
|
||||
do {
|
||||
my_clock_t::time_point s_now = my_clock_t::now();
|
||||
typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
|
||||
if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
|
||||
joined = try_join_until(s_now + d);
|
||||
@@ -495,10 +503,10 @@ namespace boost
|
||||
return true;
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
bool try_join_until(const chrono::time_point<my_clock_t, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
||||
typedef time_point<my_clock_t, nanoseconds> nano_sys_tmpt;
|
||||
return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
||||
}
|
||||
#endif
|
||||
@@ -513,7 +521,7 @@ namespace boost
|
||||
//}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
bool try_join_until(const chrono::time_point<my_clock_t, chrono::nanoseconds>& tp)
|
||||
{
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
return do_try_join_until(rel_time.count());
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
// (C) Copyright 2007-9 Anthony Williams
|
||||
|
||||
#include <list>
|
||||
#include <boost/thread/csbl/memory/unique_ptr.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/lock_guard.hpp>
|
||||
@@ -75,7 +76,7 @@ namespace boost
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
std::auto_ptr<thread> new_thread(new thread(threadfunc));
|
||||
boost::csbl::unique_ptr<thread> new_thread(new thread(threadfunc));
|
||||
threads.push_back(new_thread.get());
|
||||
return new_thread.release();
|
||||
}
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_DETAIL_WORK_HPP
|
||||
#define BOOST_THREAD_DETAIL_WORK_HPP
|
||||
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
typedef detail::nullary_function<void()> work;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
@@ -40,19 +40,19 @@ namespace boost
|
||||
typedef system::system_error base_type;
|
||||
public:
|
||||
thread_exception()
|
||||
: base_type(0,system::system_category())
|
||||
: base_type(0,system::generic_category())
|
||||
{}
|
||||
|
||||
thread_exception(int sys_error_code)
|
||||
: base_type(sys_error_code, system::system_category())
|
||||
: base_type(sys_error_code, system::generic_category())
|
||||
{}
|
||||
|
||||
thread_exception( int ev, const char * what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
: base_type(system::error_code(ev, system::generic_category()), what_arg)
|
||||
{
|
||||
}
|
||||
thread_exception( int ev, const std::string & what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
: base_type(system::error_code(ev, system::generic_category()), what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -74,18 +74,18 @@ namespace boost
|
||||
typedef system::system_error base_type;
|
||||
public:
|
||||
condition_error()
|
||||
: base_type(system::error_code(0, system::system_category()), "Condition error")
|
||||
: base_type(system::error_code(0, system::generic_category()), "Condition error")
|
||||
{}
|
||||
condition_error( int ev )
|
||||
: base_type(system::error_code(ev, system::system_category()), "Condition error")
|
||||
: base_type(system::error_code(ev, system::generic_category()), "Condition error")
|
||||
{
|
||||
}
|
||||
condition_error( int ev, const char * what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
: base_type(system::error_code(ev, system::generic_category()), what_arg)
|
||||
{
|
||||
}
|
||||
condition_error( int ev, const std::string & what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
: base_type(system::error_code(ev, system::generic_category()), what_arg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
|
||||
@@ -30,15 +30,14 @@ namespace executors
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
|
||||
typedef thread thread_t;
|
||||
/// A move aware vector type
|
||||
typedef scoped_thread<> thread_t;
|
||||
typedef csbl::vector<thread_t> thread_vector;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
/// A move aware vector
|
||||
thread_vector threads;
|
||||
/// the thread safe work queue
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -48,23 +47,20 @@ namespace executors
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
work task;
|
||||
if (work_queue.try_pull(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
std::terminate();
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -90,17 +86,16 @@ namespace executors
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = work_queue.wait_pull_front(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
queue_op_status st = work_queue.wait_pull(task);
|
||||
if (st == queue_op_status::closed) {
|
||||
return;
|
||||
}
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -134,7 +129,7 @@ namespace executors
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -228,7 +223,8 @@ namespace executors
|
||||
{
|
||||
// signal to all the worker threads that there will be no more submissions.
|
||||
close();
|
||||
// joins all the threads as the threads were scoped_threads
|
||||
// joins all the threads before destroying the thread pool resources (e.g. the queue).
|
||||
join();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -270,23 +266,28 @@ namespace executors
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
work_queue.push(boost::move(closure));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
//submit(work(boost::forward<Closure>(closure)));
|
||||
work w((boost::forward<Closure>(closure)));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_EXECUTORS_DETAIL_PRIORITY_EXECUTOR_BASE_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_DETAIL_PRIORITY_EXECUTOR_BASE_HPP
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_timed_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class Queue>
|
||||
class priority_executor_base
|
||||
{
|
||||
public:
|
||||
//typedef boost::function<void()> work;
|
||||
typedef executors::work_pq work;
|
||||
protected:
|
||||
typedef Queue queue_type;
|
||||
queue_type _workq;
|
||||
|
||||
priority_executor_base() {}
|
||||
public:
|
||||
|
||||
~priority_executor_base()
|
||||
{
|
||||
if(!closed())
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
_workq.close();
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return _workq.closed();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = _workq.wait_pull(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}; //end class
|
||||
|
||||
} //end detail namespace
|
||||
} //end executors namespace
|
||||
} //end boost namespace
|
||||
#endif
|
||||
@@ -0,0 +1,66 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014-2015 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_EXECUTORS_DETAIL_SCHEDULED_EXECUTOR_BASE_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_DETAIL_SCHEDULED_EXECUTOR_BASE_HPP
|
||||
|
||||
#include <boost/thread/concurrent_queues/sync_timed_queue.hpp>
|
||||
#include <boost/thread/executors/detail/priority_executor_base.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class Clock=chrono::steady_clock>
|
||||
class scheduled_executor_base : public priority_executor_base<concurrent::sync_timed_queue<executors::work_pq, Clock > >
|
||||
{
|
||||
public:
|
||||
typedef executors::work_pq work;
|
||||
typedef Clock clock;
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
protected:
|
||||
|
||||
scheduled_executor_base() {}
|
||||
public:
|
||||
|
||||
~scheduled_executor_base()
|
||||
{
|
||||
if(! this->closed())
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
|
||||
void submit_at(work w, const time_point& tp)
|
||||
{
|
||||
this->_workq.push(boost::move(w), tp);
|
||||
}
|
||||
|
||||
void submit_after(work w, const duration& dura)
|
||||
{
|
||||
this->_workq.push(boost::move(w), dura+clock::now());
|
||||
}
|
||||
|
||||
}; //end class
|
||||
|
||||
} //end detail namespace
|
||||
} //end executors namespace
|
||||
} //end boost namespace
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -38,7 +38,7 @@ namespace boost
|
||||
* \par Synchronization
|
||||
* The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
virtual ~executor() {};
|
||||
virtual ~executor() {}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
@@ -99,9 +99,10 @@ namespace boost
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
//submit(work(boost::forward<Closure>(closure)));
|
||||
work w((boost::forward<Closure>(closure)));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
|
||||
@@ -98,9 +98,6 @@ namespace executors
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
return ex.submit(boost::move(closure));
|
||||
}
|
||||
// void submit(work & closure) {
|
||||
// return ex.submit(closure);
|
||||
// }
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
@@ -115,9 +112,11 @@ namespace executors
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
submit(work(boost::forward<Closure>(closure)));
|
||||
//submit(work(boost::forward<Closure>(closure)));
|
||||
work w((boost::forward<Closure>(closure)));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace boost
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor_ref)
|
||||
executor_ref(Executor& ex) : ex(ex) {}
|
||||
executor_ref(Executor& ex_) : ex(ex_) {}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
@@ -41,7 +41,7 @@ namespace boost
|
||||
* \par Synchronization
|
||||
* The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
~executor_ref() {};
|
||||
~executor_ref() {}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
@@ -98,9 +98,9 @@ namespace boost
|
||||
typedef executors::work work;
|
||||
|
||||
template<typename Executor>
|
||||
generic_executor_ref(Executor& ex)
|
||||
//: ex(make_shared<executor_ref<Executor> >(ex)) // todo check why this doesn't works with C++03
|
||||
: ex( new executor_ref<Executor>(ex) )
|
||||
generic_executor_ref(Executor& ex_)
|
||||
//: ex(make_shared<executor_ref<Executor> >(ex_)) // todo check why this doesn't works with C++03
|
||||
: ex( new executor_ref<Executor>(ex_) )
|
||||
{
|
||||
}
|
||||
|
||||
@@ -121,11 +121,6 @@ namespace boost
|
||||
*/
|
||||
bool closed() { return ex->closed(); }
|
||||
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure)
|
||||
{
|
||||
ex->submit(boost::forward<work>(closure));
|
||||
}
|
||||
|
||||
/**
|
||||
* \par Requires
|
||||
* \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
@@ -142,24 +137,31 @@ namespace boost
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure)
|
||||
{
|
||||
ex->submit(boost::move(closure));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//work w ((closure));
|
||||
//submit(boost::move(w));
|
||||
submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
work w((boost::forward<Closure>(closure)));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace executors
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
mutable mutex mtx_;
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
@@ -66,16 +67,22 @@ namespace executors
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
bool closed(lock_guard<mutex>& )
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
bool closed()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
@@ -93,21 +100,54 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -14,8 +14,9 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -31,7 +32,7 @@ namespace executors
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
|
||||
public:
|
||||
/**
|
||||
@@ -40,51 +41,39 @@ namespace executors
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
return execute_one(/*wait:*/false);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Effects: Execute one task.
|
||||
* Remark: If wait is true, waits until a task is available or the executor
|
||||
* is closed. If wait is false, returns false immediately if no
|
||||
* task is available.
|
||||
* Returns: whether a task has been executed (if wait is true, only returns false if closed).
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool execute_one(bool wait)
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
queue_op_status status = wait ?
|
||||
work_queue.wait_pull(task) :
|
||||
work_queue.try_pull(task);
|
||||
if (status == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
BOOST_ASSERT(!wait || status == queue_op_status::closed);
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
std::terminate();
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,9 +101,19 @@ namespace executors
|
||||
}
|
||||
|
||||
/**
|
||||
* loop
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void loop() { worker_thread(); }
|
||||
void loop()
|
||||
{
|
||||
while (execute_one(/*wait:*/true))
|
||||
{
|
||||
}
|
||||
BOOST_ASSERT(closed());
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c loop_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
@@ -143,23 +142,29 @@ namespace executors
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
work_queue.push(boost::move(closure));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
//work_queue.push(work(boost::forward<Closure>(closure)));
|
||||
work w((boost::forward<Closure>(closure)));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
48
include/boost/thread/executors/scheduled_thread_pool.hpp
Normal file
48
include/boost/thread/executors/scheduled_thread_pool.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
class scheduled_thread_pool : public detail::scheduled_executor_base<>
|
||||
{
|
||||
private:
|
||||
thread_group _workers;
|
||||
public:
|
||||
|
||||
scheduled_thread_pool(size_t num_threads) : super()
|
||||
{
|
||||
for(size_t i = 0; i < num_threads; i++)
|
||||
{
|
||||
_workers.create_thread(bind(&super::loop, this));
|
||||
}
|
||||
}
|
||||
|
||||
~scheduled_thread_pool()
|
||||
{
|
||||
this->close();
|
||||
_workers.join_all();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef detail::scheduled_executor_base<> super;
|
||||
}; //end class
|
||||
|
||||
} //end executors namespace
|
||||
|
||||
using executors::scheduled_thread_pool;
|
||||
|
||||
} //end boost
|
||||
#endif
|
||||
|
||||
271
include/boost/thread/executors/scheduler.hpp
Normal file
271
include/boost/thread/executors/scheduler.hpp
Normal file
@@ -0,0 +1,271 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_EXECUTORS_SCHEDULER_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
/// Wraps the reference to an executor and a function to make a work that submit the function using the executor.
|
||||
template <class Executor, class Function>
|
||||
class resubmitter
|
||||
{
|
||||
public:
|
||||
resubmitter(Executor& ex, Function funct) :
|
||||
ex(ex),
|
||||
funct(boost::move(funct))
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
ex.submit(funct);
|
||||
}
|
||||
|
||||
private:
|
||||
Executor& ex;
|
||||
Function funct;
|
||||
};
|
||||
|
||||
/// resubmitter factory
|
||||
template <class Executor, class Function>
|
||||
resubmitter<Executor, typename decay<Function>::type>
|
||||
resubmit(Executor& ex, BOOST_THREAD_FWD_REF(Function) funct) {
|
||||
return resubmitter<Executor, typename decay<Function>::type >(ex, boost::move(funct));
|
||||
}
|
||||
|
||||
/// Wraps references to a @c Scheduler and an @c Executor providing an @c Executor that
|
||||
/// resubmit the function using the referenced Executor at a given @c time_point known at construction.
|
||||
template <class Scheduler, class Executor>
|
||||
class resubmit_at_executor
|
||||
{
|
||||
public:
|
||||
typedef typename Scheduler::clock clock;
|
||||
typedef typename Scheduler::work work;
|
||||
|
||||
template <class Duration>
|
||||
resubmit_at_executor(Scheduler& sch, Executor& ex, chrono::time_point<clock, Duration> const& tp) :
|
||||
sch(sch),
|
||||
ex(ex),
|
||||
tp(tp),
|
||||
is_closed(false)
|
||||
{
|
||||
}
|
||||
|
||||
~resubmit_at_executor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
template <class Work>
|
||||
void submit(BOOST_THREAD_FWD_REF(Work) w)
|
||||
{
|
||||
if (closed())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
sch.submit_at(resubmit(ex,boost::forward<Work>(w)), tp);
|
||||
}
|
||||
|
||||
Executor& underlying_executor()
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
Scheduler& underlying_scheduler()
|
||||
{
|
||||
return sch;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
is_closed = true;
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return is_closed || sch.closed() || ex.closed();
|
||||
}
|
||||
|
||||
private:
|
||||
Scheduler& sch;
|
||||
Executor& ex;
|
||||
typename clock::time_point tp;
|
||||
bool is_closed;
|
||||
};
|
||||
|
||||
|
||||
/// Expression template helper storing a pair of references to an @c Scheduler and an @c Executor
|
||||
/// It provides factory helper functions such as at/after that convert these a pair of @c Scheduler @c Executor
|
||||
/// into an new @c Executor that submit the work using the referenced @c Executor at/after a specific time/duration
|
||||
/// respectively, using the referenced @Scheduler.
|
||||
template <class Scheduler, class Executor>
|
||||
class scheduler_executor_wrapper
|
||||
{
|
||||
public:
|
||||
typedef typename Scheduler::clock clock;
|
||||
typedef typename Scheduler::work work;
|
||||
typedef resubmit_at_executor<Scheduler, Executor> the_executor;
|
||||
|
||||
scheduler_executor_wrapper(Scheduler& sch, Executor& ex) :
|
||||
sch(sch),
|
||||
ex(ex)
|
||||
{}
|
||||
|
||||
~scheduler_executor_wrapper()
|
||||
{
|
||||
}
|
||||
|
||||
Executor& underlying_executor()
|
||||
{
|
||||
return ex;
|
||||
}
|
||||
Scheduler& underlying_scheduler()
|
||||
{
|
||||
return sch;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
the_executor after(chrono::duration<Rep,Period> const& rel_time)
|
||||
{
|
||||
return at(clock::now() + rel_time );
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
the_executor at(chrono::time_point<clock,Duration> const& abs_time)
|
||||
{
|
||||
return the_executor(sch, ex, abs_time);
|
||||
}
|
||||
|
||||
private:
|
||||
Scheduler& sch;
|
||||
Executor& ex;
|
||||
}; //end class
|
||||
|
||||
/// Wraps a reference to a @c Scheduler providing an @c Executor that
|
||||
/// run the function at a given @c time_point known at construction.
|
||||
template <class Scheduler>
|
||||
class at_executor
|
||||
{
|
||||
public:
|
||||
typedef typename Scheduler::clock clock;
|
||||
typedef typename Scheduler::work work;
|
||||
typedef typename clock::time_point time_point;
|
||||
|
||||
template <class Duration>
|
||||
at_executor(Scheduler& sch, chrono::time_point<clock,Duration> const& tp) :
|
||||
sch(sch),
|
||||
tp(tp),
|
||||
is_closed(false)
|
||||
{}
|
||||
|
||||
~at_executor()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
Scheduler& underlying_scheduler()
|
||||
{
|
||||
return sch;
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
is_closed = true;
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return is_closed || sch.closed();
|
||||
}
|
||||
|
||||
template <class Work>
|
||||
void submit(BOOST_THREAD_FWD_REF(Work) w)
|
||||
{
|
||||
if (closed())
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
sch.submit_at(boost::forward<Work>(w), tp);
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
resubmit_at_executor<Scheduler, Executor> on(Executor& ex)
|
||||
{
|
||||
return resubmit_at_executor<Scheduler, Executor>(sch, ex, tp);
|
||||
}
|
||||
|
||||
private:
|
||||
Scheduler& sch;
|
||||
time_point tp;
|
||||
bool is_closed;
|
||||
}; //end class
|
||||
|
||||
/// A @c Scheduler using a specific thread. Note that a Scheduler is not an Executor.
|
||||
/// It provides factory helper functions such as at/after that convert a @c Scheduler into an @c Executor
|
||||
/// that submit the work at/after a specific time/duration respectively.
|
||||
template <class Clock = chrono::steady_clock>
|
||||
class scheduler : public detail::scheduled_executor_base<Clock>
|
||||
{
|
||||
public:
|
||||
typedef typename detail::scheduled_executor_base<Clock>::work work;
|
||||
|
||||
typedef Clock clock;
|
||||
|
||||
scheduler()
|
||||
: super(),
|
||||
thr(&super::loop, this) {}
|
||||
|
||||
~scheduler()
|
||||
{
|
||||
this->close();
|
||||
thr.join();
|
||||
}
|
||||
template <class Ex>
|
||||
scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex)
|
||||
{
|
||||
return scheduler_executor_wrapper<scheduler, Ex>(*this, ex);
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
at_executor<scheduler> after(chrono::duration<Rep,Period> const& rel_time)
|
||||
{
|
||||
return at(rel_time + clock::now());
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
at_executor<scheduler> at(chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
return at_executor<scheduler>(*this, tp);
|
||||
}
|
||||
|
||||
private:
|
||||
typedef detail::scheduled_executor_base<Clock> super;
|
||||
thread thr;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
using executors::resubmitter;
|
||||
using executors::resubmit;
|
||||
using executors::resubmit_at_executor;
|
||||
using executors::scheduler_executor_wrapper;
|
||||
using executors::at_executor;
|
||||
using executors::scheduler;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
51
include/boost/thread/executors/scheduling_adaptor.hpp
Normal file
51
include/boost/thread/executors/scheduling_adaptor.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_EXECUTORS_SCHEDULING_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
|
||||
|
||||
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
template <typename Executor>
|
||||
class scheduling_adpator : public detail::scheduled_executor_base<>
|
||||
{
|
||||
private:
|
||||
Executor& _exec;
|
||||
thread _scheduler;
|
||||
public:
|
||||
|
||||
scheduling_adpator(Executor& ex)
|
||||
: super(),
|
||||
_exec(ex),
|
||||
_scheduler(&super::loop, this) {}
|
||||
|
||||
~scheduling_adpator()
|
||||
{
|
||||
this->close();
|
||||
_scheduler.join();
|
||||
}
|
||||
|
||||
Executor& underlying_executor()
|
||||
{
|
||||
return _exec;
|
||||
}
|
||||
|
||||
private:
|
||||
typedef detail::scheduled_executor_base<> super;
|
||||
}; //end class
|
||||
|
||||
} //end executors
|
||||
|
||||
using executors::scheduling_adpator;
|
||||
|
||||
} //end boost
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
@@ -33,7 +33,7 @@ namespace executors
|
||||
typedef scoped_thread<> thread_t;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
concurrent::sync_queue<work > work_queue;
|
||||
generic_executor_ref ex;
|
||||
thread_t thr;
|
||||
|
||||
@@ -43,8 +43,13 @@ namespace executors
|
||||
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||
: task(task), p(p) {}
|
||||
void operator()() {
|
||||
task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
p.set_value();
|
||||
try {
|
||||
task();
|
||||
p.set_value();
|
||||
} catch (...)
|
||||
{
|
||||
p.set_exception(current_exception());
|
||||
}
|
||||
}
|
||||
};
|
||||
public:
|
||||
@@ -52,7 +57,7 @@ namespace executors
|
||||
* \par Returns
|
||||
* The underlying executor wrapped on a generic executor reference.
|
||||
*/
|
||||
generic_executor_ref underlying_executor() BOOST_NOEXCEPT { return ex; }
|
||||
generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex; }
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
@@ -64,28 +69,20 @@ namespace executors
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
if (work_queue.try_pull(task) == queue_op_status::success)
|
||||
{
|
||||
boost::promise<void> p;
|
||||
try_executing_one_task tmp(task,p);
|
||||
ex.submit(tmp);
|
||||
// ex.submit([&task, &p]()
|
||||
// {
|
||||
// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
// p.set_value();
|
||||
// });
|
||||
p.get_future().wait();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
std::terminate();
|
||||
//return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
@@ -136,7 +133,7 @@ namespace executors
|
||||
*/
|
||||
~serial_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
// signal to the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
@@ -168,23 +165,28 @@ namespace executors
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure)
|
||||
{
|
||||
work_queue.push(boost::move(closure));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
submit(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
work w((boost::forward<Closure>(closure)));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
170
include/boost/thread/executors/serial_executor_cont.hpp
Normal file
170
include/boost/thread/executors/serial_executor_cont.hpp
Normal file
@@ -0,0 +1,170 @@
|
||||
// Copyright (C) 2015 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple serial scheduler.
|
||||
|
||||
#ifndef BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP
|
||||
#define BOOST_THREAD_SERIAL_EXECUTOR_CONT_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/generic_executor_ref.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class serial_executor_cont
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
|
||||
generic_executor_ref ex_;
|
||||
future<void> fut_; // protected by mtx_
|
||||
bool closed_; // protected by mtx_
|
||||
mutex mtx_;
|
||||
|
||||
struct continuation {
|
||||
work task;
|
||||
template <class X>
|
||||
struct result {
|
||||
typedef void type;
|
||||
};
|
||||
continuation(BOOST_THREAD_RV_REF(work) tsk)
|
||||
: task(boost::move(tsk)) {}
|
||||
void operator()(future<void> f)
|
||||
{
|
||||
try {
|
||||
task();
|
||||
} catch (...) {
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
bool closed(lock_guard<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* \par Returns
|
||||
* The underlying executor wrapped on a generic executor reference.
|
||||
*/
|
||||
generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex_; }
|
||||
|
||||
/// serial_executor_cont is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(serial_executor_cont)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a serial executor that runs closures in fifo order using one the associated executor.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*
|
||||
* \b Notes:
|
||||
* * The lifetime of the associated executor must outlive the serial executor.
|
||||
* * The current implementation doesn't support submission from synchronous continuation, that is,
|
||||
* - the executor must execute the continuation asynchronously or
|
||||
* - the continuation can not submit to this serial executor.
|
||||
*/
|
||||
template <class Executor>
|
||||
serial_executor_cont(Executor& ex)
|
||||
: ex_(ex), fut_(make_ready_future()), closed_(false)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor_cont destructor.
|
||||
*/
|
||||
~serial_executor_cont()
|
||||
{
|
||||
// signal to the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c serial_executor_cont for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: none.
|
||||
* Returns: always false.
|
||||
* Throws: No.
|
||||
* Remark: A serial executor can not execute one of its pending tasks as the tasks depends on the other tasks.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution after the last submitted closure finish.
|
||||
* If the invoked closure throws an exception the \c serial_executor_cont will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the executor is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
fut_ = fut_.then(ex_, continuation(work(closure)));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
fut_ = fut_.then(ex_, continuation(work(closure)));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
fut_ = fut_.then(ex_, continuation(work(boost::forward<Closure>(closure))));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::serial_executor_cont;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -15,6 +15,9 @@
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -28,6 +31,11 @@ namespace executors
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
typedef scoped_thread<> thread_t;
|
||||
typedef csbl::vector<thread_t> threads_type;
|
||||
threads_type threads_;
|
||||
mutable mutex mtx_;
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
@@ -52,7 +60,7 @@ namespace executors
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the inline executor.
|
||||
* \b Effects: Waits for closures (if any) to complete, then joins and destroys the threads.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor.
|
||||
*/
|
||||
@@ -60,6 +68,7 @@ namespace executors
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
// all the scoped threads will join before destroying
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,16 +77,22 @@ namespace executors
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
bool closed(lock_guard<mutex>& )
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
bool closed()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
@@ -95,24 +110,30 @@ namespace executors
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
threads_.reserve(threads_.size() + 1);
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
threads_.push_back(thread_t(boost::move(th)));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
threads_.reserve(threads_.size() + 1);
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
threads_.push_back(thread_t(boost::move(th)));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
threads_.reserve(threads_.size() + 1);
|
||||
thread th(boost::forward<Closure>(closure));
|
||||
th.detach();
|
||||
threads_.push_back(thread_t(boost::move(th)));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,36 +8,23 @@
|
||||
#define BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if ! defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE \
|
||||
&& ! defined BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE
|
||||
#define BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE
|
||||
//#define BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
typedef detail::nullary_function<void()> work;
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#else
|
||||
#include <boost/thread/csbl/functional.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
typedef csbl::function<void()> work;
|
||||
typedef detail::nullary_function<void()> work;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
typedef detail::nullary_function<void()> work_pq;
|
||||
//typedef csbl::function<void()> work_pq;
|
||||
#else
|
||||
typedef csbl::function<void()> work_pq;
|
||||
#endif
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
|
||||
#endif // BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
|
||||
# define BOOST_THREAD_INLINE_NAMESPACE(name) inline namespace name
|
||||
#else
|
||||
# define BOOST_THREAD_INLINE_NAMESPACE(name) namespace name
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
16
include/boost/thread/experimental/exception_list.hpp
Normal file
16
include/boost/thread/experimental/exception_list.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/parallel/v1/exception_list.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/experimental/parallel/v1/inline_namespace.hpp>
|
||||
|
||||
#include <boost/exception_ptr.hpp>
|
||||
#include <exception>
|
||||
#include <list>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v1)
|
||||
{
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE exception_list: public std::exception
|
||||
{
|
||||
typedef std::list<exception_ptr> exception_ptr_list;
|
||||
exception_ptr_list list_;
|
||||
public:
|
||||
typedef exception_ptr_list::const_iterator const_iterator;
|
||||
|
||||
~exception_list() BOOST_NOEXCEPT_OR_NOTHROW {}
|
||||
|
||||
void add(exception_ptr const& e)
|
||||
{
|
||||
list_.push_back(e);
|
||||
}
|
||||
size_t size() const BOOST_NOEXCEPT
|
||||
{
|
||||
return list_.size();
|
||||
}
|
||||
const_iterator begin() const BOOST_NOEXCEPT
|
||||
{
|
||||
return list_.begin();
|
||||
}
|
||||
const_iterator end() const BOOST_NOEXCEPT
|
||||
{
|
||||
return list_.end();
|
||||
}
|
||||
const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{
|
||||
return "exception_list";
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/config/inline_namespace.hpp>
|
||||
namespace boost {
|
||||
namespace experimental {
|
||||
namespace parallel {
|
||||
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v1) {}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
|
||||
using namespace v1;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/config/inline_namespace.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace experimental {
|
||||
namespace parallel {
|
||||
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v2) {}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
|
||||
using namespace v2;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
316
include/boost/thread/experimental/parallel/v2/task_region.hpp
Executable file
316
include/boost/thread/experimental/parallel/v2/task_region.hpp
Executable file
@@ -0,0 +1,316 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014-2015. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#endif
|
||||
#include <boost/thread/experimental/exception_list.hpp>
|
||||
#include <boost/thread/experimental/parallel/v2/inline_namespace.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#define BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
BOOST_THREAD_INLINE_NAMESPACE(v2)
|
||||
{
|
||||
class BOOST_SYMBOL_VISIBLE task_canceled_exception: public std::exception
|
||||
{
|
||||
public:
|
||||
//task_canceled_exception() BOOST_NOEXCEPT {}
|
||||
//task_canceled_exception(const task_canceled_exception&) BOOST_NOEXCEPT {}
|
||||
//task_canceled_exception& operator=(const task_canceled_exception&) BOOST_NOEXCEPT {}
|
||||
virtual const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{ return "task_canceled_exception";}
|
||||
};
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void handle_task_region_exceptions(exception_list& errors)
|
||||
{
|
||||
try {
|
||||
throw;
|
||||
}
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
catch (task_canceled_exception&)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
catch (exception_list const& el)
|
||||
{
|
||||
for (exception_list::const_iterator it = el.begin(); it != el.end(); ++it)
|
||||
{
|
||||
boost::exception_ptr const& e = *it;
|
||||
try {
|
||||
rethrow_exception(e);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
handle_task_region_exceptions(errors);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
errors.add(boost::current_exception());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
template <class TRH, class F>
|
||||
struct wrapped
|
||||
{
|
||||
TRH& tr;
|
||||
F f;
|
||||
wrapped(TRH& tr, BOOST_THREAD_RV_REF(F) f) : tr(tr), f(move(f))
|
||||
{}
|
||||
void operator()()
|
||||
{
|
||||
try
|
||||
{
|
||||
f();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
lock_guard<mutex> lk(tr.mtx);
|
||||
tr.canceled = true;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen
|
||||
{
|
||||
private:
|
||||
// Private members and friends
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
template <class TRH, class F>
|
||||
friend struct detail::wrapped;
|
||||
#endif
|
||||
template <typename F>
|
||||
friend void task_region(BOOST_THREAD_FWD_REF(F) f);
|
||||
template<typename F>
|
||||
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
|
||||
template <class Ex, typename F>
|
||||
friend void task_region(Ex&, BOOST_THREAD_FWD_REF(F) f);
|
||||
template<class Ex, typename F>
|
||||
friend void task_region_final(Ex&, BOOST_THREAD_FWD_REF(F) f);
|
||||
|
||||
void wait_all()
|
||||
{
|
||||
wait_for_all(group.begin(), group.end());
|
||||
|
||||
for (group_type::iterator it = group.begin(); it != group.end(); ++it)
|
||||
{
|
||||
future<void>& f = *it;
|
||||
if (f.has_exception())
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::rethrow_exception(f.get_exception_ptr());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
detail::handle_task_region_exceptions(exs);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (exs.size() != 0)
|
||||
{
|
||||
boost::throw_exception(exs);
|
||||
}
|
||||
}
|
||||
protected:
|
||||
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
: canceled(false)
|
||||
, ex(0)
|
||||
{}
|
||||
task_region_handle_gen(Executor& ex)
|
||||
: canceled(false)
|
||||
, ex(&ex)
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
: ex(0)
|
||||
{}
|
||||
task_region_handle_gen(Executor& ex)
|
||||
: ex(&ex)
|
||||
{}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
task_region_handle_gen()
|
||||
: canceled(false)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
~task_region_handle_gen()
|
||||
{
|
||||
//wait_all();
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
mutable mutex mtx;
|
||||
bool canceled;
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
Executor* ex;
|
||||
#endif
|
||||
exception_list exs;
|
||||
typedef csbl::vector<future<void> > group_type;
|
||||
group_type group;
|
||||
|
||||
public:
|
||||
BOOST_DELETED_FUNCTION(task_region_handle_gen(const task_region_handle_gen&))
|
||||
BOOST_DELETED_FUNCTION(task_region_handle_gen& operator=(const task_region_handle_gen&))
|
||||
BOOST_DELETED_FUNCTION(task_region_handle_gen* operator&() const)
|
||||
|
||||
public:
|
||||
template<typename F>
|
||||
void run(BOOST_THREAD_FWD_REF(F) f)
|
||||
{
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
{
|
||||
lock_guard<mutex> lk(mtx);
|
||||
if (canceled) {
|
||||
boost::throw_exception(task_canceled_exception());
|
||||
}
|
||||
}
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
||||
#else
|
||||
group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
|
||||
#endif
|
||||
#else
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
group.push_back(async(*ex, forward<F>(f)));
|
||||
#else
|
||||
group.push_back(async(forward<F>(f)));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void wait()
|
||||
{
|
||||
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
|
||||
{
|
||||
lock_guard<mutex> lk(mtx);
|
||||
if (canceled) {
|
||||
boost::throw_exception(task_canceled_exception());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
wait_all();
|
||||
}
|
||||
};
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
typedef basic_thread_pool default_executor;
|
||||
#else
|
||||
typedef int default_executor;
|
||||
#endif
|
||||
class task_region_handle :
|
||||
public task_region_handle_gen<default_executor>
|
||||
{
|
||||
default_executor tp;
|
||||
template <typename F>
|
||||
friend void task_region(BOOST_THREAD_FWD_REF(F) f);
|
||||
template<typename F>
|
||||
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
|
||||
|
||||
protected:
|
||||
task_region_handle() : task_region_handle_gen<default_executor>()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
ex = &tp;
|
||||
#endif
|
||||
}
|
||||
BOOST_DELETED_FUNCTION(task_region_handle(const task_region_handle&))
|
||||
BOOST_DELETED_FUNCTION(task_region_handle& operator=(const task_region_handle&))
|
||||
BOOST_DELETED_FUNCTION(task_region_handle* operator&() const)
|
||||
|
||||
};
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, BOOST_THREAD_FWD_REF(F) f)
|
||||
{
|
||||
task_region_handle_gen<Executor> tr(ex);
|
||||
try
|
||||
{
|
||||
f(tr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
detail::handle_task_region_exceptions(tr.exs);
|
||||
}
|
||||
tr.wait_all();
|
||||
}
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, BOOST_THREAD_FWD_REF(F) f)
|
||||
{
|
||||
task_region_final(ex, forward<F>(f));
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void task_region_final(BOOST_THREAD_FWD_REF(F) f)
|
||||
{
|
||||
task_region_handle tr;
|
||||
try
|
||||
{
|
||||
f(tr);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
detail::handle_task_region_exceptions(tr.exs);
|
||||
}
|
||||
tr.wait_all();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void task_region(BOOST_THREAD_FWD_REF(F) f)
|
||||
{
|
||||
task_region_final(forward<F>(f));
|
||||
}
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
16
include/boost/thread/experimental/task_region.hpp
Normal file
16
include/boost/thread/experimental/task_region.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP
|
||||
#define BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. 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/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/experimental/parallel/v2/task_region.hpp>
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
98
include/boost/thread/futures/future_error.hpp
Normal file
98
include/boost/thread/futures/future_error.hpp
Normal file
@@ -0,0 +1,98 @@
|
||||
// (C) Copyright 2008-10 Anthony Williams
|
||||
// (C) Copyright 2011-2015 Vicente J. Botet Escriba
|
||||
//
|
||||
// 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_FUTURES_FUTURE_ERROR_HPP
|
||||
#define BOOST_THREAD_FUTURES_FUTURE_ERROR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/futures/future_error_code.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class BOOST_SYMBOL_VISIBLE future_error
|
||||
: public std::logic_error
|
||||
{
|
||||
system::error_code ec_;
|
||||
public:
|
||||
future_error(system::error_code ec)
|
||||
: logic_error(ec.message()),
|
||||
ec_(ec)
|
||||
{
|
||||
}
|
||||
|
||||
const system::error_code& code() const BOOST_NOEXCEPT
|
||||
{
|
||||
return ec_;
|
||||
}
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE future_uninitialized:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
future_uninitialized() :
|
||||
future_error(system::make_error_code(future_errc::no_state))
|
||||
{}
|
||||
};
|
||||
class BOOST_SYMBOL_VISIBLE broken_promise:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
broken_promise():
|
||||
future_error(system::make_error_code(future_errc::broken_promise))
|
||||
{}
|
||||
};
|
||||
class BOOST_SYMBOL_VISIBLE future_already_retrieved:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
future_already_retrieved():
|
||||
future_error(system::make_error_code(future_errc::future_already_retrieved))
|
||||
{}
|
||||
};
|
||||
class BOOST_SYMBOL_VISIBLE promise_already_satisfied:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
promise_already_satisfied():
|
||||
future_error(system::make_error_code(future_errc::promise_already_satisfied))
|
||||
{}
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE task_already_started:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
task_already_started():
|
||||
future_error(system::make_error_code(future_errc::promise_already_satisfied))
|
||||
{}
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE task_moved:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
task_moved():
|
||||
future_error(system::make_error_code(future_errc::no_state))
|
||||
{}
|
||||
};
|
||||
|
||||
class promise_moved:
|
||||
public future_error
|
||||
{
|
||||
public:
|
||||
promise_moved():
|
||||
future_error(system::make_error_code(future_errc::no_state))
|
||||
{}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // header
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user