mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
960 Commits
boost-1.57
...
boost-1.76
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
409c98f8b7 | ||
|
|
573296557a | ||
|
|
96cd717b33 | ||
|
|
7afa3e9fd4 | ||
|
|
f5bf0951be | ||
|
|
1fceaebe00 | ||
|
|
30f0ec41fe | ||
|
|
49ece352b3 | ||
|
|
116e8f6eb8 | ||
|
|
66892e5ddd | ||
|
|
42a48f4b03 | ||
|
|
f33abfd621 | ||
|
|
0277d357ae | ||
|
|
e18ae7b173 | ||
|
|
119009f2d1 | ||
|
|
9eee38db94 | ||
|
|
3e59ecec49 | ||
|
|
b1842da010 | ||
|
|
b0da8e291b | ||
|
|
1d436f9030 | ||
|
|
8ebd61c280 | ||
|
|
c13beec81c | ||
|
|
1c28a63e26 | ||
|
|
9b0e0714f0 | ||
|
|
a2492a49af | ||
|
|
25ea5c83ed | ||
|
|
1623ca9e05 | ||
|
|
b1d20a5ce7 | ||
|
|
5f9a247e0b | ||
|
|
9efc377980 | ||
|
|
5589c69547 | ||
|
|
74fb0a2609 | ||
|
|
1eb8efbad7 | ||
|
|
76ce71930f | ||
|
|
2e0bae88f7 | ||
|
|
5507e47ac2 | ||
|
|
2492e7a48c | ||
|
|
0ee9ad87eb | ||
|
|
47fd6b85e3 | ||
|
|
042ce47e77 | ||
|
|
65dcf92e48 | ||
|
|
3071b9e8b5 | ||
|
|
8190a50838 | ||
|
|
23539a88c0 | ||
|
|
6168f43db8 | ||
|
|
a05c37a997 | ||
|
|
34e354be4c | ||
|
|
ccf70ce0aa | ||
|
|
86b7ceb05a | ||
|
|
a645ef761d | ||
|
|
9a20debf11 | ||
|
|
2502b2741b | ||
|
|
5c6180fa4f | ||
|
|
c6863c4b27 | ||
|
|
48a4a06f86 | ||
|
|
a0b255768e | ||
|
|
e5eef80c28 | ||
|
|
ff38aad946 | ||
|
|
7966756ac4 | ||
|
|
8aac9047ab | ||
|
|
f90bdfd2a5 | ||
|
|
7b8fe78ccf | ||
|
|
d49236480f | ||
|
|
ea54f2ec4d | ||
|
|
2553ce4fa0 | ||
|
|
d4c2cef0a2 | ||
|
|
ba02b3af42 | ||
|
|
5d20f5b342 | ||
|
|
52b742d001 | ||
|
|
e16786f173 | ||
|
|
9342fe3f25 | ||
|
|
085c9c6ca8 | ||
|
|
7ba2f2cf5b | ||
|
|
800d0ca597 | ||
|
|
81d4e5a824 | ||
|
|
c97b504925 | ||
|
|
758d087662 | ||
|
|
f5133ab829 | ||
|
|
c46da73e3a | ||
|
|
e942774b90 | ||
|
|
c90ed87527 | ||
|
|
970dcb8afd | ||
|
|
8d0f077ab2 | ||
|
|
dfe6cc3c49 | ||
|
|
330a0a15e6 | ||
|
|
f60dfdfad9 | ||
|
|
ccb1b99e3f | ||
|
|
aa444afc5c | ||
|
|
f1d464d0d5 | ||
|
|
57161ddbb6 | ||
|
|
9a7d21444f | ||
|
|
1b2bc4e451 | ||
|
|
e1b5f9d786 | ||
|
|
8b5cd5f02a | ||
|
|
5b2ffe7104 | ||
|
|
5af180ba36 | ||
|
|
340cc5ab61 | ||
|
|
9a3b8bb4b0 | ||
|
|
79f955e229 | ||
|
|
1da2a57124 | ||
|
|
54871e21a1 | ||
|
|
00efec75d9 | ||
|
|
c66c4b1c76 | ||
|
|
6c70eccb01 | ||
|
|
fbf8d58ad7 | ||
|
|
46a94dd8ba | ||
|
|
76c7b25d4b | ||
|
|
eb297ce86c | ||
|
|
cc31d32b3f | ||
|
|
7f258e5da3 | ||
|
|
c3897bea65 | ||
|
|
502876f0e9 | ||
|
|
e1e4cbf4be | ||
|
|
d2679fec89 | ||
|
|
ba5632e33a | ||
|
|
9a3b7ff859 | ||
|
|
a35ffa3a83 | ||
|
|
1a8229160e | ||
|
|
acda67baf4 | ||
|
|
f6609a42dc | ||
|
|
534f5af9e6 | ||
|
|
2be8908dcd | ||
|
|
aaca72e34b | ||
|
|
24404dcae4 | ||
|
|
f4b239bab1 | ||
|
|
bf7e79c709 | ||
|
|
526e2d6554 | ||
|
|
8c1d232b8c | ||
|
|
92a5bc4300 | ||
|
|
0389f58f23 | ||
|
|
5b209c2e83 | ||
|
|
33ad8b1834 | ||
|
|
8fb92dfb52 | ||
|
|
c550979eff | ||
|
|
15f2d7a21c | ||
|
|
371fb42709 | ||
|
|
f7581a3662 | ||
|
|
e54f7e3960 | ||
|
|
d1284b02ad | ||
|
|
c5e756d196 | ||
|
|
ee607c86d4 | ||
|
|
68eef9240f | ||
|
|
de7608f067 | ||
|
|
743f2a0348 | ||
|
|
d8d549cf3e | ||
|
|
fc08c1fe28 | ||
|
|
dce24d5b43 | ||
|
|
b45ae62791 | ||
|
|
b0485bafdd | ||
|
|
3b52a8950f | ||
|
|
e60f66e023 | ||
|
|
2a68582676 | ||
|
|
b7ebda0f15 | ||
|
|
7b2289a1c5 | ||
|
|
377bb87ad5 | ||
|
|
180ca01c97 | ||
|
|
a6dede8199 | ||
|
|
25b915308a | ||
|
|
079871ffac | ||
|
|
4d62627668 | ||
|
|
2b88759f43 | ||
|
|
d60968b61c | ||
|
|
5aad4ac056 | ||
|
|
2ef70e02a5 | ||
|
|
f525a18239 | ||
|
|
5c2dd21508 | ||
|
|
6d9aaff58a | ||
|
|
db72b0477d | ||
|
|
1f08b38461 | ||
|
|
8cffb15e1e | ||
|
|
3f1590bce7 | ||
|
|
37e5c6513c | ||
|
|
7585187d1c | ||
|
|
8764a5b3dd | ||
|
|
9f9feca70c | ||
|
|
d268106bf8 | ||
|
|
1874018c12 | ||
|
|
d78a0ca53f | ||
|
|
d1ef6369d9 | ||
|
|
040481760c | ||
|
|
e848363029 | ||
|
|
8ce9826d98 | ||
|
|
5fa7ae14b9 | ||
|
|
e3358e0925 | ||
|
|
13a1f3daaa | ||
|
|
3a95ba8559 | ||
|
|
0871d0b0a6 | ||
|
|
7edd340995 | ||
|
|
8633d7532d | ||
|
|
03acfa57a2 | ||
|
|
9be0996062 | ||
|
|
71231fb2ae | ||
|
|
526c72cb4b | ||
|
|
ff5031db9e | ||
|
|
581558868d | ||
|
|
96484ac57f | ||
|
|
7de4a7046a | ||
|
|
3b7ca04408 | ||
|
|
473648ce6c | ||
|
|
426636b1d0 | ||
|
|
cb322cfa86 | ||
|
|
51d3030a1f | ||
|
|
26f1b6d237 | ||
|
|
5ed197748e | ||
|
|
79a523390f | ||
|
|
f01b7b5013 | ||
|
|
f855cb31d1 | ||
|
|
99c2dd9cbc | ||
|
|
36807a438a | ||
|
|
f83e887d53 | ||
|
|
57d991c36b | ||
|
|
072bbee63e | ||
|
|
a3cc3a016c | ||
|
|
669f652f4d | ||
|
|
c61f3a97e2 | ||
|
|
349ec68c0f | ||
|
|
2eb9f1eb86 | ||
|
|
7ab14ac4a3 | ||
|
|
0183e3feb8 | ||
|
|
a0c23a608a | ||
|
|
610c3ae071 | ||
|
|
b2903a5d14 | ||
|
|
81f3a78b8a | ||
|
|
56c17adf7e | ||
|
|
e5224ee27a | ||
|
|
d77affc6f5 | ||
|
|
984ec57446 | ||
|
|
e96516d10d | ||
|
|
907e827046 | ||
|
|
609d1a7be0 | ||
|
|
d19a2499cd | ||
|
|
08619ef517 | ||
|
|
5141adee96 | ||
|
|
1e84b978b2 | ||
|
|
a0f216bb2b | ||
|
|
2de04292da | ||
|
|
c50428f612 | ||
|
|
b4348b3cff | ||
|
|
fea3e33128 | ||
|
|
d60a11a75b | ||
|
|
cfd93c7747 | ||
|
|
6d8c0676a1 | ||
|
|
343230cd78 | ||
|
|
44080a444c | ||
|
|
6d7bc558d0 | ||
|
|
65681f4033 | ||
|
|
d345533596 | ||
|
|
007738d22c | ||
|
|
6ddf6a8acf | ||
|
|
f9e97a68bb | ||
|
|
44d410f067 | ||
|
|
48ceff1e65 | ||
|
|
883637e0f4 | ||
|
|
3c01e39481 | ||
|
|
eef7293932 | ||
|
|
b65b2f3fea | ||
|
|
d70e1aad77 | ||
|
|
2272e9e3f5 | ||
|
|
d259e0fde4 | ||
|
|
ac99313228 | ||
|
|
7069c97a8b | ||
|
|
3b5d0c8d7f | ||
|
|
d2498547a7 | ||
|
|
c91c9e6d52 | ||
|
|
e47081faa7 | ||
|
|
b86f9eda93 | ||
|
|
4d26e4a07f | ||
|
|
f329ba3540 | ||
|
|
adbd9c8d4c | ||
|
|
b12858610a | ||
|
|
3ebd3b6bce | ||
|
|
f247ef75cd | ||
|
|
f67e6d4417 | ||
|
|
517f1efc56 | ||
|
|
db160fa8c5 | ||
|
|
983fb2e686 | ||
|
|
f794d5a9d1 | ||
|
|
e3f586836a | ||
|
|
82e2c82e95 | ||
|
|
3479524845 | ||
|
|
178e0661ab | ||
|
|
b94c36f960 | ||
|
|
9f7e37c892 | ||
|
|
e7d6055ed3 | ||
|
|
75d5ebbea5 | ||
|
|
9969ec8504 | ||
|
|
995033cf20 | ||
|
|
d5da7a4dda | ||
|
|
659d309206 | ||
|
|
847dcbf237 | ||
|
|
35d25851ce | ||
|
|
5ffca91e60 | ||
|
|
51e6e654e3 | ||
|
|
71bc9c855d | ||
|
|
f3492f8da0 | ||
|
|
3c25ad09ce | ||
|
|
a2e037bb54 | ||
|
|
a4a21b1c12 | ||
|
|
e9ce83b399 | ||
|
|
c2b207faa4 | ||
|
|
c3a007e88b | ||
|
|
68abb96818 | ||
|
|
29c3b48da0 | ||
|
|
9c1c372067 | ||
|
|
13713f3b9c | ||
|
|
776d42f6cb | ||
|
|
b20ea9ebb1 | ||
|
|
46c1ae6f96 | ||
|
|
f02f23eff5 | ||
|
|
fb0317ec7d | ||
|
|
417a2d8a46 | ||
|
|
ce7f2b09cc | ||
|
|
e6226a95ba | ||
|
|
aa221d02b5 | ||
|
|
5a7d8eca6f | ||
|
|
de4ee72554 | ||
|
|
ad5ea75ddd | ||
|
|
dd1b5282b2 | ||
|
|
45321f0570 | ||
|
|
4e83359537 | ||
|
|
961a0689f3 | ||
|
|
bafc9f43a5 | ||
|
|
ab3da91e67 | ||
|
|
6ee1c88869 | ||
|
|
b98d022d40 | ||
|
|
f2d6d99d54 | ||
|
|
aeb54ddbe5 | ||
|
|
2fb41edf1a | ||
|
|
4d385bedd3 | ||
|
|
03a2ea4612 | ||
|
|
c290fc5f98 | ||
|
|
23861b9608 | ||
|
|
24fd5953c9 | ||
|
|
8f51d9c4a7 | ||
|
|
5dcc5f6d26 | ||
|
|
70a4ce8eb3 | ||
|
|
8207b88e97 | ||
|
|
de7e354a8e | ||
|
|
981e993d40 | ||
|
|
bad686d620 | ||
|
|
2f1b1c4d44 | ||
|
|
d8f24d9183 | ||
|
|
0fa843532e | ||
|
|
7b49f3f354 | ||
|
|
e6f876e830 | ||
|
|
285d35f43f | ||
|
|
a18dfa1fea | ||
|
|
f5ccff5b6e | ||
|
|
4329e5be07 | ||
|
|
962ef813b4 | ||
|
|
1c51b5d9b8 | ||
|
|
a9706f0745 | ||
|
|
8e718893e5 | ||
|
|
f56bc930bc | ||
|
|
f1dec7935f | ||
|
|
732f8c7458 | ||
|
|
dd66147e07 | ||
|
|
aebbcda3fe | ||
|
|
5b4d230d4a | ||
|
|
48a2a960da | ||
|
|
728c8f9507 | ||
|
|
d0db967e3b | ||
|
|
6b174a3419 | ||
|
|
d40e0faceb | ||
|
|
0a71259442 | ||
|
|
aa2fea2250 | ||
|
|
a759fc693d | ||
|
|
9813c81ef3 | ||
|
|
65989edb97 | ||
|
|
1c85a84474 | ||
|
|
c86ef1721c | ||
|
|
e2b9ce78c2 | ||
|
|
576231942d | ||
|
|
9b4c86dbd4 | ||
|
|
82eed2ca6d | ||
|
|
56016e8348 | ||
|
|
b6b6a6944a | ||
|
|
dfb64a5af5 | ||
|
|
711bcae5d7 | ||
|
|
ed9ce65eb8 | ||
|
|
d7010f9924 | ||
|
|
b64aad9869 | ||
|
|
739f8eeb81 | ||
|
|
eead731177 | ||
|
|
c689b6205c | ||
|
|
03431ae64f | ||
|
|
c33b4bafbb | ||
|
|
13959e3a5e | ||
|
|
3556f298c7 | ||
|
|
091e8c8088 | ||
|
|
14deba107f | ||
|
|
eda6b64491 | ||
|
|
ef81bd2e0b | ||
|
|
ee24ff8dd1 | ||
|
|
99e2867a21 | ||
|
|
6805c7fcb6 | ||
|
|
24b1636615 | ||
|
|
dfe39c630f | ||
|
|
c67f4b08a0 | ||
|
|
5c51abc92f | ||
|
|
a1460b6b0d | ||
|
|
02f3290765 | ||
|
|
078bd570c8 | ||
|
|
b1991924b7 | ||
|
|
fa1965a87c | ||
|
|
d00933d5f4 | ||
|
|
81fe14fda2 | ||
|
|
13d293829c | ||
|
|
a6d5b5e576 | ||
|
|
1063638763 | ||
|
|
5f0eeeff66 | ||
|
|
e63257ff7f | ||
|
|
39c23ddf5a | ||
|
|
3ee73c866d | ||
|
|
584b9c2d29 | ||
|
|
349f59d92d | ||
|
|
a02f0ec577 | ||
|
|
e99ec0a283 | ||
|
|
5920e4c7af | ||
|
|
13f3d7ed87 | ||
|
|
738ab19573 | ||
|
|
510e66aef7 | ||
|
|
19c590a881 | ||
|
|
395e3d786b | ||
|
|
fdc0cbcd8c | ||
|
|
f27a2921da | ||
|
|
bb32aa3164 | ||
|
|
32229388f5 | ||
|
|
70b887a7bd | ||
|
|
28bf345c96 | ||
|
|
6a1eed0fa8 | ||
|
|
c4d5488f7a | ||
|
|
24a22b66ef | ||
|
|
9579dc2056 | ||
|
|
89e694cc56 | ||
|
|
047205fbbd | ||
|
|
23e7135f2c | ||
|
|
333365aefe | ||
|
|
d4cff01c72 | ||
|
|
5f7dc381c7 | ||
|
|
ea0bc01400 | ||
|
|
3bc883d114 | ||
|
|
2e2850ff94 | ||
|
|
1a8019f499 | ||
|
|
bf4b38b0af | ||
|
|
f78b10a450 | ||
|
|
603689372c | ||
|
|
5b05d6a8c8 | ||
|
|
12c0fe14cd | ||
|
|
ace2b8f89e | ||
|
|
24188f295c | ||
|
|
653671bc0e | ||
|
|
c251497758 | ||
|
|
69435fa44e | ||
|
|
6bc6fcab9a | ||
|
|
50bac8c0eb | ||
|
|
d709d4707c | ||
|
|
879db6841d | ||
|
|
2ce385b949 | ||
|
|
21458fcc67 | ||
|
|
d83b7ddc0f | ||
|
|
5ee3e8d04b | ||
|
|
dcafe1e17d | ||
|
|
8dfa7c2e42 | ||
|
|
c83d30f526 | ||
|
|
51b367df53 | ||
|
|
da83662e1a | ||
|
|
36861e5b67 | ||
|
|
67df4dd84e | ||
|
|
676521808d | ||
|
|
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 |
312
.travis.yml
Normal file
312
.travis.yml
Normal file
@@ -0,0 +1,312 @@
|
||||
# Copyright 2016, 2017 Peter Dimov
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
language: cpp
|
||||
|
||||
os: linux
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- /feature\/.*/
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- BOGUS_JOB=true
|
||||
|
||||
matrix:
|
||||
|
||||
exclude:
|
||||
- env: BOGUS_JOB=true
|
||||
|
||||
include:
|
||||
- os: linux
|
||||
compiler: g++-4.4
|
||||
env: TOOLSET=gcc CXXSTD=98,0x HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.4
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-4.6
|
||||
env: TOOLSET=gcc CXXSTD=98,0x HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.6
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-4.7
|
||||
env: TOOLSET=gcc CXXSTD=03,11 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-4.8
|
||||
env: TOOLSET=gcc CXXSTD=03,11 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-4.9
|
||||
env: TOOLSET=gcc CXXSTD=03,11 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-4.9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-5
|
||||
env: TOOLSET=gcc CXXSTD=03
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-5
|
||||
env: TOOLSET=gcc CXXSTD=11
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-5
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-6
|
||||
env: TOOLSET=gcc CXXSTD=14,1z HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-6
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-7
|
||||
env: TOOLSET=gcc CXXSTD=14,17 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-8
|
||||
env: TOOLSET=gcc CXXSTD=14,17 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-9
|
||||
env: TOOLSET=gcc CXXSTD=14
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: g++-9
|
||||
env: TOOLSET=gcc CXXSTD=17
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- g++-9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
dist: trusty
|
||||
compiler: clang++-3.5
|
||||
env: TOOLSET=clang CXXSTD=03,11 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.5
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.6
|
||||
env: TOOLSET=clang CXXSTD=03,11,14 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.6
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.7
|
||||
env: TOOLSET=clang CXXSTD=03,11,14 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.8
|
||||
env: TOOLSET=clang CXXSTD=03,11,14 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-3.9
|
||||
env: TOOLSET=clang CXXSTD=03,11,14,1z HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-3.9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-4.0
|
||||
env: TOOLSET=clang CXXSTD=03,11,14,1z HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-4.0
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-5.0
|
||||
env: TOOLSET=clang CXXSTD=03,11,14,1z HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-5.0
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-6.0
|
||||
env: TOOLSET=clang CXXSTD=14,17 HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-6.0
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-7
|
||||
env: TOOLSET=clang CXXSTD=14,17,2a HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-7
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-7
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-8
|
||||
env: TOOLSET=clang CXXSTD=14,17,2a HEADERS_ONLY=1
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-8
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-xenial-8
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-9
|
||||
env: TOOLSET=clang CXXSTD=14
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
|
||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
|
||||
- os: linux
|
||||
compiler: clang++-9
|
||||
env: TOOLSET=clang CXXSTD=17
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- clang-9
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
|
||||
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
|
||||
|
||||
- os: osx
|
||||
compiler: clang++
|
||||
env: TOOLSET=clang CXXSTD=98
|
||||
|
||||
# - os: osx
|
||||
# compiler: clang++
|
||||
# env: TOOLSET=clang CXXSTD=11
|
||||
|
||||
# - os: osx
|
||||
# compiler: clang++
|
||||
# env: TOOLSET=clang CXXSTD=14
|
||||
|
||||
- os: osx
|
||||
compiler: clang++
|
||||
env: TOOLSET=clang CXXSTD=1z
|
||||
|
||||
install:
|
||||
- GIT_FETCH_JOBS=8
|
||||
- BOOST_BRANCH=develop
|
||||
- if [ "$TRAVIS_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
|
||||
- cd ..
|
||||
- git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule init tools/build
|
||||
- git submodule init libs/config
|
||||
- git submodule init tools/boostdep
|
||||
- git submodule update --jobs $GIT_FETCH_JOBS
|
||||
- mkdir -p libs/thread
|
||||
- cp -r $TRAVIS_BUILD_DIR/* libs/thread
|
||||
- python tools/boostdep/depinst/depinst.py --git_args "--jobs $GIT_FETCH_JOBS" thread
|
||||
- ./bootstrap.sh
|
||||
- ./b2 headers
|
||||
|
||||
script:
|
||||
- |-
|
||||
echo "using $TOOLSET : : $TRAVIS_COMPILER ;" > ~/user-config.jam
|
||||
- ./b2 -j3 -l60 libs/thread/test${HEADERS_ONLY:+//test_self_contained_headers} toolset=$TOOLSET cxxstd=$CXXSTD
|
||||
|
||||
notifications:
|
||||
email:
|
||||
on_success: always
|
||||
@@ -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).
|
||||
|
||||
|
||||
|
||||
89
appveyor.yml
Normal file
89
appveyor.yml
Normal file
@@ -0,0 +1,89 @@
|
||||
# Copyright 2016-2018 Peter Dimov
|
||||
# Copyright 2018 Vicente Botet
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
version: 1.0.{build}-{branch}
|
||||
|
||||
shallow_clone: true
|
||||
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- develop
|
||||
- /feature\/.*/
|
||||
|
||||
image: Visual Studio 2015
|
||||
|
||||
environment:
|
||||
matrix:
|
||||
|
||||
- TOOLSET: msvc-12.0
|
||||
VARIANT: release
|
||||
|
||||
- TOOLSET: msvc-14.0
|
||||
ADDRMD: 32
|
||||
VARIANT: debug
|
||||
|
||||
- TOOLSET: msvc-14.1
|
||||
ADDRMD: 64
|
||||
VARIANT: release
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
|
||||
- TOOLSET: msvc-14.2
|
||||
CXXSTD: 17
|
||||
ADDRMD: 32
|
||||
VARIANT: debug
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
|
||||
- TOOLSET: msvc-14.2
|
||||
ADDRMD: 64
|
||||
VARIANT: release
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
|
||||
- ADDPATH: C:\cygwin\bin;
|
||||
TOOLSET: gcc
|
||||
VARIANT: release
|
||||
|
||||
- ADDPATH: C:\mingw\bin;
|
||||
TOOLSET: gcc
|
||||
VARIANT: debug
|
||||
|
||||
# The following configurations fail with
|
||||
# ./boost/thread/detail/invoke.hpp:101:43: internal compiler error: in gimplify_expr, at gimplify.c:12039
|
||||
# https://sourceforge.net/p/mingw-w64/bugs/694/
|
||||
#
|
||||
# - ADDPATH: C:\cygwin64\bin;
|
||||
# TOOLSET: gcc
|
||||
# VARIANT: debug
|
||||
# - ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin;
|
||||
# TOOLSET: gcc
|
||||
# VARIANT: debug
|
||||
# - ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
# TOOLSET: gcc
|
||||
# VARIANT: debug,release
|
||||
|
||||
install:
|
||||
- set GIT_FETCH_JOBS=8
|
||||
- set BOOST_BRANCH=develop
|
||||
- if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master
|
||||
- cd ..
|
||||
- git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
- cd boost-root
|
||||
- git submodule init tools/build
|
||||
- git submodule init libs/config
|
||||
- git submodule init tools/boostdep
|
||||
- git submodule update --jobs %GIT_FETCH_JOBS%
|
||||
- xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\thread
|
||||
- python tools/boostdep/depinst/depinst.py --git_args "--jobs %GIT_FETCH_JOBS%" thread
|
||||
- cmd /c bootstrap
|
||||
- b2 -d0 headers
|
||||
|
||||
build: off
|
||||
|
||||
test_script:
|
||||
- PATH=%ADDPATH%%PATH%
|
||||
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
- if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
- if not "%VARIANT%" == "" set VARIANT=variant=%VARIANT%
|
||||
- b2 -j2 --abbreviate-paths libs/thread/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% %VARIANT%
|
||||
@@ -17,7 +17,7 @@
|
||||
# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
|
||||
# paths in site-config.jam, user-config.jam or in the environment.
|
||||
# A new feature is provided to request a specific API:
|
||||
# <threadapi>win32 and <threadapi)pthread.
|
||||
# <threadapi>win32 and <threadapi>pthread.
|
||||
#
|
||||
# The naming of the resulting libraries is mostly the same for the
|
||||
# variant native to the build platform, i.e.
|
||||
@@ -33,10 +33,12 @@
|
||||
#########################################################################
|
||||
|
||||
import os ;
|
||||
import feature ;
|
||||
import indirect ;
|
||||
import path ;
|
||||
import configure ;
|
||||
import threadapi-feature ;
|
||||
|
||||
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
@@ -52,7 +54,6 @@ project boost/thread
|
||||
#<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
|
||||
<library>/boost/system//boost_system
|
||||
#-pedantic -ansi -std=gnu++0x -Wextra -fpermissive
|
||||
<warnings>all
|
||||
<toolset>gcc:<cxxflags>-Wextra
|
||||
@@ -60,30 +61,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 +123,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)
|
||||
@@ -128,21 +139,8 @@ project boost/thread
|
||||
#<define>BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
#<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
<library>/boost/system//boost_system
|
||||
;
|
||||
|
||||
local rule default_threadapi ( )
|
||||
{
|
||||
local api = pthread ;
|
||||
if [ os.name ] = "NT" { api = win32 ; }
|
||||
return $(api) ;
|
||||
}
|
||||
|
||||
feature.feature threadapi : pthread win32 : propagated ;
|
||||
feature.set-default threadapi : [ default_threadapi ] ;
|
||||
|
||||
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
|
||||
|
||||
rule tag ( name : type ? : property-set )
|
||||
{
|
||||
local result = $(name) ;
|
||||
@@ -152,7 +150,7 @@ rule tag ( name : type ? : property-set )
|
||||
local api = [ $(property-set).get <threadapi> ] ;
|
||||
|
||||
# non native api gets additional tag
|
||||
if $(api) != [ default_threadapi ] {
|
||||
if $(api) != [ threadapi-feature.get-default $(property-set) ] {
|
||||
result = $(result)_$(api) ;
|
||||
}
|
||||
}
|
||||
@@ -238,6 +236,10 @@ rule usage-requirements ( properties * )
|
||||
# in that case?
|
||||
}
|
||||
}
|
||||
if <threadapi>win32 in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_WIN32 ;
|
||||
}
|
||||
|
||||
#if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.1 in $(properties)
|
||||
#{
|
||||
@@ -272,6 +274,10 @@ rule requirements ( properties * )
|
||||
result += <library>/boost/atomic//boost_atomic ;
|
||||
}
|
||||
} else {
|
||||
if <threadapi>win32 in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_WIN32 ;
|
||||
}
|
||||
result += <define>BOOST_THREAD_USES_CHRONO ;
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
@@ -284,6 +290,7 @@ alias thread_sources
|
||||
win32/thread.cpp
|
||||
win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp
|
||||
win32/thread_primitives.cpp
|
||||
future.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>win32
|
||||
@@ -308,3 +315,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;
|
||||
}
|
||||
|
||||
177
circle.yml
Normal file
177
circle.yml
Normal file
@@ -0,0 +1,177 @@
|
||||
# Copyright 2018 Tom Hughes
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
|
||||
|
||||
build_steps: &build_steps
|
||||
steps:
|
||||
- run:
|
||||
name: Setup
|
||||
command: |
|
||||
PLATFORM=`uname`
|
||||
if [ "${PLATFORM}" == "Linux" ]; then
|
||||
sudo apt-get install -y software-properties-common apt-transport-https
|
||||
|
||||
# https://github.com/ilikenwf/apt-fast
|
||||
sudo add-apt-repository -y ppa:apt-fast/stable
|
||||
sudo apt-get update
|
||||
sudo apt-get -y install apt-fast
|
||||
|
||||
sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
|
||||
echo "deb https://apt.llvm.org/trusty/ llvm-toolchain-trusty-4.0 main" | sudo tee -a /etc/apt/sources.list
|
||||
echo "deb https://apt.llvm.org/trusty/ llvm-toolchain-trusty-5.0 main" | sudo tee -a /etc/apt/sources.list
|
||||
echo "deb https://apt.llvm.org/trusty/ llvm-toolchain-trusty-6.0 main" | sudo tee -a /etc/apt/sources.list
|
||||
sudo apt-fast update
|
||||
sudo apt-fast install -y $COMPILER
|
||||
fi
|
||||
- checkout
|
||||
- run:
|
||||
name: Install
|
||||
command: |
|
||||
BOOST_BRANCH=develop && [ "$CIRCLE_BRANCH" == "master" ] && BOOST_BRANCH=master || true
|
||||
cd ..
|
||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
||||
cd boost-root
|
||||
git submodule update --init tools/build
|
||||
git submodule update --init libs/config
|
||||
git submodule update --init tools/boostdep
|
||||
mkdir -p libs/thread
|
||||
cp -r $HOME/project/* libs/thread
|
||||
python tools/boostdep/depinst/depinst.py thread
|
||||
./bootstrap.sh
|
||||
./b2 headers
|
||||
- run:
|
||||
name: Build
|
||||
command: |
|
||||
echo "using $TOOLSET : : $COMPILER : <cxxflags>-std=$CXXSTD <cxxflags>$CXXFLAGS <cxxflags>$DEFINES ;" > ~/user-config.jam
|
||||
cd ../boost-root
|
||||
./b2 -d2 -j8 -l60 libs/thread/test toolset=$TOOLSET
|
||||
|
||||
mac_build: &mac_build
|
||||
macos:
|
||||
xcode: "9.2.0"
|
||||
<<: *build_steps
|
||||
|
||||
linux_build: &linux_build
|
||||
docker:
|
||||
- image: circleci/buildpack-deps:trusty
|
||||
<<: *build_steps
|
||||
|
||||
|
||||
version: 2
|
||||
jobs:
|
||||
linux-g++-c++11:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "gcc"
|
||||
- COMPILER: "g++"
|
||||
- CXXSTD: "c++11"
|
||||
|
||||
linux-g++-7-c++98:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "gcc"
|
||||
- COMPILER: "g++-7"
|
||||
- CXXSTD: "c++98"
|
||||
|
||||
linux-g++-7-c++11:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "gcc"
|
||||
- COMPILER: "g++-7"
|
||||
- CXXSTD: "c++11"
|
||||
|
||||
linux-g++-7-c++14:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "gcc"
|
||||
- COMPILER: "g++-7"
|
||||
- CXXSTD: "c++14"
|
||||
|
||||
linux-g++-7-c++1z:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "gcc"
|
||||
- COMPILER: "g++-7"
|
||||
- CXXSTD: "c++1z"
|
||||
|
||||
linux-clang++-4.0-c++98:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++-4.0"
|
||||
- CXXSTD: "c++98"
|
||||
|
||||
linux-clang++-4.0-c++11:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++-4.0"
|
||||
- CXXSTD: "c++11"
|
||||
|
||||
linux-clang++-4.0-c++14:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++-4.0"
|
||||
- CXXSTD: "c++14"
|
||||
|
||||
linux-clang++-4.0-c++1z:
|
||||
<<: *linux_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++-4.0"
|
||||
- CXXSTD: "c++1z"
|
||||
|
||||
mac-clang++-c++98:
|
||||
<<: *mac_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++"
|
||||
- CXXSTD: "c++98"
|
||||
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
|
||||
|
||||
mac-clang++-c++11:
|
||||
<<: *mac_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++"
|
||||
- CXXSTD: "c++11"
|
||||
- CXXFLAGS: "-Wno-unusable-partial-specialization"
|
||||
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
|
||||
|
||||
mac-clang++-c++14:
|
||||
<<: *mac_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++"
|
||||
- CXXSTD: "c++14"
|
||||
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
|
||||
|
||||
mac-clang++-c++1z:
|
||||
<<: *mac_build
|
||||
environment:
|
||||
- TOOLSET: "clang"
|
||||
- COMPILER: "clang++"
|
||||
- CXXSTD: "c++1z"
|
||||
- CXXFLAGS: "-Wno-unusable-partial-specialization"
|
||||
- DEFINES: "-DBOOST_THREAD_TEST_TIME_MS=100"
|
||||
|
||||
workflows:
|
||||
version: 2
|
||||
continous:
|
||||
jobs:
|
||||
- linux-g++-c++11
|
||||
- linux-g++-7-c++98
|
||||
- linux-g++-7-c++11
|
||||
- linux-g++-7-c++14
|
||||
- linux-g++-7-c++1z
|
||||
- linux-clang++-4.0-c++98
|
||||
- linux-clang++-4.0-c++11
|
||||
- linux-clang++-4.0-c++14
|
||||
- linux-clang++-4.0-c++1z
|
||||
- mac-clang++-c++98
|
||||
- mac-clang++-c++11
|
||||
- mac-clang++-c++14
|
||||
- mac-clang++-c++1z
|
||||
|
||||
@@ -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).
|
||||
|
||||
317
doc/changes.qbk
317
doc/changes.qbk
@@ -1,6 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-14 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-18 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,314 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[heading Version 4.9.0 - boost 1.70]
|
||||
|
||||
[*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/10964 #10964] future<future<T>>::unwrap().then() Deadlocks
|
||||
|
||||
|
||||
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 master regression test] to see the last regression test snapshot.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@https://github.com/boostorg/thread/pull/268] Add self contained header tests and fix discovered bugs
|
||||
|
||||
* Improvements support for cygwin platform using the pthread interface.
|
||||
* [@https://github.com/boostorg/thread/pull/263] Fix compilation of timed functions on Cygwin
|
||||
$ [@https://github.com/boostorg/thread/pull/262] Fix MinGW warnings about violation of the strict aliasing rules
|
||||
|
||||
* [@https://github.com/boostorg/thread/pull/260] Fix "interruption_point" defined twice.
|
||||
|
||||
* [@https://github.com/boostorg/thread/pull/249] Simplify TSS cleanup routines. Fixes #236
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* Since BOOST_THREAD_VERSION 5, BOOST_THREAD_USES_EXECUTOR is defined by default.
|
||||
* [@https://github.com/boostorg/thread/pull/266] Remove linking with Boost.System
|
||||
|
||||
[heading Version 4.8.1 - boost 1.67]
|
||||
|
||||
[*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/10964 #10964] future<future<T>>::unwrap().then() Deadlocks
|
||||
|
||||
|
||||
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 master regression test] to see the last regression test snapshot.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
|
||||
* [@https://github.com/boostorg/thread/issues/162 #162] fix as much time-related issues as possible and improve the QOI
|
||||
* [@https://github.com/boostorg/thread/issues/193 #193] future_then unit test contains two different implementations of do_continuation function
|
||||
* [@https://github.com/boostorg/thread/issues/209 #209] Legal problem with `win32/thread_primitives.hpp`
|
||||
|
||||
|
||||
[heading Version 4.8.0 - boost 1.66]
|
||||
|
||||
[*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/10964 #10964] future<future<T>>::unwrap().then() Deadlocks
|
||||
|
||||
|
||||
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 master regression test] to see the last regression test snapshot.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12323 #12323] windows - boost/thread/win32/mfc_thread_init.hpp has wrong signature for _pRawDllMainOrig
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12730 #12730] windows - static threads library is incompatible with MSVC 2017 RC
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12976 #12976] Boost Thread Executors documentation mistakes
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12949 #12949] using sleep_for in a thread context without including boost/thread/thread.hpp yields incorrect behaviour when BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC is defined
|
||||
* [@http://svn.boost.org/trac/boost/ticket/13019 #13019] ABI compatibility for BOOST_THREAD_PROVIDES_INTERRUPTIONS incomplete
|
||||
* [@http://svn.boost.org/trac/boost/ticket/13069 #13069] Boost unit test "sync_pq_multi_thread_p_lib.exe" hung in thread library
|
||||
* [@http://svn.boost.org/trac/boost/ticket/13163 #13163] boost::detail::heap_new does not have a variadic variant
|
||||
* [@http://svn.boost.org/trac/boost/ticket/13226 #13226] getpagesize() is deprecated since 199506L
|
||||
|
||||
* [@https://github.com/boostorg/thread/issues/132 #132] VS 2017.4 Preview deadlocks on Test 10964
|
||||
* [@https://github.com/boostorg/thread/issues/133 #133] windows - Spurious timing test failures on windows
|
||||
* [@https://github.com/boostorg/thread/issues/134 #134] VS 2017.4 Preview deadlock in sync_pq_multi_thread_p_lib.exe
|
||||
* [@https://github.com/boostorg/thread/issues/135 #135] VS 2017.4 Preview test_scheduled_tp_p.exe deadlock
|
||||
* [@https://github.com/boostorg/thread/issues/136 #136] VS 2017.4 Preview test_scheduler_p.exe deadlock
|
||||
* [@https://github.com/boostorg/thread/issues/137 #137] VS 2017.4 Preview executor_ex.exe deadlock
|
||||
* [@https://github.com/boostorg/thread/issues/143 #143] Failures on msvc-12.0
|
||||
* [@https://github.com/boostorg/thread/issues/145 #145] Clang build error with BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@https://github.com/boostorg/thread/issues/116 #116] [Proposal] Add APIs for deferred set_value/exception
|
||||
|
||||
[heading Version 4.7.5 - boost 1.65.1]
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@https://github.com/boostorg/thread/issues/130 #130] windows: Bug in boost::condition_variable on Windows
|
||||
|
||||
[heading Version 4.7.4 - boost 1.65]
|
||||
|
||||
[*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/12519 #12519] boost::thread::try_join_for does not return after timeout
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12874 #12874] future<> extension constructor must be under BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12888 #12888] Linking with boost thread does not work on mingw/gcc 4.4
|
||||
* [@http://svn.boost.org/trac/boost/ticket/12958 #12958] sync_bounded_queue::wait_pull_front( lve ) might throw
|
||||
* [@http://svn.boost.org/trac/boost/ticket/13077 #13077] Linking to static 64bit libboost_thread fails DLL initialization
|
||||
* [@http://svn.boost.org/trac/boost/ticket/13155 #13155] log doesn't build on a system with pthreads
|
||||
|
||||
* [@https://github.com/boostorg/thread/issues/121 #121] on_tls_prepare is broken under VS2017
|
||||
|
||||
[heading Version 4.7.3 - boost 1.64]
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@https://github.com/boostorg/thread/issues/113 #113] Add a Thread template on all the scoped thread and thread guard classes
|
||||
* [@https://github.com/boostorg/thread/issues/117 #117] loop_executor should block on it's work_queue instead of polling
|
||||
* [@https://github.com/boostorg/thread/issues/119 #119] basic_condition_variable::relocker::~relocker can throw an exception
|
||||
|
||||
[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 master 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 +332,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 +866,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 +873,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).
|
||||
@@ -10,36 +10,37 @@
|
||||
|
||||
|
||||
[table Default Values for Configurable Features
|
||||
[[Feature] [Anti-Feature] [V2] [V3] [V4] ]
|
||||
[[USES_CHRONO] [DONT_USE_CHRONO] [YES/NO] [YES/NO] [YES/NO] ]
|
||||
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ]
|
||||
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ]
|
||||
[[Feature] [Anti-Feature] [V2] [V3] [V4] [V5] ]
|
||||
[[USES_CHRONO] [DONT_USE_CHRONO] [YES/NO] [YES/NO] [YES/NO] [YES/NO] ]
|
||||
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] [YES] ]
|
||||
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] [NO] ]
|
||||
|
||||
|
||||
|
||||
[[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] ]
|
||||
[[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] [NO] ]
|
||||
|
||||
[[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] [YES] ]
|
||||
|
||||
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] ]
|
||||
[[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] ]
|
||||
[[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] ]
|
||||
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_EXECUTORS] [-] [NO] [NO] [NO] [YES] ]
|
||||
[[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] [YES] ]
|
||||
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] [YES] ]
|
||||
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] [YES] ]
|
||||
|
||||
[[USES_DATETIME] [DONT_USE_DATETIME] [YES/NO] [YES/NO] [YES/NO] ]
|
||||
[[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] ]
|
||||
[[PROVIDES_SIGNATURE_PACKAGED_TASK] [DONT_PROVIDE_SIGNATURE_PACKAGED_TASK] [NO] [NO] [YES] ]
|
||||
[[PROVIDES_FUTURE_INVALID_AFTER_GET] [DONT_PROVIDE_FUTURE_INVALID_AFTER_GET] [NO] [NO] [YES] ]
|
||||
[/ [[PROVIDES_FUTURE_CONTINUATION] [DONT_PROVIDE_FUTURE_CONTINUATION] [NO] [NO] [YES] ] ]
|
||||
[[USES_DATETIME] [DONT_USE_DATETIME] [YES/NO] [YES/NO] [YES/NO] [YES/NO] ]
|
||||
[[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] [NO] ]
|
||||
[[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] [NO] ]
|
||||
[[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] [NO] ]
|
||||
[[PROVIDES_SIGNATURE_PACKAGED_TASK] [DONT_PROVIDE_SIGNATURE_PACKAGED_TASK] [NO] [NO] [YES] [YES] ]
|
||||
[[PROVIDES_FUTURE_INVALID_AFTER_GET] [DONT_PROVIDE_FUTURE_INVALID_AFTER_GET] [NO] [NO] [YES] [YES] ]
|
||||
[/ [[PROVIDES_FUTURE_CONTINUATION] [DONT_PROVIDE_FUTURE_CONTINUATION] [NO] [NO] [YES] [YES] ] ]
|
||||
|
||||
[[PROVIDES_VARIADIC_THREAD] [DONT_PROVIDE_VARIADIC_THREAD] [NO] [NO] [C++11] ]
|
||||
[[PROVIDES_VARIADIC_THREAD] [DONT_PROVIDE_VARIADIC_THREAD] [NO] [NO] [C++11] [C++11] ]
|
||||
|
||||
]
|
||||
|
||||
@@ -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.
|
||||
@@ -178,9 +179,9 @@ When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_
|
||||
[section:shared_upwards Shared Locking Upwards Conversion]
|
||||
|
||||
Boost.Threads includes in version 3 the Shared Locking Upwards Conversion as defined in [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking].
|
||||
These conversions need to be used carefully to avoid deadlock or livelock. The user need to define explicitly `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` to get these upwards conversions.
|
||||
These conversions need to be used carefully to avoid deadlock or livelock. The user need to define explicitly `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` to get these upwards conversions.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
@@ -302,7 +303,7 @@ When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKA
|
||||
|
||||
[section:thread_const-var thread constructor with variadic rvalue parameters]
|
||||
|
||||
C++11 thread constructor accep a variable number of rvalue argumentshas. When `BOOST_THREAD_PROVIDES_VARIADIC_THREAD ` is defined Boost.Thread provides this C++ feature if the following are not defined
|
||||
C++11 thread constructor accept a variable number of rvalue arguments has. When `BOOST_THREAD_PROVIDES_VARIADIC_THREAD ` is defined Boost.Thread provides this C++ feature if the following are not defined
|
||||
|
||||
* BOOST_NO_SFINAE_EXPR
|
||||
* BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
@@ -351,7 +352,7 @@ The user can request the version 3 by defining `BOOST_THREAD_VERSION` to 3. In t
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION `
|
||||
* Conformity & Breaking change `BOOST_THREAD_PROVIDES_FUTURE`
|
||||
* Uniformity `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN`
|
||||
* Extension `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION`
|
||||
* Extension `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS`
|
||||
* Conformity `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS`
|
||||
* Conformity & Breaking change BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Conformity & Breaking change BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
|
||||
@@ -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
|
||||
@@ -342,9 +358,9 @@ The object's `name` virtual function returns a pointer to the string "future".]]
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
template<typename Ex, 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.]]
|
||||
|
||||
@@ -882,9 +898,9 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
|
||||
then(F&& func); // EXTENSION
|
||||
template<typename S, typename F>
|
||||
template<typename Ex, 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.]]
|
||||
|
||||
@@ -1359,9 +1387,9 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
|
||||
template<typename F>
|
||||
__unique_future__<typename boost::result_of<F(shared_future)>::type>
|
||||
then(F&& func) const; // EXTENSION
|
||||
template<typename S, typename F>
|
||||
template<typename Ex, 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`.
|
||||
|
||||
]]
|
||||
|
||||
@@ -1463,6 +1507,13 @@ scheduler, then the parent is filled by immediately calling `.wait()`, and the p
|
||||
|
||||
template<typename F>
|
||||
void set_wait_callback(F f); // EXTENSION
|
||||
|
||||
void set_value_deferred(see below); // EXTENSION
|
||||
void set_exception_deferred(exception_ptr p); // EXTENSION
|
||||
template <typename E>
|
||||
void set_exception_deferred(E e); // EXTENSION
|
||||
void notify_deferred(); // EXTENSION
|
||||
|
||||
};
|
||||
|
||||
[///////////////////////////////////////////////]
|
||||
@@ -1639,9 +1690,10 @@ Stores the value r in the shared state without making that state ready immediate
|
||||
Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration
|
||||
associated with the current thread have been destroyed.]]
|
||||
|
||||
[[Postconditions:] [the result associated with `*this` is set as deferred]]
|
||||
|
||||
[[Throws:] [
|
||||
- __promise_already_satisfied__ if the result associated with `*this` is already ['ready].
|
||||
- __promise_already_satisfied__ if the result associated with `*this` is already ['ready] or deferred.
|
||||
|
||||
- __broken_promise__ if `*this` has no shared state.
|
||||
|
||||
@@ -1667,11 +1719,11 @@ Stores the exception pointer p in the shared state without making that state rea
|
||||
Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration
|
||||
associated with the current thread have been destroyed.]]
|
||||
|
||||
[[Postconditions:] [All futures waiting on the shared state are ['ready] and __unique_future_has_exception__ or
|
||||
__shared_future_has_exception__ for those futures shall return `true`.]]
|
||||
[[Postconditions:] [the result associated with `*this` is set as deferred]]
|
||||
|
||||
|
||||
[[Throws:] [
|
||||
- __promise_already_satisfied__ if the result associated with `*this` is already ['ready].
|
||||
- __promise_already_satisfied__ if the result associated with `*this` is already ['ready] or deferred.
|
||||
|
||||
- __broken_promise__ if `*this` has no shared state.
|
||||
|
||||
@@ -1701,6 +1753,82 @@ or __shared_future__ associated with this result, and the result is not ['ready]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////////////////////]
|
||||
[section:set_value Member Function `set_value_deferred()` EXTENSION]
|
||||
|
||||
void set_value_deferred(R&& r);
|
||||
void set_value_deferred(const R& r);
|
||||
void promise<R&>:: set_value_deferred(R& r);
|
||||
void promise<void>:: set_value_deferred();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
- If BOOST_THREAD_PROVIDES_PROMISE_LAZY is defined and if `*this` was not associated with a result, allocate storage for a new shared state and associate it with `*this`.
|
||||
|
||||
- Stores the value `r` in the shared state without making that state ready immediately. Threads blocked waiting for the asynchronous result are not woken. They will be woken only when `notify_deferred` is called.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [the result associated with `*this` is set as deferred]]
|
||||
|
||||
[[Throws:] [
|
||||
- __promise_already_satisfied__ if the result associated with `*this` is already ['ready] or deferred.
|
||||
|
||||
- __broken_promise__ if `*this` has no shared state.
|
||||
|
||||
- `std::bad_alloc` if the memory required for storage of the result cannot be allocated.
|
||||
|
||||
- Any exception thrown by the copy or move-constructor of `R`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////////////////////////////]
|
||||
[section:set_exception Member Function `set_exception_deferred()` EXTENSION]
|
||||
|
||||
void set_exception_deferred(boost::exception_ptr e);
|
||||
template <typename E>
|
||||
void set_exception_deferred(E e); // EXTENSION
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
- If BOOST_THREAD_PROVIDES_PROMISE_LAZY is defined and if `*this` was not associated with a result, allocate storage for a new shared state and associate it with `*this`.
|
||||
|
||||
- Store the exception `e` in the shared state associated with `*this`without making that state ready immediately. Threads blocked waiting for the asynchronous result are not woken. They will be woken only when `notify_deferred` is called.]]
|
||||
|
||||
[[Postconditions:] [the result associated with `*this` is set as deferred]]
|
||||
|
||||
|
||||
[[Throws:] [
|
||||
- __promise_already_satisfied__ if the result associated with `*this` is already ['ready] or deferred.
|
||||
|
||||
- __broken_promise__ if `*this` has no shared state.
|
||||
|
||||
- `std::bad_alloc` if the memory required for storage of the result cannot be allocated.
|
||||
]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[///////////////////////////////////////////////]
|
||||
[section:set_value Member Function `notify_deferred()` EXTENSION]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
Any threads blocked waiting for the asynchronous result are woken.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [All futures waiting on the shared state are ['ready] and __unique_future_has_value__ or
|
||||
__shared_future_has_value__ for those futures shall return `true`.]]
|
||||
|
||||
[[Postconditions:] [the result associated with `*this` is ready.]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
[////////////////////////////////////////////////////]
|
||||
@@ -2362,7 +2490,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 +2499,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 +2535,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
|
||||
|
||||
|
||||
15
doc/futures.qbk
Executable file → Normal file
15
doc/futures.qbk
Executable file → Normal file
@@ -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]
|
||||
|
||||
@@ -542,7 +542,7 @@ requirements and the following expressions are well-formed and have the specifie
|
||||
* `m.__unlock_upgrade_and_lock_shared();`
|
||||
|
||||
|
||||
If `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION is defined the following expressions are also required:
|
||||
If `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS is defined the following expressions are also required:
|
||||
|
||||
* `m.__try_unlock_shared_and_lock();`
|
||||
* `m.__try_unlock_shared_and_lock_for(rel_time);`
|
||||
@@ -678,7 +678,7 @@ If the conversion is not successful, the shared ownership of m is retained.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
@@ -704,7 +704,7 @@ If the conversion is not successful, the shared ownership of the mutex is retain
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
@@ -730,7 +730,7 @@ If the conversion is not successful, the shared ownership of the mutex is retain
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
@@ -770,7 +770,7 @@ If the conversion is not successful, the shared ownership of the mutex is retain
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
@@ -797,7 +797,7 @@ If the conversion is not successful, the shared ownership of m is retained.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
|
||||
]
|
||||
@@ -823,7 +823,7 @@ If the conversion is not successful, the shared ownership of the mutex is retain
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
@@ -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()`).
|
||||
@@ -1268,7 +1268,7 @@ The following classes are models of `StrictLock`:
|
||||
unique_lock(Lockable& m_,defer_lock_t) noexcept;
|
||||
unique_lock(Lockable& m_,try_to_lock_t);
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
unique_lock(shared_lock<mutex_type>&& sl, try_to_lock_t); // C++14
|
||||
template <class Clock, class Duration>
|
||||
unique_lock(shared_lock<mutex_type>&& sl,
|
||||
@@ -1426,7 +1426,7 @@ Else `sl.__owns_lock()` returns `true`, and in this case if `sl.mutex()->try_unl
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1451,7 +1451,7 @@ Else `sl.__owns_lock_shared_ref__()` returns `true`, and in this case if `sl.mut
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1478,7 +1478,7 @@ Else `sl.owns_lock()` returns `true`, and in this case if `sl.mutex()-> __try_un
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
[[Notes:] [Available only if `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS` and `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` is defined on Windows platform]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1899,7 +1899,7 @@ __owns_lock_shared_ref__ returns `false`.]]
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void unlock();
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
// Conversion from shared locking
|
||||
upgrade_lock(shared_lock<mutex_type>&& sl, try_to_lock_t);
|
||||
template <class Clock, class Duration>
|
||||
@@ -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.]]
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
struct once_flag
|
||||
{
|
||||
constexprr once_flag() noexcept;
|
||||
constexpr once_flag() noexcept;
|
||||
once_flag(const once_flag&) = delete;
|
||||
once_flag& operator=(const once_flag&) = delete;
|
||||
};
|
||||
|
||||
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.8.0]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-14 Vicente J. Botet Escriba]
|
||||
[copyright 2011-17 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.]]
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(disable: 4355) // 'this' : used in base member initializer list
|
||||
#endif
|
||||
|
||||
using namespace boost;
|
||||
|
||||
class BankAccount
|
||||
|
||||
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
|
||||
@@ -21,6 +21,10 @@
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
int p1_ex()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
@@ -35,31 +39,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 +131,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;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,13 @@
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
@@ -41,10 +45,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)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include <string>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
@@ -58,6 +62,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 +87,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)
|
||||
{
|
||||
|
||||
@@ -20,8 +20,11 @@
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS && ! (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS && ! (defined BOOST_MSVC && _MSC_VER < 1800) // works since msvc-12.0
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
@@ -42,6 +45,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)
|
||||
{
|
||||
@@ -60,6 +71,8 @@ int main()
|
||||
}
|
||||
#else
|
||||
|
||||
//#warning "This test is not supported in this configuration, either because Bosst.Thread has been configured to don't support continuations, the compiler doesn't provides lambdas or because they are buggy as for MSV versions < msvc-12.0"
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -37,7 +37,7 @@ struct accumulate_block
|
||||
template<typename Iterator,typename T>
|
||||
T parallel_accumulate(Iterator first,Iterator last,T init)
|
||||
{
|
||||
unsigned long const length=std::distance(first,last);
|
||||
unsigned long const length=static_cast<unsigned long>(std::distance(first,last));
|
||||
|
||||
if(!length)
|
||||
return init;
|
||||
|
||||
@@ -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())
|
||||
@@ -76,14 +63,17 @@ int main()
|
||||
else
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
#if 0
|
||||
{
|
||||
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();
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::scoped_thread<> g( &f, 1, 2 );
|
||||
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 0
|
||||
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
|
||||
|
||||
85
example/this_executor.cpp
Normal file
85
example/this_executor.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// 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 5
|
||||
#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;
|
||||
}
|
||||
{
|
||||
{
|
||||
|
||||
@@ -20,6 +20,7 @@ struct func
|
||||
int& i;
|
||||
|
||||
func(int& i_):i(i_){}
|
||||
func(func const& other):i(other.i){}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_VERSION 5
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
@@ -15,9 +15,14 @@
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
|
||||
@@ -24,6 +24,7 @@ void thread_proc()
|
||||
increment();
|
||||
int* p = value.get();
|
||||
assert(*p == i+1);
|
||||
(void)(p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_VERSION 5
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
@@ -17,6 +17,10 @@
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
#include <string>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(disable: 4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
|
||||
@@ -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__ < 7) || !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__ < 7) || !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,211 @@
|
||||
#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-2017. 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/bind/bind.hpp>
|
||||
|
||||
#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/time_point.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;
|
||||
|
||||
// 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 cond_;
|
||||
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 bool not_empty_or_closed(unique_lock<mutex>& ) const;
|
||||
|
||||
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
|
||||
template <class WClock, class Duration>
|
||||
queue_op_status wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
|
||||
|
||||
inline void notify_elem_added(unique_lock<mutex>& )
|
||||
{
|
||||
cond_.notify_all();
|
||||
}
|
||||
inline void notify_elem_added(lock_guard<mutex>& )
|
||||
{
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
cond_.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>
|
||||
bool sync_deque_base<ValueType, Queue>::not_empty_or_closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return ! data_.empty() || closed_;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
cond_.wait(lk, boost::bind(&sync_deque_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk)));
|
||||
if (! empty(lk)) return false; // success
|
||||
return true; // closed
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
template <class WClock, class Duration>
|
||||
queue_op_status sync_deque_base<ValueType, Queue>::wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
|
||||
{
|
||||
if (! cond_.wait_until(lk, tp, boost::bind(&sync_deque_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk))))
|
||||
return queue_op_status::timeout;
|
||||
if (! empty(lk)) return queue_op_status::success;
|
||||
return queue_op_status::closed;
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // concurrent
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
#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-2017. 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/bind/bind.hpp>
|
||||
|
||||
#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/time_point.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;
|
||||
|
||||
// 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 cond_;
|
||||
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 bool not_empty_or_closed(unique_lock<mutex>& ) const;
|
||||
|
||||
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
|
||||
template <class WClock, class Duration>
|
||||
queue_op_status wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp);
|
||||
|
||||
inline void notify_elem_added(unique_lock<mutex>& )
|
||||
{
|
||||
cond_.notify_all();
|
||||
}
|
||||
inline void notify_elem_added(lock_guard<mutex>& )
|
||||
{
|
||||
cond_.notify_all();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
cond_.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>
|
||||
bool sync_queue_base<ValueType, Queue>::not_empty_or_closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return ! data_.empty() || closed_;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
cond_.wait(lk, boost::bind(&sync_queue_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk)));
|
||||
if (! empty(lk)) return false; // success
|
||||
return true; // closed
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
template <class WClock, class Duration>
|
||||
queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed_until(unique_lock<mutex>& lk, chrono::time_point<WClock,Duration> const&tp)
|
||||
{
|
||||
if (! cond_.wait_until(lk, tp, boost::bind(&sync_queue_base<ValueType, Queue>::not_empty_or_closed, boost::ref(*this), boost::ref(lk))))
|
||||
return queue_op_status::timeout;
|
||||
if (! empty(lk)) return queue_op_status::success;
|
||||
return queue_op_status::closed;
|
||||
}
|
||||
|
||||
} // 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,32 +123,32 @@ 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 __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#if defined __GNUC__ && ! defined __clang__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
@@ -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() {};
|
||||
};
|
||||
|
||||
104
include/boost/thread/concurrent_queues/queue_base.hpp
Executable file → Normal file
104
include/boost/thread/concurrent_queues/queue_base.hpp
Executable file → Normal file
@@ -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,31 +116,31 @@ 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 __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
#if defined __GNUC__ && ! defined __clang__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
@@ -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() {};
|
||||
};
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <exception>
|
||||
#include <boost/core/scoped_enum.hpp>
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
@@ -22,10 +24,10 @@ 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
|
||||
struct BOOST_SYMBOL_VISIBLE 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); }
|
||||
|
||||
};
|
||||
|
||||
|
||||
727
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
727
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
@@ -0,0 +1,727 @@
|
||||
#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 ((in_+capacity(lk)-out_) % 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;}
|
||||
bool is_closed = false;
|
||||
wait_until_not_empty(lk, is_closed);
|
||||
if (is_closed) {return queue_op_status::closed;}
|
||||
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 wait_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
|
||||
325
include/boost/thread/concurrent_queues/sync_deque.hpp
Normal file
325
include/boost/thread/concurrent_queues/sync_deque.hpp
Normal file
@@ -0,0 +1,325 @@
|
||||
#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_elem_added(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_elem_added(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_elem_added(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)
|
||||
{
|
||||
const 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_);
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) super::throw_if_closed(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_);
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) super::throw_if_closed(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-2017 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() const
|
||||
{
|
||||
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&);
|
||||
|
||||
template <class WClock, class Duration>
|
||||
queue_op_status pull_until(const chrono::time_point<WClock,Duration>&, ValueType&);
|
||||
template <class Rep, class Period>
|
||||
queue_op_status pull_for(const chrono::duration<Rep,Period>&, 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_elem_added(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_elem_added(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_elem_added(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_elem_added(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_);
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) super::throw_if_closed(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_);
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) super::throw_if_closed(lk);
|
||||
pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
template <class WClock, class Duration>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_until(const chrono::time_point<WClock,Duration>& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
const queue_op_status rc = super::wait_until_not_empty_or_closed_until(lk, tp);
|
||||
if (rc == queue_op_status::success) pull(lk, elem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_for(const chrono::duration<Rep,Period>& dura, T& elem)
|
||||
{
|
||||
return pull_until(chrono::steady_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)
|
||||
{
|
||||
const 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
|
||||
325
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
325
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
@@ -0,0 +1,325 @@
|
||||
#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 <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_elem_added(lk);
|
||||
}
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_elem_added(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_elem_added(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)
|
||||
{
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(elem, lk);
|
||||
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_);
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) super::throw_if_closed(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_);
|
||||
const bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) super::throw_if_closed(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
|
||||
469
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
469
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
@@ -0,0 +1,469 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014-2017 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 <algorithm> // std::min
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
// fixme: shouldn't the timepoint be configurable
|
||||
template <class T, class Clock = chrono::steady_clock, class TimePoint=typename Clock::time_point>
|
||||
struct scheduled_type
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef Clock clock;
|
||||
typedef TimePoint 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 operator <(const scheduled_type & other) const
|
||||
{
|
||||
return this->time > other.time;
|
||||
}
|
||||
}; //end struct
|
||||
|
||||
template <class Duration>
|
||||
chrono::time_point<chrono::steady_clock,Duration>
|
||||
limit_timepoint(chrono::time_point<chrono::steady_clock,Duration> const& tp)
|
||||
{
|
||||
// Clock == chrono::steady_clock
|
||||
return tp;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
chrono::time_point<Clock,Duration>
|
||||
limit_timepoint(chrono::time_point<Clock,Duration> const& tp)
|
||||
{
|
||||
// Clock != chrono::steady_clock
|
||||
// The system time may jump while wait_until() is waiting. To compensate for this and time out near
|
||||
// the correct time, we limit how long wait_until() can wait before going around the loop again.
|
||||
const chrono::time_point<Clock,Duration> tpmax(chrono::time_point_cast<Duration>(Clock::now() + chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
|
||||
return (std::min)(tp, tpmax);
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
chrono::steady_clock::time_point
|
||||
convert_to_steady_clock_timepoint(chrono::time_point<chrono::steady_clock,Duration> const& tp)
|
||||
{
|
||||
// Clock == chrono::steady_clock
|
||||
return chrono::time_point_cast<chrono::steady_clock::duration>(tp);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
chrono::steady_clock::time_point
|
||||
convert_to_steady_clock_timepoint(chrono::time_point<Clock,Duration> const& tp)
|
||||
{
|
||||
// Clock != chrono::steady_clock
|
||||
// The system time may jump while wait_until() is waiting. To compensate for this and time out near
|
||||
// the correct time, we limit how long wait_until() can wait before going around the loop again.
|
||||
const chrono::steady_clock::duration dura(chrono::duration_cast<chrono::steady_clock::duration>(tp - Clock::now()));
|
||||
const chrono::steady_clock::duration duramax(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
|
||||
return chrono::steady_clock::now() + (std::min)(dura, duramax);
|
||||
}
|
||||
|
||||
} //end detail namespace
|
||||
|
||||
template <class T, class Clock = chrono::steady_clock, class TimePoint=typename Clock::time_point>
|
||||
class sync_timed_queue
|
||||
: private sync_priority_queue<detail::scheduled_type<T, Clock, TimePoint> >
|
||||
{
|
||||
typedef detail::scheduled_type<T, Clock, TimePoint> 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:
|
||||
inline bool not_empty_and_time_reached(unique_lock<mutex>& lk) const;
|
||||
inline bool not_empty_and_time_reached(lock_guard<mutex>& lk) const;
|
||||
|
||||
bool wait_to_pull(unique_lock<mutex>&);
|
||||
queue_op_status wait_to_pull_until(unique_lock<mutex>&, TimePoint const& tp);
|
||||
template <class Rep, class Period>
|
||||
queue_op_status wait_to_pull_for(unique_lock<mutex>& lk, chrono::duration<Rep,Period> const& dura);
|
||||
|
||||
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);
|
||||
|
||||
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, class TimePoint>
|
||||
template <class Duration>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::push(const T& elem, chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
super::push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Rep, class Period>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::push(const T& elem, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
push(elem, clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Duration>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
template <class Rep, class Period>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
template <class Duration>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_push(const T& elem, chrono::time_point<clock,Duration> const& tp)
|
||||
{
|
||||
return super::try_push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_push(const T& elem, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
return try_push(elem,clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Duration>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
bool sync_timed_queue<T, Clock, TimePoint>::not_empty_and_time_reached(unique_lock<mutex>& lk) const
|
||||
{
|
||||
return ! super::empty(lk) && clock::now() >= super::data_.top().time;
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
bool sync_timed_queue<T, Clock, TimePoint>::not_empty_and_time_reached(lock_guard<mutex>& lk) const
|
||||
{
|
||||
return ! super::empty(lk) && clock::now() >= super::data_.top().time;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
bool sync_timed_queue<T, Clock, TimePoint>::wait_to_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (not_empty_and_time_reached(lk)) return false; // success
|
||||
if (super::closed(lk)) return true; // closed
|
||||
|
||||
super::wait_until_not_empty_or_closed(lk);
|
||||
|
||||
if (not_empty_and_time_reached(lk)) return false; // success
|
||||
if (super::closed(lk)) return true; // closed
|
||||
|
||||
const time_point tpmin(detail::limit_timepoint(super::data_.top().time));
|
||||
super::cond_.wait_until(lk, tpmin);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_until(unique_lock<mutex>& lk, TimePoint const& tp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
if (clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
|
||||
|
||||
super::wait_until_not_empty_or_closed_until(lk, tp);
|
||||
|
||||
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
if (clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
|
||||
|
||||
const time_point tpmin((std::min)(tp, detail::limit_timepoint(super::data_.top().time)));
|
||||
super::cond_.wait_until(lk, tpmin);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_to_pull_for(unique_lock<mutex>& lk, chrono::duration<Rep,Period> const& dura)
|
||||
{
|
||||
const chrono::steady_clock::time_point tp(chrono::steady_clock::now() + chrono::duration_cast<chrono::steady_clock::duration>(dura));
|
||||
for (;;)
|
||||
{
|
||||
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
if (chrono::steady_clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
|
||||
|
||||
super::wait_until_not_empty_or_closed_until(lk, tp);
|
||||
|
||||
if (not_empty_and_time_reached(lk)) return queue_op_status::success;
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
if (chrono::steady_clock::now() >= tp) return super::empty(lk) ? queue_op_status::timeout : queue_op_status::not_ready;
|
||||
|
||||
const chrono::steady_clock::time_point tpmin((std::min)(tp, detail::convert_to_steady_clock_timepoint(super::data_.top().time)));
|
||||
super::cond_.wait_until(lk, tpmin);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
T sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
T sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
T sync_timed_queue<T, Clock, TimePoint>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
const bool has_been_closed = wait_to_pull(lk);
|
||||
if (has_been_closed) super::throw_if_closed(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::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, class TimePoint>
|
||||
void sync_timed_queue<T, Clock, TimePoint>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
const bool has_been_closed = wait_to_pull(lk);
|
||||
if (has_been_closed) super::throw_if_closed(lk);
|
||||
pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Duration>
|
||||
queue_op_status
|
||||
sync_timed_queue<T, Clock, TimePoint>::pull_until(chrono::time_point<clock,Duration> const& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
const queue_op_status rc = wait_to_pull_until(lk, chrono::time_point_cast<typename time_point::duration>(tp));
|
||||
if (rc == queue_op_status::success) pull(lk, elem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
template <class Rep, class Period>
|
||||
queue_op_status
|
||||
sync_timed_queue<T, Clock, TimePoint>::pull_for(chrono::duration<Rep,Period> const& dura, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
const queue_op_status rc = wait_to_pull_for(lk, dura);
|
||||
if (rc == queue_op_status::success) pull(lk, elem);
|
||||
return rc;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (not_empty_and_time_reached(lk))
|
||||
{
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
if (super::empty(lk)) return queue_op_status::empty;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if (not_empty_and_time_reached(lk))
|
||||
{
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
if (super::empty(lk)) return queue_op_status::empty;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
const bool has_been_closed = wait_to_pull(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T, class Clock, class TimePoint>
|
||||
queue_op_status sync_timed_queue<T, Clock, TimePoint>::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
|
||||
|
||||
46
include/boost/thread/csbl/queue.hpp
Normal file
46
include/boost/thread/csbl/queue.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
// 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.
|
||||
#if 0
|
||||
#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
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -11,21 +11,52 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#include <boost/thread/detail/thread_safety.hpp>
|
||||
|
||||
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
// ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||
//#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||
#if !defined(BOOST_NO_MAY_ALIAS)
|
||||
|
||||
// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with
|
||||
// regard to violation of the strict aliasing rules.
|
||||
// GCC since 3.3 and some other compilers have may_alias attribute that helps
|
||||
// to alleviate optimizer issues with regard to violation of the strict aliasing rules.
|
||||
|
||||
#define BOOST_THREAD_DETAIL_USE_ATTRIBUTE_MAY_ALIAS
|
||||
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS __attribute__((__may_alias__))
|
||||
#endif
|
||||
#if defined(BOOST_MAY_ALIAS)
|
||||
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS BOOST_MAY_ALIAS
|
||||
#else
|
||||
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
|
||||
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
|
||||
# warning Boost.Thread will use the Windows API for time
|
||||
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
|
||||
# warning Boost.Thread will use the Mac API for time
|
||||
#elif defined(BOOST_THREAD_CHRONO_POSIX_API)
|
||||
# warning Boost.Thread will use the POSIX API for time
|
||||
#endif
|
||||
|
||||
# if defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API )
|
||||
# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_POSIX_API are defined
|
||||
# elif defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && defined( BOOST_THREAD_CHRONO_MAC_API )
|
||||
# error both BOOST_THREAD_CHRONO_WINDOWS_API and BOOST_THREAD_CHRONO_MAC_API are defined
|
||||
# elif defined( BOOST_THREAD_CHRONO_MAC_API ) && defined( BOOST_THREAD_CHRONO_POSIX_API )
|
||||
# error both BOOST_THREAD_CHRONO_MAC_API and BOOST_THREAD_CHRONO_POSIX_API are defined
|
||||
# elif !defined( BOOST_THREAD_CHRONO_WINDOWS_API ) && !defined( BOOST_THREAD_CHRONO_MAC_API ) && !defined( BOOST_THREAD_CHRONO_POSIX_API )
|
||||
# if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
# define BOOST_THREAD_CHRONO_WINDOWS_API
|
||||
# elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_CHRONO_MAC_API
|
||||
# else
|
||||
# define BOOST_THREAD_CHRONO_POSIX_API
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#if !defined(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)
|
||||
#define BOOST_THREAD_POLL_INTERVAL_MILLISECONDS 100
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
|
||||
#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \
|
||||
@@ -93,15 +124,15 @@
|
||||
|
||||
/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
|
||||
//#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC
|
||||
#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR
|
||||
#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNCTION_PTR
|
||||
//#endif
|
||||
|
||||
// Default version
|
||||
#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 +335,21 @@
|
||||
|
||||
#endif // BOOST_THREAD_VERSION>=4
|
||||
|
||||
|
||||
#if BOOST_THREAD_VERSION>=5
|
||||
//#define BOOST_THREAD_FUTURE_BLOCKING
|
||||
|
||||
#if ! defined BOOST_THREAD_PROVIDES_EXECUTORS \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_EXECUTORS
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#endif
|
||||
|
||||
#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
|
||||
@@ -359,7 +405,7 @@
|
||||
#define BOOST_THREAD_FUTURE_USES_OPTIONAL
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
#if BOOST_WORKAROUND(BOOST_BORLANDC, < 0x600)
|
||||
# pragma warn -8008 // Condition always true/false
|
||||
# pragma warn -8080 // Identifier declared but never used
|
||||
# pragma warn -8057 // Parameter never used
|
||||
@@ -375,9 +421,37 @@
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
|
||||
#define BOOST_THREAD_HAS_MONO_CLOCK
|
||||
#define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
|
||||
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
|
||||
#define BOOST_THREAD_HAS_MONO_CLOCK
|
||||
#elif defined(__ANDROID__)
|
||||
#define BOOST_THREAD_HAS_MONO_CLOCK
|
||||
#if defined(__ANDROID_API__) && __ANDROID_API__ >= 21
|
||||
#define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
|
||||
#endif
|
||||
#else
|
||||
#include <time.h> // check for CLOCK_MONOTONIC
|
||||
#if defined(CLOCK_MONOTONIC)
|
||||
#define BOOST_THREAD_HAS_MONO_CLOCK
|
||||
#define BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#elif ! defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
|
||||
#if defined BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
|
||||
#elif (defined(_POSIX_TIMEOUTS) && (_POSIX_TIMEOUTS-0)>=200112L) \
|
||||
|| (defined(__ANDROID__) && defined(__ANDROID_API__) && __ANDROID_API__ >= 21)
|
||||
#define BOOST_THREAD_USES_PTHREAD_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// provided for backwards compatibility, since this
|
||||
// macro was used for several releases by mistake.
|
||||
#if defined(BOOST_THREAD_DYN_DLL) && ! defined BOOST_THREAD_DYN_LINK
|
||||
#if defined(BOOST_THREAD_DYN_DLL) && ! defined(BOOST_THREAD_DYN_LINK)
|
||||
# define BOOST_THREAD_DYN_LINK
|
||||
#endif
|
||||
|
||||
@@ -396,7 +470,8 @@
|
||||
#else //Use default
|
||||
# if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) \
|
||||
|| defined(__MINGW32__) || defined(MINGW32) || defined(BOOST_MINGW32)
|
||||
|| defined(__MINGW32__) || defined(MINGW32) || defined(BOOST_MINGW32) \
|
||||
|| (defined(_MSC_VER) && defined(__clang__))
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
@@ -436,7 +511,7 @@
|
||||
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_USE_DLL)
|
||||
#if defined(BOOST_THREAD_USE_DLL) & ! defined(BOOST_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
#endif
|
||||
//
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_member_function_pointer.hpp>
|
||||
@@ -531,13 +530,13 @@ namespace boost
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return f(boost::forward<Args>(args)...);
|
||||
}
|
||||
@@ -1360,12 +1359,12 @@ namespace boost
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
|
||||
template <class Ret, class Fp>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return boost::forward<Fp>(f)();
|
||||
}
|
||||
template <class Ret, class Fp>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
@@ -1382,12 +1381,12 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
@@ -1404,12 +1403,12 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
@@ -1426,12 +1425,12 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
@@ -1449,12 +1448,12 @@ namespace boost
|
||||
|
||||
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return f(a1);
|
||||
}
|
||||
@@ -1471,12 +1470,12 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return f(a1, a2);
|
||||
}
|
||||
@@ -1493,12 +1492,12 @@ namespace boost
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
inline Ret do_invoke(boost::false_type, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2, a3);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
inline Ret do_invoke(boost::true_type, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return f(a1, a2, a3);
|
||||
}
|
||||
|
||||
@@ -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_)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,13 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#define BOOST_THREAD_LOG \
|
||||
__pragma(warning(suppress:4127)) /* conditional expression is constant */ \
|
||||
if (true) {} else boost::thread_detail::dummy_stream
|
||||
#else
|
||||
#define BOOST_THREAD_LOG if (true) {} else boost::thread_detail::dummy_stream
|
||||
#endif
|
||||
#define BOOST_THREAD_END_LOG boost::thread_detail::dummy_stream
|
||||
|
||||
#endif
|
||||
@@ -80,4 +86,13 @@ namespace boost
|
||||
#define BOOST_THREAD_TRACE BOOST_THREAD_LOG << BOOST_THREAD_END_LOG
|
||||
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#define BOOST_DETAIL_THREAD_LOG \
|
||||
__pragma(warning(suppress:4127)) /* conditional expression is constant */ \
|
||||
if (false) {} else std::cout << std::endl << __FILE__ << "[" << __LINE__ << "]"
|
||||
#else
|
||||
#define BOOST_DETAIL_THREAD_LOG \
|
||||
if (false) {} else std::cout << std::endl << __FILE__ << "[" << __LINE__ << "]"
|
||||
#endif
|
||||
|
||||
#endif // header
|
||||
|
||||
@@ -18,9 +18,7 @@
|
||||
#include <boost/type_traits/remove_extent.hpp>
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/add_pointer.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
@@ -94,6 +92,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 +118,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 +144,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 +174,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; \
|
||||
@@ -333,12 +350,19 @@ namespace boost
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
decay_copy(T&& t)
|
||||
{
|
||||
return boost::forward<T>(t);
|
||||
}
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
decay_copy(T&& t)
|
||||
{
|
||||
return boost::forward<T>(t);
|
||||
}
|
||||
typedef void (*void_fct_ptr)();
|
||||
|
||||
// inline void_fct_ptr
|
||||
// decay_copy(void (&t)())
|
||||
// {
|
||||
// return &t;
|
||||
// }
|
||||
#else
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
// 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/09 Vicente J. Botet Escriba
|
||||
// 2013,2018 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// Make use of Boost.Move
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/csbl/memory/shared_ptr.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -72,12 +73,16 @@ namespace boost
|
||||
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
explicit nullary_function(F& f):
|
||||
explicit nullary_function(F& f
|
||||
, typename disable_if<is_same<typename decay<F>::type, nullary_function>, int* >::type=0
|
||||
):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
#endif
|
||||
template<typename F>
|
||||
nullary_function(BOOST_THREAD_RV_REF(F) f):
|
||||
nullary_function(BOOST_THREAD_RV_REF(F) f
|
||||
, typename disable_if<is_same<typename decay<F>::type, nullary_function>, int* >::type=0
|
||||
):
|
||||
impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{}
|
||||
|
||||
@@ -228,7 +233,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
|
||||
|
||||
@@ -31,7 +31,9 @@
|
||||
#elif defined(__CYGWIN__)
|
||||
# define BOOST_THREAD_CYGWIN
|
||||
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
|
||||
#if ! defined BOOST_THREAD_WIN32
|
||||
# define BOOST_THREAD_WIN32
|
||||
#endif
|
||||
#elif defined(__BEOS__)
|
||||
# define BOOST_THREAD_BEOS
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
|
||||
478
include/boost/thread/detail/platform_time.hpp
Normal file
478
include/boost/thread/detail/platform_time.hpp
Normal file
@@ -0,0 +1,478 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
|
||||
#define BOOST_THREAD_DETAIL_PLATFORM_TIME_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2012 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/thread/detail/config.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#endif
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
|
||||
#include <boost/winapi/time.hpp>
|
||||
#include <boost/winapi/timers.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
|
||||
#include <sys/time.h> //for gettimeofday and timeval
|
||||
#include <mach/mach_time.h> // mach_absolute_time, mach_timebase_info_data_t
|
||||
|
||||
#else
|
||||
#include <time.h> // for clock_gettime
|
||||
#endif
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
//typedef boost::int_least64_t time_max_t;
|
||||
typedef boost::intmax_t time_max_t;
|
||||
|
||||
#if defined BOOST_THREAD_CHRONO_MAC_API
|
||||
namespace threads
|
||||
{
|
||||
|
||||
namespace chrono_details
|
||||
{
|
||||
|
||||
// steady_clock
|
||||
|
||||
// Note, in this implementation steady_clock and high_resolution_clock
|
||||
// are the same clock. They are both based on mach_absolute_time().
|
||||
// mach_absolute_time() * MachInfo.numer / MachInfo.denom is the number of
|
||||
// nanoseconds since the computer booted up. MachInfo.numer and MachInfo.denom
|
||||
// are run time constants supplied by the OS. This clock has no relationship
|
||||
// to the Gregorian calendar. It's main use is as a high resolution timer.
|
||||
|
||||
// MachInfo.numer / MachInfo.denom is often 1 on the latest equipment. Specialize
|
||||
// for that case as an optimization.
|
||||
|
||||
inline time_max_t
|
||||
steady_simplified()
|
||||
{
|
||||
return mach_absolute_time();
|
||||
}
|
||||
|
||||
inline double compute_steady_factor(kern_return_t& err)
|
||||
{
|
||||
mach_timebase_info_data_t MachInfo;
|
||||
err = mach_timebase_info(&MachInfo);
|
||||
if ( err != 0 ) {
|
||||
return 0;
|
||||
}
|
||||
return static_cast<double>(MachInfo.numer) / MachInfo.denom;
|
||||
}
|
||||
|
||||
inline time_max_t steady_full()
|
||||
{
|
||||
kern_return_t err;
|
||||
const double factor = chrono_details::compute_steady_factor(err);
|
||||
if (err != 0)
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
return static_cast<time_max_t>(mach_absolute_time() * factor);
|
||||
}
|
||||
|
||||
|
||||
typedef time_max_t (*FP)();
|
||||
|
||||
inline FP init_steady_clock(kern_return_t & err)
|
||||
{
|
||||
mach_timebase_info_data_t MachInfo;
|
||||
err = mach_timebase_info(&MachInfo);
|
||||
if ( err != 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (MachInfo.numer == MachInfo.denom)
|
||||
{
|
||||
return &chrono_details::steady_simplified;
|
||||
}
|
||||
return &chrono_details::steady_full;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
inline timespec ns_to_timespec(boost::time_max_t const& ns)
|
||||
{
|
||||
boost::time_max_t s = ns / 1000000000l;
|
||||
timespec ts;
|
||||
ts.tv_sec = static_cast<long> (s);
|
||||
ts.tv_nsec = static_cast<long> (ns - s * 1000000000l);
|
||||
return ts;
|
||||
}
|
||||
inline boost::time_max_t timespec_to_ns(timespec const& ts)
|
||||
{
|
||||
return static_cast<boost::time_max_t>(ts.tv_sec) * 1000000000l + ts.tv_nsec;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct platform_duration
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
explicit platform_duration(timespec const& v) : ts_val(v) {}
|
||||
timespec const& getTs() const { return ts_val; }
|
||||
|
||||
explicit platform_duration(boost::time_max_t const& ns = 0) : ts_val(ns_to_timespec(ns)) {}
|
||||
boost::time_max_t getNs() const { return timespec_to_ns(ts_val); }
|
||||
#else
|
||||
explicit platform_duration(boost::time_max_t const& ns = 0) : ns_val(ns) {}
|
||||
boost::time_max_t getNs() const { return ns_val; }
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
platform_duration(boost::posix_time::time_duration const& rel_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
ts_val.tv_sec = rel_time.total_seconds();
|
||||
ts_val.tv_nsec = static_cast<long>(rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second()));
|
||||
#else
|
||||
ns_val = static_cast<boost::time_max_t>(rel_time.total_seconds()) * 1000000000l;
|
||||
ns_val += rel_time.fractional_seconds() * (1000000000l / rel_time.ticks_per_second());
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
platform_duration(chrono::duration<Rep, Period> const& d)
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
ts_val = ns_to_timespec(chrono::ceil<chrono::nanoseconds>(d).count());
|
||||
#else
|
||||
ns_val = chrono::ceil<chrono::nanoseconds>(d).count();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::time_max_t getMs() const
|
||||
{
|
||||
const boost::time_max_t ns = getNs();
|
||||
// ceil/floor away from zero
|
||||
if (ns >= 0)
|
||||
{
|
||||
// return ceiling of positive numbers
|
||||
return (ns + 999999) / 1000000;
|
||||
}
|
||||
else
|
||||
{
|
||||
// return floor of negative numbers
|
||||
return (ns - 999999) / 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
static platform_duration zero()
|
||||
{
|
||||
return platform_duration(0);
|
||||
}
|
||||
|
||||
private:
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
timespec ts_val;
|
||||
#else
|
||||
boost::time_max_t ns_val;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline bool operator==(platform_duration const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return lhs.getNs() == rhs.getNs();
|
||||
}
|
||||
inline bool operator!=(platform_duration const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return lhs.getNs() != rhs.getNs();
|
||||
}
|
||||
inline bool operator<(platform_duration const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return lhs.getNs() < rhs.getNs();
|
||||
}
|
||||
inline bool operator<=(platform_duration const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return lhs.getNs() <= rhs.getNs();
|
||||
}
|
||||
inline bool operator>(platform_duration const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return lhs.getNs() > rhs.getNs();
|
||||
}
|
||||
inline bool operator>=(platform_duration const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return lhs.getNs() >= rhs.getNs();
|
||||
}
|
||||
|
||||
static inline platform_duration platform_milliseconds(long const& ms)
|
||||
{
|
||||
return platform_duration(ms * 1000000l);
|
||||
}
|
||||
|
||||
struct real_platform_timepoint
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
explicit real_platform_timepoint(timespec const& v) : dur(v) {}
|
||||
timespec const& getTs() const { return dur.getTs(); }
|
||||
#endif
|
||||
|
||||
explicit real_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
|
||||
boost::time_max_t getNs() const { return dur.getNs(); }
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
real_platform_timepoint(boost::system_time const& abs_time)
|
||||
: dur(abs_time - boost::posix_time::from_time_t(0)) {}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
template <class Duration>
|
||||
real_platform_timepoint(chrono::time_point<chrono::system_clock, Duration> const& abs_time)
|
||||
: dur(abs_time.time_since_epoch()) {}
|
||||
#endif
|
||||
|
||||
private:
|
||||
platform_duration dur;
|
||||
};
|
||||
|
||||
inline bool operator==(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() == rhs.getNs();
|
||||
}
|
||||
inline bool operator!=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() != rhs.getNs();
|
||||
}
|
||||
inline bool operator<(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() < rhs.getNs();
|
||||
}
|
||||
inline bool operator<=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() <= rhs.getNs();
|
||||
}
|
||||
inline bool operator>(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() > rhs.getNs();
|
||||
}
|
||||
inline bool operator>=(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() >= rhs.getNs();
|
||||
}
|
||||
|
||||
inline real_platform_timepoint operator+(real_platform_timepoint const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return real_platform_timepoint(lhs.getNs() + rhs.getNs());
|
||||
}
|
||||
inline real_platform_timepoint operator+(platform_duration const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return real_platform_timepoint(lhs.getNs() + rhs.getNs());
|
||||
}
|
||||
inline platform_duration operator-(real_platform_timepoint const& lhs, real_platform_timepoint const& rhs)
|
||||
{
|
||||
return platform_duration(lhs.getNs() - rhs.getNs());
|
||||
}
|
||||
|
||||
struct real_platform_clock
|
||||
{
|
||||
static real_platform_timepoint now()
|
||||
{
|
||||
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
|
||||
boost::winapi::FILETIME_ ft;
|
||||
boost::winapi::GetSystemTimeAsFileTime(&ft); // never fails
|
||||
boost::time_max_t ns = ((((static_cast<boost::time_max_t>(ft.dwHighDateTime) << 32) | ft.dwLowDateTime) - 116444736000000000LL) * 100LL);
|
||||
return real_platform_timepoint(ns);
|
||||
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
|
||||
timeval tv;
|
||||
::gettimeofday(&tv, 0);
|
||||
timespec ts;
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
return real_platform_timepoint(ts);
|
||||
#else
|
||||
timespec ts;
|
||||
if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_REALTIME) Internal Error");
|
||||
return real_platform_timepoint(0);
|
||||
}
|
||||
return real_platform_timepoint(ts);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(BOOST_THREAD_HAS_MONO_CLOCK)
|
||||
|
||||
struct mono_platform_timepoint
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
|
||||
explicit mono_platform_timepoint(timespec const& v) : dur(v) {}
|
||||
timespec const& getTs() const { return dur.getTs(); }
|
||||
#endif
|
||||
|
||||
explicit mono_platform_timepoint(boost::time_max_t const& ns) : dur(ns) {}
|
||||
boost::time_max_t getNs() const { return dur.getNs(); }
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
// This conversion assumes that chrono::steady_clock::time_point and mono_platform_timepoint share the same epoch.
|
||||
template <class Duration>
|
||||
mono_platform_timepoint(chrono::time_point<chrono::steady_clock, Duration> const& abs_time)
|
||||
: dur(abs_time.time_since_epoch()) {}
|
||||
#endif
|
||||
|
||||
// can't name this max() since that is a macro on some Windows systems
|
||||
static mono_platform_timepoint getMax()
|
||||
{
|
||||
#if defined BOOST_THREAD_CHRONO_POSIX_API || defined BOOST_THREAD_CHRONO_MAC_API
|
||||
timespec ts;
|
||||
ts.tv_sec = (std::numeric_limits<time_t>::max)();
|
||||
ts.tv_nsec = 999999999;
|
||||
return mono_platform_timepoint(ts);
|
||||
#else
|
||||
boost::time_max_t ns = (std::numeric_limits<boost::time_max_t>::max)();
|
||||
return mono_platform_timepoint(ns);
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
platform_duration dur;
|
||||
};
|
||||
|
||||
inline bool operator==(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() == rhs.getNs();
|
||||
}
|
||||
inline bool operator!=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() != rhs.getNs();
|
||||
}
|
||||
inline bool operator<(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() < rhs.getNs();
|
||||
}
|
||||
inline bool operator<=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() <= rhs.getNs();
|
||||
}
|
||||
inline bool operator>(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() > rhs.getNs();
|
||||
}
|
||||
inline bool operator>=(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return lhs.getNs() >= rhs.getNs();
|
||||
}
|
||||
|
||||
inline mono_platform_timepoint operator+(mono_platform_timepoint const& lhs, platform_duration const& rhs)
|
||||
{
|
||||
return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
|
||||
}
|
||||
inline mono_platform_timepoint operator+(platform_duration const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return mono_platform_timepoint(lhs.getNs() + rhs.getNs());
|
||||
}
|
||||
inline platform_duration operator-(mono_platform_timepoint const& lhs, mono_platform_timepoint const& rhs)
|
||||
{
|
||||
return platform_duration(lhs.getNs() - rhs.getNs());
|
||||
}
|
||||
|
||||
struct mono_platform_clock
|
||||
{
|
||||
static mono_platform_timepoint now()
|
||||
{
|
||||
#if defined(BOOST_THREAD_CHRONO_WINDOWS_API)
|
||||
#if defined(BOOST_THREAD_USES_CHRONO)
|
||||
// Use QueryPerformanceCounter() to match the implementation in Boost
|
||||
// Chrono so that chrono::steady_clock::now() and this function share the
|
||||
// same epoch and so can be converted between each other.
|
||||
boost::winapi::LARGE_INTEGER_ freq;
|
||||
if ( !boost::winapi::QueryPerformanceFrequency( &freq ) )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
|
||||
return mono_platform_timepoint(0);
|
||||
}
|
||||
if ( freq.QuadPart <= 0 )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceFrequency Internal Error");
|
||||
return mono_platform_timepoint(0);
|
||||
}
|
||||
|
||||
boost::winapi::LARGE_INTEGER_ pcount;
|
||||
unsigned times=0;
|
||||
while ( ! boost::winapi::QueryPerformanceCounter( &pcount ) )
|
||||
{
|
||||
if ( ++times > 3 )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Thread - QueryPerformanceCounter Internal Error");
|
||||
return mono_platform_timepoint(0);
|
||||
}
|
||||
}
|
||||
|
||||
long double ns = 1000000000.0L * pcount.QuadPart / freq.QuadPart;
|
||||
return mono_platform_timepoint(static_cast<boost::time_max_t>(ns));
|
||||
#else
|
||||
// Use GetTickCount64() because it's more reliable on older
|
||||
// systems like Windows XP and Windows Server 2003.
|
||||
win32::ticks_type msec = win32::gettickcount64();
|
||||
return mono_platform_timepoint(msec * 1000000);
|
||||
#endif
|
||||
#elif defined(BOOST_THREAD_CHRONO_MAC_API)
|
||||
kern_return_t err;
|
||||
threads::chrono_details::FP fp = threads::chrono_details::init_steady_clock(err);
|
||||
if ( err != 0 )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Chrono - Internal Error");
|
||||
}
|
||||
return mono_platform_timepoint(fp());
|
||||
#else
|
||||
timespec ts;
|
||||
if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
|
||||
{
|
||||
BOOST_ASSERT(0 && "Boost::Thread - clock_gettime(CLOCK_MONOTONIC) Internal Error");
|
||||
return mono_platform_timepoint(0);
|
||||
}
|
||||
return mono_platform_timepoint(ts);
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
|
||||
typedef mono_platform_clock internal_platform_clock;
|
||||
typedef mono_platform_timepoint internal_platform_timepoint;
|
||||
#else
|
||||
typedef real_platform_clock internal_platform_clock;
|
||||
typedef real_platform_timepoint internal_platform_timepoint;
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#ifdef BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
|
||||
typedef chrono::steady_clock internal_chrono_clock;
|
||||
#else
|
||||
typedef chrono::system_clock internal_chrono_clock;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -18,6 +18,9 @@
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#endif
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
#include <boost/thread/interruption.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
@@ -27,7 +30,7 @@
|
||||
#include <algorithm>
|
||||
#include <boost/core/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/bind/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
@@ -36,6 +39,7 @@
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/thread/detail/platform_time.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
@@ -72,7 +76,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 +177,6 @@ namespace boost
|
||||
private:
|
||||
bool start_thread_noexcept();
|
||||
bool start_thread_noexcept(const attributes& attr);
|
||||
//public:
|
||||
void start_thread()
|
||||
{
|
||||
if (!start_thread_noexcept())
|
||||
@@ -292,7 +295,7 @@ namespace boost
|
||||
template <class F>
|
||||
explicit thread(F f
|
||||
, typename disable_if_c<
|
||||
boost::thread_detail::is_rv<F>::value // todo ass a thread_detail::is_rv
|
||||
boost::thread_detail::is_rv<F>::value // todo as a thread_detail::is_rv
|
||||
//boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
|
||||
//|| is_same<typename decay<F>::type, thread>::value
|
||||
, dummy* >::type=0
|
||||
@@ -355,6 +358,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();
|
||||
@@ -453,104 +458,80 @@ namespace boost
|
||||
}
|
||||
|
||||
class id;
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
inline id get_id() const BOOST_NOEXCEPT;
|
||||
#else
|
||||
id get_id() const BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
|
||||
bool joinable() const BOOST_NOEXCEPT;
|
||||
private:
|
||||
bool join_noexcept();
|
||||
bool do_try_join_until_noexcept(detail::internal_platform_timepoint const &timeout, bool& res);
|
||||
bool do_try_join_until(detail::internal_platform_timepoint const &timeout);
|
||||
public:
|
||||
inline void join();
|
||||
void join();
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
template <class Duration>
|
||||
bool try_join_until(const chrono::time_point<detail::internal_chrono_clock, Duration>& t)
|
||||
{
|
||||
chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
|
||||
return do_try_join_until(rel_time2.count());
|
||||
return do_try_join_until(boost::detail::internal_platform_timepoint(t));
|
||||
}
|
||||
#else
|
||||
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
typedef typename common_type<Duration, typename Clock::duration>::type common_duration;
|
||||
common_duration d(t - Clock::now());
|
||||
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
|
||||
while ( ! try_join_until(detail::internal_chrono_clock::now() + d) )
|
||||
{
|
||||
d = t - Clock::now();
|
||||
if ( d <= common_duration::zero() ) return false; // timeout occurred
|
||||
d = (std::min)(d, common_duration(chrono::milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_join_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
#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 {
|
||||
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);
|
||||
} while (! joined);
|
||||
return true;
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
||||
return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
||||
}
|
||||
#endif
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
private:
|
||||
bool do_try_join_until_noexcept(uintmax_t milli, bool& res);
|
||||
inline bool do_try_join_until(uintmax_t milli);
|
||||
public:
|
||||
bool timed_join(const system_time& abs_time);
|
||||
//{
|
||||
// return do_try_join_until(get_milliseconds_until(wait_until));
|
||||
//}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
return do_try_join_until(rel_time.count());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#else
|
||||
private:
|
||||
bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res);
|
||||
inline bool do_try_join_until(struct timespec const &timeout);
|
||||
public:
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
bool timed_join(const system_time& abs_time)
|
||||
{
|
||||
struct timespec const ts=detail::to_timespec(abs_time);
|
||||
const detail::real_platform_timepoint ts(abs_time);
|
||||
#if defined BOOST_THREAD_INTERNAL_CLOCK_IS_MONO
|
||||
detail::platform_duration d(ts - detail::real_platform_clock::now());
|
||||
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
|
||||
while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) )
|
||||
{
|
||||
d = ts - detail::real_platform_clock::now();
|
||||
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
|
||||
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return do_try_join_until(ts);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts = boost::detail::to_timespec(d);
|
||||
return do_try_join_until(ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
public:
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template<typename TimeDuration>
|
||||
inline bool timed_join(TimeDuration const& rel_time)
|
||||
bool timed_join(TimeDuration const& rel_time)
|
||||
{
|
||||
return timed_join(get_system_time()+rel_time);
|
||||
detail::platform_duration d(rel_time);
|
||||
#if defined(BOOST_THREAD_HAS_MONO_CLOCK) && !defined(BOOST_THREAD_INTERNAL_CLOCK_IS_MONO)
|
||||
const detail::mono_platform_timepoint ts(detail::mono_platform_clock::now() + d);
|
||||
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
|
||||
while ( ! do_try_join_until(detail::internal_platform_clock::now() + d) )
|
||||
{
|
||||
d = ts - detail::mono_platform_clock::now();
|
||||
if ( d <= detail::platform_duration::zero() ) return false; // timeout occurred
|
||||
d = (std::min)(d, detail::platform_milliseconds(BOOST_THREAD_POLL_INTERVAL_MILLISECONDS));
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return do_try_join_until(detail::internal_platform_clock::now() + d);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
void detach();
|
||||
@@ -604,19 +585,13 @@ namespace boost
|
||||
namespace this_thread
|
||||
{
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
inline thread::id get_id() BOOST_NOEXCEPT;
|
||||
thread::id get_id() BOOST_NOEXCEPT;
|
||||
#else
|
||||
thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
|
||||
bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(::boost::xtime const& abs_time)
|
||||
{
|
||||
sleep(system_time(abs_time));
|
||||
}
|
||||
@@ -626,6 +601,9 @@ namespace boost
|
||||
class BOOST_SYMBOL_VISIBLE thread::id
|
||||
{
|
||||
private:
|
||||
|
||||
#if !defined(BOOST_EMBTC)
|
||||
|
||||
friend inline
|
||||
std::size_t
|
||||
hash_value(const thread::id &v)
|
||||
@@ -637,6 +615,14 @@ namespace boost
|
||||
#endif
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
friend
|
||||
std::size_t
|
||||
hash_value(const thread::id &v);
|
||||
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
typedef unsigned int data;
|
||||
@@ -662,10 +648,6 @@ namespace boost
|
||||
#endif
|
||||
{}
|
||||
|
||||
id(const id& other) BOOST_NOEXCEPT :
|
||||
thread_data(other.thread_data)
|
||||
{}
|
||||
|
||||
bool operator==(const id& y) const BOOST_NOEXCEPT
|
||||
{
|
||||
return thread_data==y.thread_data;
|
||||
@@ -733,9 +715,24 @@ namespace boost
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(BOOST_EMBTC)
|
||||
|
||||
inline
|
||||
std::size_t
|
||||
hash_value(const thread::id &v)
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
return hash_value(v.thread_data);
|
||||
#else
|
||||
return hash_value(v.thread_data.get());
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
thread::id thread::get_id() const BOOST_NOEXCEPT
|
||||
inline thread::id thread::get_id() const BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
return const_cast<thread*>(this)->native_handle();
|
||||
@@ -758,7 +755,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void thread::join() {
|
||||
inline void thread::join() {
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
|
||||
|
||||
@@ -767,11 +764,7 @@ namespace boost
|
||||
);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PLATFORM_PTHREAD
|
||||
bool thread::do_try_join_until(struct timespec const &timeout)
|
||||
#else
|
||||
bool thread::do_try_join_until(uintmax_t timeout)
|
||||
#endif
|
||||
inline bool thread::do_try_join_until(detail::internal_platform_timepoint const &timeout)
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
|
||||
@@ -837,6 +830,7 @@ namespace boost
|
||||
};
|
||||
|
||||
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
|
||||
//#ifndef BOOST_NO_EXCEPTIONS
|
||||
struct shared_state_base;
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
||||
@@ -850,6 +844,7 @@ namespace boost
|
||||
#else
|
||||
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
|
||||
#endif
|
||||
//#endif
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
160
include/boost/thread/detail/thread_safety.hpp
Normal file
160
include/boost/thread/detail/thread_safety.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP
|
||||
#define BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP
|
||||
|
||||
#if defined(__GNUC__) && !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
//
|
||||
// This is horrible, but it seems to be the only we can shut up the
|
||||
// "anonymous variadic macros were introduced in C99 [-Wvariadic-macros]"
|
||||
// warning that get spewed out otherwise in non-C++11 mode.
|
||||
//
|
||||
#pragma GCC system_header
|
||||
#endif
|
||||
|
||||
// See https://clang.llvm.org/docs/ThreadSafetyAnalysis.html
|
||||
|
||||
// Un-comment to enable Thread Safety Analysis
|
||||
//#define BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS
|
||||
|
||||
// Enable thread safety attributes only with clang.
|
||||
// The attributes can be safely erased when compiling with other compilers.
|
||||
#if defined (BOOST_THREAD_ENABLE_THREAD_SAFETY_ANALYSIS) && defined(__clang__) && (!defined(SWIG))
|
||||
#define BOOST_THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
|
||||
#else
|
||||
#define BOOST_THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_CAPABILITY(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
|
||||
|
||||
#define BOOST_THREAD_SCOPED_CAPABILITY \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
#define BOOST_THREAD_GUARDED_BY(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
|
||||
|
||||
#define BOOST_THREAD_PT_GUARDED_BY(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
|
||||
|
||||
#define BOOST_THREAD_ACQUIRED_BEFORE(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_ACQUIRED_AFTER(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_REQUIRES(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_REQUIRES_SHARED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_ACQUIRE(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_ACQUIRE_SHARED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_RELEASE(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_RELEASE_SHARED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_TRY_ACQUIRE(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_TRY_ACQUIRE_SHARED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_EXCLUDES(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
#define BOOST_THREAD_ASSERT_CAPABILITY(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
|
||||
|
||||
#define BOOST_THREAD_ASSERT_SHARED_CAPABILITY(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
|
||||
|
||||
#define BOOST_THREAD_RETURN_CAPABILITY(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
#define BOOST_THREAD_NO_THREAD_SAFETY_ANALYSIS \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
#if defined(__clang__) && (!defined(SWIG)) && defined(__FreeBSD__)
|
||||
#if __has_attribute(no_thread_safety_analysis)
|
||||
#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis))
|
||||
#else
|
||||
#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
|
||||
#endif
|
||||
#else
|
||||
#define BOOST_THREAD_DISABLE_THREAD_SAFETY_ANALYSIS
|
||||
#endif
|
||||
|
||||
#ifdef USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
|
||||
// The original version of thread safety analysis the following attribute
|
||||
// definitions. These use a lock-based terminology. They are still in use
|
||||
// by existing thread safety code, and will continue to be supported.
|
||||
|
||||
// Deprecated.
|
||||
#define BOOST_THREAD_PT_GUARDED_VAR \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_var)
|
||||
|
||||
// Deprecated.
|
||||
#define BOOST_THREAD_GUARDED_VAR \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(guarded_var)
|
||||
|
||||
// Replaced by REQUIRES
|
||||
#define BOOST_THREAD_EXCLUSIVE_LOCKS_REQUIRED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_locks_required(__VA_ARGS__))
|
||||
|
||||
// Replaced by REQUIRES_SHARED
|
||||
#define BOOST_THREAD_SHARED_LOCKS_REQUIRED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_locks_required(__VA_ARGS__))
|
||||
|
||||
// Replaced by CAPABILITY
|
||||
#define BOOST_THREAD_LOCKABLE \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lockable)
|
||||
|
||||
// Replaced by SCOPED_CAPABILITY
|
||||
#define BOOST_THREAD_SCOPED_LOCKABLE \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
|
||||
|
||||
// Replaced by ACQUIRE
|
||||
#define BOOST_THREAD_EXCLUSIVE_LOCK_FUNCTION(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_lock_function(__VA_ARGS__))
|
||||
|
||||
// Replaced by ACQUIRE_SHARED
|
||||
#define BOOST_THREAD_SHARED_LOCK_FUNCTION(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_lock_function(__VA_ARGS__))
|
||||
|
||||
// Replaced by RELEASE and RELEASE_SHARED
|
||||
#define BOOST_THREAD_UNLOCK_FUNCTION(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(unlock_function(__VA_ARGS__))
|
||||
|
||||
// Replaced by TRY_ACQUIRE
|
||||
#define BOOST_THREAD_EXCLUSIVE_TRYLOCK_FUNCTION(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(exclusive_trylock_function(__VA_ARGS__))
|
||||
|
||||
// Replaced by TRY_ACQUIRE_SHARED
|
||||
#define BOOST_THREAD_SHARED_TRYLOCK_FUNCTION(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(shared_trylock_function(__VA_ARGS__))
|
||||
|
||||
// Replaced by ASSERT_CAPABILITY
|
||||
#define BOOST_THREAD_ASSERT_EXCLUSIVE_LOCK(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_exclusive_lock(__VA_ARGS__))
|
||||
|
||||
// Replaced by ASSERT_SHARED_CAPABILITY
|
||||
#define BOOST_THREAD_ASSERT_SHARED_LOCK(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_lock(__VA_ARGS__))
|
||||
|
||||
// Replaced by EXCLUDE_CAPABILITY.
|
||||
#define BOOST_THREAD_LOCKS_EXCLUDED(...) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
|
||||
|
||||
// Replaced by RETURN_CAPABILITY
|
||||
#define BOOST_THREAD_LOCK_RETURNED(x) \
|
||||
BOOST_THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
|
||||
|
||||
#endif // USE_LOCK_STYLE_THREAD_SAFETY_ATTRIBUTES
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_THREAD_SAFETY_HPP
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
#if defined(BOOST_THREAD_WIN32)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -58,7 +58,7 @@ namespace boost
|
||||
//it to be linked into the Boost.Threads library.
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
#endif //defined(BOOST_THREAD_WIN32)
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
@@ -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,23 +40,23 @@ 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)
|
||||
{
|
||||
}
|
||||
|
||||
~thread_exception() throw()
|
||||
~thread_exception() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -113,7 +113,7 @@ namespace boost
|
||||
{
|
||||
}
|
||||
|
||||
~lock_error() throw()
|
||||
~lock_error() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{}
|
||||
|
||||
};
|
||||
@@ -141,7 +141,7 @@ namespace boost
|
||||
}
|
||||
|
||||
|
||||
~thread_resource_error() throw()
|
||||
~thread_resource_error() BOOST_NOEXCEPT_OR_NOTHROW
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
#define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
|
||||
|
||||
#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 +32,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 +49,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 +88,23 @@ namespace executors
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = work_queue.wait_pull_front(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
try
|
||||
{
|
||||
queue_op_status st = work_queue.wait_pull(task);
|
||||
if (st == queue_op_status::closed) {
|
||||
return;
|
||||
}
|
||||
task();
|
||||
}
|
||||
catch (boost::thread_interrupted&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -134,7 +138,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 +232,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).
|
||||
interrupt_and_join();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -238,6 +243,30 @@ namespace executors
|
||||
{
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
{
|
||||
//threads[i].interrupt();
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: interrupt all the threads.
|
||||
*/
|
||||
void interrupt()
|
||||
{
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
{
|
||||
threads[i].interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: interrupt and join all the threads.
|
||||
*/
|
||||
void interrupt_and_join()
|
||||
{
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
{
|
||||
threads[i].interrupt();
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
@@ -270,23 +299,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));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,3 +349,4 @@ using executors::basic_thread_pool;
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
// 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(;;)
|
||||
{
|
||||
try {
|
||||
work task;
|
||||
queue_op_status st = _workq.wait_pull(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
catch (boost::thread_interrupted&)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
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
|
||||
@@ -10,6 +10,7 @@
|
||||
#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
@@ -38,7 +39,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 +100,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));
|
||||
}
|
||||
|
||||
@@ -145,3 +147,4 @@ namespace boost
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
|
||||
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
|
||||
@@ -98,9 +99,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 +113,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));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -135,3 +135,4 @@ using executors::executor_adaptor;
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined BOOST_THREAD_PROVIDES_EXECUTORS && defined BOOST_THREAD_USES_MOVE
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
@@ -32,7 +33,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 +42,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 +99,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 +122,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 +138,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));
|
||||
}
|
||||
|
||||
@@ -209,3 +212,4 @@ namespace boost
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user