mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
946 Commits
svn-branch
...
boost-1.51
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b71353f28 | ||
|
|
c4420d7591 | ||
|
|
6ef2dade3a | ||
|
|
c594f5d9ae | ||
|
|
a73cf83971 | ||
|
|
67a5a6f39e | ||
|
|
348bd080ef | ||
|
|
bca4c3d5fa | ||
|
|
9e6384bf79 | ||
|
|
dcd544082e | ||
|
|
1013ce68c1 | ||
|
|
aea84b03fc | ||
|
|
7608db4b0e | ||
|
|
62f1c4b086 | ||
|
|
ab6864f3b4 | ||
|
|
b8bd80a5f4 | ||
|
|
fffc5ddd1f | ||
|
|
cd4c858048 | ||
|
|
3fb1bd3d1d | ||
|
|
75aff7f1a6 | ||
|
|
3f3c5c8ac5 | ||
|
|
40b66a83f7 | ||
|
|
0b15d66dc0 | ||
|
|
ceacda6c6a | ||
|
|
0a22ac9209 | ||
|
|
ba1d54d672 | ||
|
|
b5a18dc71a | ||
|
|
4a0141511d | ||
|
|
f0a6e49984 | ||
|
|
f60e1d1230 | ||
|
|
625db78abf | ||
|
|
b470ffdb56 | ||
|
|
78095afdbc | ||
|
|
e83cdc6721 | ||
|
|
7ba000fe45 | ||
|
|
cae6a36c19 | ||
|
|
8549895373 | ||
|
|
efa907881e | ||
|
|
744cae8270 | ||
|
|
28899243b1 | ||
|
|
267288ba19 | ||
|
|
3487d05fac | ||
|
|
031186a8e6 | ||
|
|
f970c9fddc | ||
|
|
e9ceaaa2bb | ||
|
|
0e7c436df5 | ||
|
|
745e23f2c3 | ||
|
|
1f7b8a6583 | ||
|
|
b2790c6df5 | ||
|
|
f5e3c1c348 | ||
|
|
ba955f003e | ||
|
|
75e0ffbbce | ||
|
|
9168dd7d1d | ||
|
|
ee5f871f1a | ||
|
|
c896c8fda4 | ||
|
|
0e895a1e28 | ||
|
|
d95081094f | ||
|
|
011dda9816 | ||
|
|
34c377328f | ||
|
|
382204f702 | ||
|
|
19aed55e52 | ||
|
|
9d1e1fb64a | ||
|
|
d75cda0cc3 | ||
|
|
a4c7f68320 | ||
|
|
547431da0b | ||
|
|
c3fdc098fe | ||
|
|
6ed276190d | ||
|
|
59265265d9 | ||
|
|
8d9370b005 | ||
|
|
fd97c6e7a7 | ||
|
|
297da0745f | ||
|
|
cb231e02a6 | ||
|
|
298b51fefa | ||
|
|
80befa1c94 | ||
|
|
11dce20534 | ||
|
|
56bd079f96 | ||
|
|
733b49ae42 | ||
|
|
08ed4c4201 | ||
|
|
09d5125278 | ||
|
|
6e1a3f3c27 | ||
|
|
5b3743d9a6 | ||
|
|
ec135b1b8e | ||
|
|
60e34cff11 | ||
|
|
da8dc9f5aa | ||
|
|
27aa44acb5 | ||
|
|
ff1d051359 | ||
|
|
85e32534fa | ||
|
|
bc49b7d03a | ||
|
|
ee97068208 | ||
|
|
0f7e069dd9 | ||
|
|
3c3c6d5efe | ||
|
|
f163054557 | ||
|
|
fb80bea056 | ||
|
|
abad5c3028 | ||
|
|
d0c164220d | ||
|
|
34b1a86a68 | ||
|
|
06f5da7f5b | ||
|
|
1e80ccb8d3 | ||
|
|
8ad34a689a | ||
|
|
a421e10e3b | ||
|
|
1c4b42bb95 | ||
|
|
bba3be457b | ||
|
|
3abfbb8ba1 | ||
|
|
331a35070c | ||
|
|
99ad690382 | ||
|
|
4301b21702 | ||
|
|
fceab582fe | ||
|
|
e8a4ed40a5 | ||
|
|
b698c1437b | ||
|
|
14cea92e06 | ||
|
|
3a8e04cac6 | ||
|
|
5b01721440 | ||
|
|
aad2b35ac9 | ||
|
|
f8371daeb8 | ||
|
|
74519977fd | ||
|
|
c0bea158d4 | ||
|
|
70686b4913 | ||
|
|
14502dd715 | ||
|
|
8ee986536b | ||
|
|
8ed82798d2 | ||
|
|
ebfe10b7df | ||
|
|
4aa26180ca | ||
|
|
89496448d9 | ||
|
|
dfa0a3979a | ||
|
|
396cd7db4f | ||
|
|
0351d59060 | ||
|
|
6f0b0e976d | ||
|
|
dd5d687014 | ||
|
|
5d8b0891bd | ||
|
|
7dc95f63d3 | ||
|
|
a7adc5865b | ||
|
|
cdbe5766fa | ||
|
|
b1cac0731c | ||
|
|
fc8de511c6 | ||
|
|
defdb8ff1c | ||
|
|
9a08a8478f | ||
|
|
a6f7a0180b | ||
|
|
5a59df4476 | ||
|
|
1df9d7c575 | ||
|
|
65008b11f7 | ||
|
|
b18314878a | ||
|
|
11a951c679 | ||
|
|
c67e3ff7b9 | ||
|
|
e5a633cc41 | ||
|
|
3724d847cf | ||
|
|
b6063b5c60 | ||
|
|
09362f0eac | ||
|
|
32b3f3f569 | ||
|
|
0d08362291 | ||
|
|
9f120a80a7 | ||
|
|
2eb6fd754e | ||
|
|
9f4a8973d0 | ||
|
|
a4d9355060 | ||
|
|
5a7545afbd | ||
|
|
8affa33718 | ||
|
|
4d25ea1760 | ||
|
|
6ec8e2ccec | ||
|
|
97d0ae6527 | ||
|
|
50a74d0eda | ||
|
|
f9e03b5eaa | ||
|
|
ad571bd898 | ||
|
|
de8ef9aee4 | ||
|
|
21f75da2f6 | ||
|
|
233dbf8075 | ||
|
|
d8f1ba9b3d | ||
|
|
1241f18215 | ||
|
|
b6604882eb | ||
|
|
a9c9d5c499 | ||
|
|
9a827d937e | ||
|
|
38594f889a | ||
|
|
04c17e45b3 | ||
|
|
730a8de024 | ||
|
|
7eac2fe3e4 | ||
|
|
267243d959 | ||
|
|
f587262c8e | ||
|
|
ebf458dbd0 | ||
|
|
f64b5559dd | ||
|
|
2ddcd5f678 | ||
|
|
cac715937a | ||
|
|
39f43feb11 | ||
|
|
58d65b17ea | ||
|
|
4314f0cac3 | ||
|
|
d4da369930 | ||
|
|
6f1876b618 | ||
|
|
c6e872ceb0 | ||
|
|
72d809819f | ||
|
|
dd09ef3362 | ||
|
|
aa7941fae2 | ||
|
|
35af4a8f35 | ||
|
|
a01fd3dd76 | ||
|
|
d220da89d1 | ||
|
|
55c75e9299 | ||
|
|
616ea87a0a | ||
|
|
319ba2fe75 | ||
|
|
d79eeff779 | ||
|
|
26d38748db | ||
|
|
5c124234bb | ||
|
|
b991c9a8a0 | ||
|
|
681af396b8 | ||
|
|
cac0eaa6c3 | ||
|
|
a64fa2c18f | ||
|
|
f07640850b | ||
|
|
ab665c8c56 | ||
|
|
e43586ffac | ||
|
|
9cc243837d | ||
|
|
de7e3baabc | ||
|
|
7ec9804540 | ||
|
|
5e29afcb57 | ||
|
|
0a1085d9be | ||
|
|
0439d53704 | ||
|
|
7c9116af2e | ||
|
|
5ac2ff4521 | ||
|
|
8565a3e472 | ||
|
|
3648bc8cb0 | ||
|
|
70584af9c0 | ||
|
|
73121eda9d | ||
|
|
381554f8bc | ||
|
|
768e92b0e9 | ||
|
|
98333b7dcf | ||
|
|
4dc1cb1ba1 | ||
|
|
4e0007780c | ||
|
|
506019dd62 | ||
|
|
10f0c3e08e | ||
|
|
fa2950a04b | ||
|
|
ebfb62ca49 | ||
|
|
96023e81af | ||
|
|
e30be60bc4 | ||
|
|
7bfafec128 | ||
|
|
9c07d0ff5d | ||
|
|
e12d2bc486 | ||
|
|
72a85b396c | ||
|
|
87786091bb | ||
|
|
784494274b | ||
|
|
68012dd92c | ||
|
|
a37d2a1364 | ||
|
|
e40be775fe | ||
|
|
64e6924132 | ||
|
|
4bbf47086d | ||
|
|
7c674bc255 | ||
|
|
cc662c102c | ||
|
|
6b9a2d791b | ||
|
|
4551e8759b | ||
|
|
9442976bdb | ||
|
|
8d07df176f | ||
|
|
4b22aff33e | ||
|
|
93dee254d0 | ||
|
|
a29b598205 | ||
|
|
e3b20eaae9 | ||
|
|
d369fb0f94 | ||
|
|
d816bca42f | ||
|
|
d6bb11c4e9 | ||
|
|
2fdcefac05 | ||
|
|
044c3cc11e | ||
|
|
bd9223b525 | ||
|
|
347703dab2 | ||
|
|
f9a0e450e1 | ||
|
|
f6b8cdd1f5 | ||
|
|
6727013302 | ||
|
|
cda12a2660 | ||
|
|
c3c2072472 | ||
|
|
bfc226fdc0 | ||
|
|
fd28e1a7fb | ||
|
|
b11911f5e5 | ||
|
|
a1587d070f | ||
|
|
df2f43bc61 | ||
|
|
895e8eea52 | ||
|
|
97d6249f3b | ||
|
|
7a8ed98eb5 | ||
|
|
d611eece19 | ||
|
|
a99320f5a4 | ||
|
|
c97484943a | ||
|
|
547d9bd844 | ||
|
|
1a65aab05a | ||
|
|
2e869aeb86 | ||
|
|
d729776575 | ||
|
|
895c436405 | ||
|
|
4ae2932792 | ||
|
|
a52be2bdbb | ||
|
|
31c4792216 | ||
|
|
39fd9c0b47 | ||
|
|
9c25df3402 | ||
|
|
fb150b5038 | ||
|
|
8cff3a167e | ||
|
|
2be1431f60 | ||
|
|
255b7ed7f6 | ||
|
|
58fd27399e | ||
|
|
65d2898ff0 | ||
|
|
5f88ba1e47 | ||
|
|
ab569461d8 | ||
|
|
7093fc670b | ||
|
|
6f2b030253 | ||
|
|
0e61e679af | ||
|
|
b40998e1b5 | ||
|
|
174d701bc3 | ||
|
|
f2143d08b9 | ||
|
|
1273e2620d | ||
|
|
c719f6e37e | ||
|
|
37922d8ce0 | ||
|
|
7b79a31f40 | ||
|
|
9a09406f77 | ||
|
|
9bdb778478 | ||
|
|
9621dafe46 | ||
|
|
d7c9837844 | ||
|
|
9087fd904d | ||
|
|
27bb7803ae | ||
|
|
66ac6942b6 | ||
|
|
c0e1086f2c | ||
|
|
ffa751c617 | ||
|
|
b8ad60a2d6 | ||
|
|
5db0aac816 | ||
|
|
20980fe54d | ||
|
|
3fae7c5184 | ||
|
|
fb54acfe69 | ||
|
|
47889a8f22 | ||
|
|
8d22c3869b | ||
|
|
0e69edd066 | ||
|
|
235ed4afe0 | ||
|
|
627cb7f774 | ||
|
|
09021af350 | ||
|
|
31c280d1fa | ||
|
|
629f344f34 | ||
|
|
db5f924e24 | ||
|
|
9be3eb282a | ||
|
|
9255a035f4 | ||
|
|
effd891a16 | ||
|
|
fbdc23f482 | ||
|
|
8ab0d5acdd | ||
|
|
13db35cbf5 | ||
|
|
0f2d480e3c | ||
|
|
9edc61e37b | ||
|
|
f4dab6aac5 | ||
|
|
5af323102a | ||
|
|
9e0550d140 | ||
|
|
0997fad8ec | ||
|
|
0d1701c509 | ||
|
|
f2f62f93ea | ||
|
|
8a329f66fb | ||
|
|
05d4c52918 | ||
|
|
8fd0dd0cc0 | ||
|
|
8eea5811ba | ||
|
|
a154c2adab | ||
|
|
10bf4ed576 | ||
|
|
60d12dd395 | ||
|
|
b4e9be3c52 | ||
|
|
dcebae6d4a | ||
|
|
8749696538 | ||
|
|
0d776bcd26 | ||
|
|
2d6ed47cf2 | ||
|
|
9beea23f63 | ||
|
|
ea06434425 | ||
|
|
6508eff95e | ||
|
|
69930684a9 | ||
|
|
b1931a3eda | ||
|
|
63b44d4e32 | ||
|
|
f7cb8d8141 | ||
|
|
48c857e02c | ||
|
|
2978d43a5d | ||
|
|
a264766584 | ||
|
|
442dc58e0f | ||
|
|
25460c652c | ||
|
|
31a98f0a1e | ||
|
|
36c44b6f45 | ||
|
|
27426b18d1 | ||
|
|
3ea9ce1c8c | ||
|
|
f03a9bfcf3 | ||
|
|
4dfc636c84 | ||
|
|
5fe4312c6c | ||
|
|
63e675a6bb | ||
|
|
e92aeac7d7 | ||
|
|
f1f7eac1f2 | ||
|
|
eff0c84553 | ||
|
|
58c8ce61c7 | ||
|
|
6ac5e6953a | ||
|
|
5d9ad59af2 | ||
|
|
3c48a05437 | ||
|
|
4462124ff2 | ||
|
|
373f557ef7 | ||
|
|
495e561398 | ||
|
|
d24a579033 | ||
|
|
77130424b4 | ||
|
|
eb30688937 | ||
|
|
880bac0633 | ||
|
|
60fdcddcb5 | ||
|
|
851d6a987f | ||
|
|
9bebd7b35f | ||
|
|
309acb9597 | ||
|
|
a56887167e | ||
|
|
e984dff4e4 | ||
|
|
685e4d446b | ||
|
|
8af680f307 | ||
|
|
6c60cce60d | ||
|
|
5882a675bb | ||
|
|
a5e95845b3 | ||
|
|
5b83d81e40 | ||
|
|
c8e5ad564d | ||
|
|
5edfa273ff | ||
|
|
4db57bcb10 | ||
|
|
3f13340903 | ||
|
|
6abb53c9d3 | ||
|
|
fdd20a519e | ||
|
|
67cc49f333 | ||
|
|
31a34cd0b5 | ||
|
|
ef8c08ba99 | ||
|
|
2991ca6c6f | ||
|
|
52bace18b2 | ||
|
|
767d14ae4f | ||
|
|
1a5c911e36 | ||
|
|
6e42a04e43 | ||
|
|
28be2cfeef | ||
|
|
8be168fd87 | ||
|
|
eee95fef57 | ||
|
|
9ea179b052 | ||
|
|
6868280409 | ||
|
|
e00b764454 | ||
|
|
999613c686 | ||
|
|
c2661d7eb5 | ||
|
|
4d21dd1f47 | ||
|
|
a0a0e57527 | ||
|
|
d8af0d0b4e | ||
|
|
113288e3b0 | ||
|
|
afecfd7c2d | ||
|
|
94d89aac5f | ||
|
|
8831b13efc | ||
|
|
01f99da03a | ||
|
|
080654e3ef | ||
|
|
2ac2eb2a61 | ||
|
|
61b940b705 | ||
|
|
4a4f87e017 | ||
|
|
6d5e7f63a7 | ||
|
|
f77285f375 | ||
|
|
dc5d03a6dc | ||
|
|
ea0961b7f6 | ||
|
|
33d9f9774c | ||
|
|
86097fa038 | ||
|
|
70d9dbc45a | ||
|
|
3926fd3a20 | ||
|
|
7861cf1146 | ||
|
|
0516b86a6e | ||
|
|
ec735d3e9b | ||
|
|
1c5c070983 | ||
|
|
a5c02b73dc | ||
|
|
918b920670 | ||
|
|
de67d2e27e | ||
|
|
bc89df04cb | ||
|
|
c26a4cf082 | ||
|
|
6e1a866b13 | ||
|
|
f91986ad0d | ||
|
|
795cc23f3e | ||
|
|
a3695bd4a0 | ||
|
|
08dc521daf | ||
|
|
8b916d21b1 | ||
|
|
c40f47a78a | ||
|
|
e9fb470b06 | ||
|
|
343d049772 | ||
|
|
86f9480da4 | ||
|
|
8696b610ca | ||
|
|
6f13227eda | ||
|
|
525d190f91 | ||
|
|
58d5110e61 | ||
|
|
1e0154335b | ||
|
|
76e53c7bc5 | ||
|
|
413c29a5e4 | ||
|
|
30bb6143c1 | ||
|
|
cfb08be1a8 | ||
|
|
b5bbb7fb1c | ||
|
|
a76c33f8cc | ||
|
|
991ac727c6 | ||
|
|
810306b8f3 | ||
|
|
6c22bdb3bd | ||
|
|
569a78649f | ||
|
|
6a0d3e98bc | ||
|
|
7caec1ec33 | ||
|
|
7fd3fb48b1 | ||
|
|
3809321037 | ||
|
|
eef695bdf0 | ||
|
|
ab01ab1e4d | ||
|
|
a32a3b37db | ||
|
|
c8d8a108a7 | ||
|
|
7afd9efcc5 | ||
|
|
56ded87ad2 | ||
|
|
82e503339b | ||
|
|
713d0c7ace | ||
|
|
25ad6e3f8f | ||
|
|
df0197b617 | ||
|
|
a89c4f01ad | ||
|
|
ae67099633 | ||
|
|
57542d3a5c | ||
|
|
9a1da14116 | ||
|
|
ed050d753d | ||
|
|
8bec363710 | ||
|
|
7c68e190a9 | ||
|
|
7ebf5ea3d1 | ||
|
|
11e0435a4b | ||
|
|
d15ee57cd1 | ||
|
|
56d660b7fd | ||
|
|
792958e693 | ||
|
|
914e67dc04 | ||
|
|
b50a7ccb61 | ||
|
|
f827709d42 | ||
|
|
36abb42175 | ||
|
|
40f3b1b4c8 | ||
|
|
4f35e25688 | ||
|
|
270e88edd7 | ||
|
|
5ded171247 | ||
|
|
88f6076f3c | ||
|
|
b4d12e08dd | ||
|
|
332dd988e4 | ||
|
|
bce8db41d7 | ||
|
|
f6fd70245d | ||
|
|
4ff0a055d6 | ||
|
|
c9140267a5 | ||
|
|
72fcee4e5e | ||
|
|
9c8e512edd | ||
|
|
3c191af34a | ||
|
|
5e0b2d7370 | ||
|
|
5994abd453 | ||
|
|
67a2d119c0 | ||
|
|
114215088a | ||
|
|
a78e2b793e | ||
|
|
519ed3834e | ||
|
|
22647135fa | ||
|
|
58c741e9ca | ||
|
|
ef9083089e | ||
|
|
5de1582a0a | ||
|
|
39c864e31f | ||
|
|
320cb63df4 | ||
|
|
c246222ded | ||
|
|
b7edb2873c | ||
|
|
89f2032c0d | ||
|
|
d2f8230093 | ||
|
|
9f6b5d169a | ||
|
|
e56708d4aa | ||
|
|
304156c20e | ||
|
|
31e1566e1d | ||
|
|
3908637056 | ||
|
|
abee301f3d | ||
|
|
9b1d3f8f3c | ||
|
|
3513eaf701 | ||
|
|
08a840afe4 | ||
|
|
370f5d461c | ||
|
|
8efc8458e1 | ||
|
|
6485717c52 | ||
|
|
1d5bbd11a8 | ||
|
|
bc403742b5 | ||
|
|
c7f963f57e | ||
|
|
afb6684bde | ||
|
|
ee3d772235 | ||
|
|
1af08f7085 | ||
|
|
ccf23fa273 | ||
|
|
f701defc5f | ||
|
|
c606f05bf8 | ||
|
|
a646153615 | ||
|
|
60380afe15 | ||
|
|
d4b0a977c9 | ||
|
|
f86156ad10 | ||
|
|
1836ee854f | ||
|
|
c37cdeec9f | ||
|
|
b0b2b17908 | ||
|
|
2918732481 | ||
|
|
5a4d5ddb9d | ||
|
|
55afcf678d | ||
|
|
16c7cf9b5e | ||
|
|
432bd29c1c | ||
|
|
a87914ef23 | ||
|
|
041530a953 | ||
|
|
9d4c55161a | ||
|
|
a706d1df00 | ||
|
|
b15b2e666f | ||
|
|
5d4678364e | ||
|
|
1c0f470032 | ||
|
|
9590526430 | ||
|
|
1c6dfda83c | ||
|
|
a8be12940e | ||
|
|
4b5046366b | ||
|
|
a0fff90c26 | ||
|
|
a8daedac5e | ||
|
|
5fa26fb3ac | ||
|
|
ea3e297175 | ||
|
|
92b8789532 | ||
|
|
8f61694057 | ||
|
|
67f7de5305 | ||
|
|
6faecefb73 | ||
|
|
68c5bd44e8 | ||
|
|
3656277053 | ||
|
|
19846ff356 | ||
|
|
a11bd6ebd9 | ||
|
|
db2aaa04fd | ||
|
|
9889bf50a2 | ||
|
|
b48f9aa609 | ||
|
|
d75fb2deda | ||
|
|
7915ab1ec6 | ||
|
|
f0faf88d66 | ||
|
|
7dd7537f5f | ||
|
|
f51680e8d9 | ||
|
|
a6bc072c6d | ||
|
|
85f2508157 | ||
|
|
ebb6c8d637 | ||
|
|
ddc83e270c | ||
|
|
0173148a2e | ||
|
|
69a4ec6c00 | ||
|
|
2d52219af2 | ||
|
|
6355a5b28d | ||
|
|
1f87a9e4c0 | ||
|
|
ba8afde42b | ||
|
|
93f677cba6 | ||
|
|
595bbee41e | ||
|
|
dfd865d67d | ||
|
|
cb3f3a1f64 | ||
|
|
96a04402db | ||
|
|
0e44838905 | ||
|
|
78e644c7c1 | ||
|
|
89cc7fc34e | ||
|
|
974754598e | ||
|
|
87acbb406d | ||
|
|
597517157c | ||
|
|
a0b816be8c | ||
|
|
64cd268fc7 | ||
|
|
4a056924d2 | ||
|
|
d5a81f990c | ||
|
|
f048dd81f2 | ||
|
|
5746f2214c | ||
|
|
099af669d4 | ||
|
|
79cac706a7 | ||
|
|
df229074ac | ||
|
|
191c27e856 | ||
|
|
e5ee01b43c | ||
|
|
c46b040f6f | ||
|
|
da8c92f057 | ||
|
|
866b33c808 | ||
|
|
182daf0b17 | ||
|
|
2552febc2a | ||
|
|
eb9db9b683 | ||
|
|
11dbdfca4d | ||
|
|
f49de9ec10 | ||
|
|
3a7e569a65 | ||
|
|
c376c1a62a | ||
|
|
72e4794f5b | ||
|
|
fbbc52063a | ||
|
|
78b4fe3d07 | ||
|
|
c30b65a0ea | ||
|
|
b8c8b250b1 | ||
|
|
b26d01c8d7 | ||
|
|
1cb08ff60c | ||
|
|
4dbd8a66af | ||
|
|
cb4d739fd1 | ||
|
|
11f913e8fb | ||
|
|
0b6054a919 | ||
|
|
e7620a1050 | ||
|
|
d3d7fd9317 | ||
|
|
acf0f97663 | ||
|
|
34bd87cea7 | ||
|
|
228f11262e | ||
|
|
811a03f281 | ||
|
|
9683e0f1cc | ||
|
|
2528bd0b8f | ||
|
|
ed587be470 | ||
|
|
674ae6d571 | ||
|
|
690d44e2e6 | ||
|
|
55b48874a4 | ||
|
|
720ccdb474 | ||
|
|
a556ff6560 | ||
|
|
33c0af8253 | ||
|
|
86072f95ac | ||
|
|
c7b96bcd7d | ||
|
|
572c18302f | ||
|
|
efd1bdec23 | ||
|
|
ba86f9ff13 | ||
|
|
56b07cb5c0 | ||
|
|
358e32e98f | ||
|
|
01297016bd | ||
|
|
64b5b67661 | ||
|
|
b6f0ec7fd9 | ||
|
|
e9c0b5e0c5 | ||
|
|
4a005ea288 | ||
|
|
9658b69af4 | ||
|
|
e3c9446e29 | ||
|
|
aa240e61d9 | ||
|
|
2954e932ce | ||
|
|
5be79cc858 | ||
|
|
4a9d97d22d | ||
|
|
f4f3433854 | ||
|
|
26bffa3740 | ||
|
|
69e52a9882 | ||
|
|
cc8de48849 | ||
|
|
9d7c119f94 | ||
|
|
6ba9fd1b60 | ||
|
|
fb6250eb94 | ||
|
|
bc73368c96 | ||
|
|
3068f0c62c | ||
|
|
8e00803c83 | ||
|
|
087b69b629 | ||
|
|
3b237267fb | ||
|
|
b9dbb1ed45 | ||
|
|
41d3b29ec0 | ||
|
|
05ceb8b1e2 | ||
|
|
80d3925b8d | ||
|
|
2cd6cbeacc | ||
|
|
6382846f6c | ||
|
|
349d0fd74b | ||
|
|
9c88855bf4 | ||
|
|
f0e6cdfcb5 | ||
|
|
af9864a1b5 | ||
|
|
8ac145e667 | ||
|
|
39f7afc7d0 | ||
|
|
113b974bb7 | ||
|
|
c747a6ff4e | ||
|
|
107d11cfd5 | ||
|
|
a4d2cd94b9 | ||
|
|
3d9fb84fc9 | ||
|
|
e500bc075e | ||
|
|
25e8fa0e11 | ||
|
|
5f27fb2607 | ||
|
|
d977cedb78 | ||
|
|
454b58cdf0 | ||
|
|
82a632b0f9 | ||
|
|
43cbe3f1f8 | ||
|
|
d027cec8a6 | ||
|
|
e53c2c52ee | ||
|
|
5ff0ecc12d | ||
|
|
9c1f421ccb | ||
|
|
66850bc057 | ||
|
|
33da34b4bf | ||
|
|
792cd49310 | ||
|
|
37fdb5e2b0 | ||
|
|
88cd251db7 | ||
|
|
4038d18fc8 | ||
|
|
59bf92a183 | ||
|
|
57879155d2 | ||
|
|
96d43cebc0 | ||
|
|
8e13857b29 | ||
|
|
8c6e454697 | ||
|
|
4c7c7df89b | ||
|
|
515e6d8635 | ||
|
|
bbd941e2df | ||
|
|
3edba1bf19 | ||
|
|
4ad99d8242 | ||
|
|
c0aeaecc14 | ||
|
|
792be9e687 | ||
|
|
fd65337f43 | ||
|
|
9de9726e6f | ||
|
|
522037ca4a | ||
|
|
8fc3d1f718 | ||
|
|
cebaf27ee8 | ||
|
|
b62503f274 | ||
|
|
af50c640ab | ||
|
|
b5c5fbe0f5 | ||
|
|
b88ae8105e | ||
|
|
9ad04bb65e | ||
|
|
13bbaab1c4 | ||
|
|
09ca8d1728 | ||
|
|
9797a93d86 | ||
|
|
d29dae72de | ||
|
|
59fba2bff6 | ||
|
|
0350d4c501 | ||
|
|
d3e4a90e70 | ||
|
|
8ebb19fd18 | ||
|
|
02ddc33e6c | ||
|
|
410e8efeba | ||
|
|
e9f8e0bad9 | ||
|
|
f69e0313dc | ||
|
|
baa9b396d9 | ||
|
|
a82b0c516d | ||
|
|
43e2192aa2 | ||
|
|
4cd6453cac | ||
|
|
921d4c24c2 | ||
|
|
4fc7653b12 | ||
|
|
9d0e39a7c2 | ||
|
|
7aa979cf5b | ||
|
|
0aa50614d7 | ||
|
|
6f402c7362 | ||
|
|
2bf43a124d | ||
|
|
3573c53eda | ||
|
|
4546ec4ef7 | ||
|
|
2f7337aaf6 | ||
|
|
046698bcc2 | ||
|
|
06d7bf21d5 | ||
|
|
e7b9ccdf10 | ||
|
|
1e15b043a0 | ||
|
|
6c5f3d76e2 | ||
|
|
8679d6f6af | ||
|
|
f1c7d0f354 | ||
|
|
261e413500 | ||
|
|
094e41d7a7 | ||
|
|
e20299c8ee | ||
|
|
f8962b7ad2 | ||
|
|
c34f829c3e | ||
|
|
46264e4a4a | ||
|
|
096df68ea6 | ||
|
|
35f2055a1e | ||
|
|
e1353eefb3 | ||
|
|
4911a532bf | ||
|
|
96362e03aa | ||
|
|
049b4e09fe | ||
|
|
828c0e28af | ||
|
|
15a638edc0 | ||
|
|
fc8f1b1075 | ||
|
|
318a8e38c9 | ||
|
|
f0dbb02a9f | ||
|
|
649b777b76 | ||
|
|
6fad43670a | ||
|
|
e24b16229e | ||
|
|
21b4b81810 | ||
|
|
1096b1e28e | ||
|
|
03458fedef | ||
|
|
c1a2004344 | ||
|
|
2adb13a209 | ||
|
|
dba194ddb9 | ||
|
|
8179f041e6 | ||
|
|
a13c7a4d84 | ||
|
|
bbf92bb971 | ||
|
|
b33f413635 | ||
|
|
58ffb2bc16 | ||
|
|
0ed112631c | ||
|
|
9cfe8e9422 | ||
|
|
7d3fe72970 | ||
|
|
ac422138fa | ||
|
|
bf8746454a | ||
|
|
b61aa5b4ba | ||
|
|
c2bcd08168 | ||
|
|
48593b8868 | ||
|
|
83d4dc1831 | ||
|
|
0696f3cc41 | ||
|
|
515590495a | ||
|
|
7221bca909 | ||
|
|
ed64a8cd12 | ||
|
|
cbd30d22ff | ||
|
|
0c74dbd436 | ||
|
|
49356cc931 | ||
|
|
ceee6e8b17 | ||
|
|
61ab2754d2 | ||
|
|
2de3df61e8 | ||
|
|
b84d7aa06d | ||
|
|
ed48f900a3 | ||
|
|
d197a49707 | ||
|
|
b8ccaa3bf6 | ||
|
|
507a684b21 | ||
|
|
c969c9387a | ||
|
|
1709db4953 | ||
|
|
4d1c9ba316 | ||
|
|
45b0396355 | ||
|
|
1df2169e48 | ||
|
|
2c056b3621 | ||
|
|
680119006c | ||
|
|
c4ac4b7538 | ||
|
|
ff5d3b49ca | ||
|
|
e101c878f0 | ||
|
|
125193dcfa | ||
|
|
77efa9810d | ||
|
|
7f03d1917b | ||
|
|
55b4ca9350 | ||
|
|
7196a0f9d2 | ||
|
|
2caabde5ca | ||
|
|
137d7663c1 | ||
|
|
508b71a921 | ||
|
|
5d90820005 | ||
|
|
84727e90b1 | ||
|
|
9a1e3d3320 | ||
|
|
d33e0c8ee1 | ||
|
|
3332649480 | ||
|
|
c918b66199 | ||
|
|
dbbf56e17a | ||
|
|
c77500c15a | ||
|
|
75084aaa96 | ||
|
|
35714c8f1c | ||
|
|
3699cc97a6 | ||
|
|
5a7377acda | ||
|
|
6aaee629b5 | ||
|
|
b465fe569c | ||
|
|
5e6f72a688 | ||
|
|
51f80f6c15 | ||
|
|
45c314e594 | ||
|
|
cfce0892e0 | ||
|
|
05d1abf030 | ||
|
|
6c24a2626b | ||
|
|
870c75bd12 | ||
|
|
5fdd771708 | ||
|
|
06f39ac409 | ||
|
|
c92b0a2fb7 | ||
|
|
8a8d0e05ca | ||
|
|
74bae2baac | ||
|
|
4ba48676bd | ||
|
|
78480e7951 | ||
|
|
4cb9c412e8 | ||
|
|
75c83fed96 | ||
|
|
391de20ae0 | ||
|
|
1e2a9e8971 | ||
|
|
43cbd3a283 | ||
|
|
31cf6b5e64 | ||
|
|
99109ab78b | ||
|
|
a80d5f159d | ||
|
|
7ba4fc4aed | ||
|
|
9fb31e9868 | ||
|
|
3a2246de5b | ||
|
|
e7c4e2fa57 | ||
|
|
724ab285f0 | ||
|
|
d60e66fb00 | ||
|
|
97cdaca028 | ||
|
|
3044c8f905 | ||
|
|
2775a2a945 | ||
|
|
c43c1febba | ||
|
|
ceb6471d57 | ||
|
|
b99cc044f3 | ||
|
|
d91429dcec | ||
|
|
b1d1f7d8f1 | ||
|
|
86b608cf41 | ||
|
|
f263f75751 | ||
|
|
24bec05b86 | ||
|
|
ce1a5e9359 | ||
|
|
311525bc06 | ||
|
|
ecdfd96529 | ||
|
|
5aab32bc1a | ||
|
|
e152a1c6f2 | ||
|
|
e84fde78ec | ||
|
|
6ec4652bcf | ||
|
|
a5239c820b | ||
|
|
41b001b22c | ||
|
|
34e903b8b0 | ||
|
|
2b67e953fd | ||
|
|
aa0d3adf1d | ||
|
|
a1f57a8a80 | ||
|
|
6bc82a8580 | ||
|
|
c4c2e5d3a2 | ||
|
|
dd7d4b2173 | ||
|
|
2719c4d545 | ||
|
|
33c1e36b54 | ||
|
|
e7e46e185e | ||
|
|
9200d48873 | ||
|
|
831d054d24 | ||
|
|
f3af804ddb | ||
|
|
1f35149ef0 | ||
|
|
554a18842f | ||
|
|
869243b6d1 | ||
|
|
c0da02326a | ||
|
|
9b5f666fc5 | ||
|
|
1ce93426a4 | ||
|
|
6dacf3478b | ||
|
|
dff91699c3 | ||
|
|
9f83e8c1fc | ||
|
|
7b07cb0759 | ||
|
|
c2e7091632 | ||
|
|
1ab320042e | ||
|
|
b0cd307eaf | ||
|
|
ca2cf20cf3 | ||
|
|
b3acba1d2d | ||
|
|
6d2731c463 | ||
|
|
b7f8f8867c |
273
build/Jamfile.v2
Normal file
273
build/Jamfile.v2
Normal file
@@ -0,0 +1,273 @@
|
||||
# $Id$
|
||||
# Copyright 2006-2007 Roland Schwarz.
|
||||
# Copyright 2007 Anthony Williams
|
||||
# Copyright 2011-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)
|
||||
|
||||
#########################################################################
|
||||
# The boost threading library can be built on top of different API's
|
||||
# Currently this is the win32 API and the pthreads API.
|
||||
# Pthread is native on unix variants.
|
||||
# To get pthread on windows you need the pthread win32 library
|
||||
# http://sourceware.org/pthreads-win32 which is available under LGPL.
|
||||
#
|
||||
# You need to provide the include path and lib path in the variables
|
||||
# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
|
||||
# paths in site-config.jam, user-config.jam or in the environment.
|
||||
# A new feature is provided to request a specific API:
|
||||
# <threadapi>win32 and <threadapi)pthread.
|
||||
#
|
||||
# The naming of the resulting libraries is mostly the same for the
|
||||
# variant native to the build platform, i.e.
|
||||
# boost_thread and the boost specific tagging.
|
||||
# For the library variant that is not native on the build platform
|
||||
# an additional tag is applied:
|
||||
# boost_thread_pthread for the pthread variant on windows, and
|
||||
# boost_thread_win32 for the win32 variant (likely when built on cygwin).
|
||||
#
|
||||
# To request the pthread variant on windows, from boost root you would
|
||||
# say e.g:
|
||||
# bjam msvc-8.0 --with-thread install threadapi=pthread
|
||||
#########################################################################
|
||||
|
||||
import os ;
|
||||
import feature ;
|
||||
import indirect ;
|
||||
import path ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
: requirements <threading>multi
|
||||
#<link>static:<define>BOOST_THREAD_STATIC_LINK=1
|
||||
#<link>shared:<define>BOOST_THREAD_DYN_LINK=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
|
||||
<tag>@$(__name__).tag
|
||||
<toolset>gcc:<cxxflags>-Wno-long-long
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
<library>/boost/system//boost_system
|
||||
#-pedantic -ansi -std=gnu++0x -Wextra -fpermissive
|
||||
<warnings>all
|
||||
<toolset>gcc:<cxxflags>-Wextra
|
||||
<toolset>gcc:<cxxflags>-pedantic
|
||||
<toolset>gcc:<cxxflags>-Wno-long-long
|
||||
#<toolset>gcc:<cxxflags>-ansi
|
||||
#<toolset>gcc:<cxxflags>-fpermissive
|
||||
|
||||
<toolset>darwin:<cxxflags>-Wextra
|
||||
<toolset>darwin:<cxxflags>-pedantic
|
||||
<toolset>darwin:<cxxflags>-ansi
|
||||
<toolset>darwin:<cxxflags>-fpermissive
|
||||
<toolset>darwin:<cxxflags>-Wno-long-long
|
||||
|
||||
#<toolset>pathscale:<cxxflags>-Wextra
|
||||
<toolset>pathscale:<cxxflags>-Wno-long-long
|
||||
<toolset>pathscale:<cxxflags>-pedantic
|
||||
|
||||
<toolset>clang:<cxxflags>-Wextra
|
||||
<toolset>clang:<cxxflags>-pedantic
|
||||
<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
|
||||
<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.6.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.6.3:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.7.0:<cxxflags>-fdiagnostics-show-option
|
||||
<toolset>gcc-mingw-4.8.0:<cxxflags>-fdiagnostics-show-option
|
||||
|
||||
<toolset>darwin-4.6.2:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
<toolset>darwin-4.7.0:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
|
||||
#<toolset>clang-2.8:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
#<toolset>clang-2.8:<cxxflags>-Wno-unused-function
|
||||
#<toolset>clang-2.9:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
#<toolset>clang-2.9:<cxxflags>-Wno-unused-function
|
||||
<toolset>clang-3.0:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
#<toolset>clang-3.0:<cxxflags>-Wno-unused-function
|
||||
#<toolset>clang-3.0:<cxxflags>-Wno-unused-variable
|
||||
|
||||
|
||||
# : default-build <threading>multi
|
||||
: usage-requirements # pass these requirement to dependents (i.e. users)
|
||||
#<link>static:<define>BOOST_THREAD_STATIC_LINK=1
|
||||
#<link>shared:<define>BOOST_THREAD_DYN_LINK=1
|
||||
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
|
||||
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
|
||||
<define>BOOST_SYSTEM_NO_DEPRECATED
|
||||
<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 ] ;
|
||||
|
||||
rule tag ( name : type ? : property-set )
|
||||
{
|
||||
local result = $(name) ;
|
||||
|
||||
if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB
|
||||
{
|
||||
local api = [ $(property-set).get <threadapi> ] ;
|
||||
|
||||
# non native api gets additional tag
|
||||
if $(api) != [ default_threadapi ] {
|
||||
result = $(result)_$(api) ;
|
||||
}
|
||||
}
|
||||
|
||||
# forward to the boost tagging rule
|
||||
return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
|
||||
$(result) : $(type) : $(property-set) ] ;
|
||||
}
|
||||
|
||||
rule win32_pthread_paths ( properties * )
|
||||
{
|
||||
local result ;
|
||||
local PTW32_INCLUDE ;
|
||||
local PTW32_LIB ;
|
||||
PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
|
||||
PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
|
||||
PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
|
||||
PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
|
||||
|
||||
if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
|
||||
{
|
||||
if ! $(.notified)
|
||||
{
|
||||
echo "************************************************************" ;
|
||||
echo "Trying to build Boost.Thread with pthread support." ;
|
||||
echo "If you need pthread you should specify the paths." ;
|
||||
echo "You can specify them in site-config.jam, user-config.jam" ;
|
||||
echo "or in the environment." ;
|
||||
echo "For example:" ;
|
||||
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
|
||||
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
|
||||
echo "************************************************************" ;
|
||||
.notified = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
local include_path = [ path.make $(PTW32_INCLUDE) ] ;
|
||||
local lib_path = [ path.make $(PTW32_LIB) ] ;
|
||||
local libname = pthread ;
|
||||
if <toolset>msvc in $(properties)
|
||||
{
|
||||
libname = $(libname)VC2.lib ;
|
||||
}
|
||||
if <toolset>gcc in $(properties)
|
||||
{
|
||||
libname = lib$(libname)GC2.a ;
|
||||
}
|
||||
lib_path = [ path.glob $(lib_path) : $(libname) ] ;
|
||||
if ! $(lib_path)
|
||||
{
|
||||
if ! $(.notified)
|
||||
{
|
||||
echo "************************************************************" ;
|
||||
echo "Trying to build Boost.Thread with pthread support." ;
|
||||
echo "But the library" $(libname) "could not be found in path" ;
|
||||
echo $(PTW32_LIB) ;
|
||||
echo "************************************************************" ;
|
||||
.notified = true ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
result += <include>$(include_path) ;
|
||||
result += <library>$(lib_path) ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
rule usage-requirements ( properties * )
|
||||
{
|
||||
local result ;
|
||||
if <threadapi>pthread in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_POSIX ;
|
||||
if <target-os>windows in $(properties)
|
||||
{
|
||||
result += [ win32_pthread_paths $(properties) ] ;
|
||||
# TODO: What is for static linking? Is the <library> also needed
|
||||
# in that case?
|
||||
}
|
||||
}
|
||||
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties)
|
||||
{
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
rule requirements ( properties * )
|
||||
{
|
||||
local result ;
|
||||
|
||||
if <threadapi>pthread in $(properties)
|
||||
{
|
||||
result += <define>BOOST_THREAD_POSIX ;
|
||||
if <target-os>windows in $(properties)
|
||||
{
|
||||
local paths = [ win32_pthread_paths $(properties) ] ;
|
||||
if $(paths)
|
||||
{
|
||||
result += $(paths) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = <build>no ;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties)
|
||||
{
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
alias thread_sources
|
||||
: ## win32 sources ##
|
||||
win32/thread.cpp
|
||||
win32/tss_dll.cpp
|
||||
win32/tss_pe.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>win32
|
||||
;
|
||||
|
||||
alias thread_sources
|
||||
: ## pthread sources ##
|
||||
pthread/thread.cpp
|
||||
pthread/once.cpp
|
||||
: ## requirements ##
|
||||
<threadapi>pthread
|
||||
;
|
||||
|
||||
explicit thread_sources ;
|
||||
|
||||
lib boost_thread
|
||||
: thread_sources future.cpp
|
||||
: <conditional>@requirements
|
||||
:
|
||||
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
|
||||
<link>static:<define>BOOST_THREAD_USE_LIB=1
|
||||
<conditional>@usage-requirements
|
||||
;
|
||||
32
doc/Jamfile.v2
Normal file
32
doc/Jamfile.v2
Normal file
@@ -0,0 +1,32 @@
|
||||
# (C) Copyright 2008-11 Anthony Williams
|
||||
# (C) Copyright 2011-12 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)
|
||||
|
||||
path-constant boost-images : ../../../doc/src/images ;
|
||||
|
||||
xml thread : thread.qbk ;
|
||||
|
||||
boostbook standalone
|
||||
:
|
||||
thread
|
||||
:
|
||||
# HTML options first:
|
||||
# Use graphics not text for navigation:
|
||||
<xsl:param>navig.graphics=1
|
||||
# How far down we chunk nested sections, basically all of them:
|
||||
<xsl:param>chunk.section.depth=2
|
||||
# Don't put the first section on the same page as the TOC:
|
||||
<xsl:param>chunk.first.sections=1
|
||||
# How far down sections get TOC's
|
||||
<xsl:param>toc.section.depth=4
|
||||
# Max depth in each TOC:
|
||||
<xsl:param>toc.max.depth=2
|
||||
# How far down we go with TOC's
|
||||
<xsl:param>generate.section.toc.level=10
|
||||
# Path for links to Boost:
|
||||
<xsl:param>boost.root=../../../..
|
||||
;
|
||||
|
||||
|
||||
23
doc/acknowledgements.qbk
Normal file
23
doc/acknowledgements.qbk
Normal file
@@ -0,0 +1,23 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:acknowledgements Acknowledgments]
|
||||
|
||||
The original implementation of __boost_thread__ was written by William Kempf, with contributions from numerous others. This new
|
||||
version initially grew out of an attempt to rewrite __boost_thread__ to William Kempf's design with fresh code that could be
|
||||
released under the Boost Software License. However, as the C++ Standards committee have been actively discussing standardizing a
|
||||
thread library for C++, this library has evolved to reflect the proposals, whilst retaining as much backwards-compatibility as
|
||||
possible.
|
||||
|
||||
Particular thanks must be given to Roland Schwarz, who contributed a lot of time and code to the original __boost_thread__ library,
|
||||
and who has been actively involved with the rewrite. The scheme for dividing the platform-specific implementations into separate
|
||||
directories was devised by Roland, and his input has contributed greatly to improving the quality of the current implementation.
|
||||
|
||||
Thanks also must go to Peter Dimov, Howard Hinnant, Alexander Terekhov, Chris Thomasson and others for their comments on the
|
||||
implementation details of the code.
|
||||
|
||||
[endsect]
|
||||
72
doc/barrier.qbk
Normal file
72
doc/barrier.qbk
Normal file
@@ -0,0 +1,72 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:barriers Barriers]
|
||||
|
||||
A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is
|
||||
configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have
|
||||
arrived. Once the `n`-th thread has reached the barrier, all the waiting threads can proceed, and the barrier is reset.
|
||||
|
||||
[section:barrier Class `barrier`]
|
||||
|
||||
#include <boost/thread/barrier.hpp>
|
||||
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count);
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
};
|
||||
|
||||
Instances of __barrier__ are not copyable or movable.
|
||||
|
||||
[heading Constructor]
|
||||
|
||||
barrier(unsigned int count);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Construct a barrier for `count` threads.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[heading Destructor]
|
||||
|
||||
~barrier();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [No threads are waiting on `*this`.]]
|
||||
|
||||
[[Effects:] [Destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[heading Member function `wait`]
|
||||
|
||||
bool wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads
|
||||
are unblocked, and the barrier is reset. ]]
|
||||
|
||||
[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
228
doc/changes.qbk
Normal file
228
doc/changes.qbk
Normal file
@@ -0,0 +1,228 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-12 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:changes History]
|
||||
|
||||
[heading Version 3.0.1 - boost 1.51]
|
||||
|
||||
Deprecated features since boost 1.50 available only until boost 1.55:
|
||||
|
||||
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
|
||||
|
||||
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
|
||||
|
||||
Breaking changes when BOOST_THREAD_VERSION==3:
|
||||
|
||||
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 3, but the user can however choose the version 2 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Rename the unique_future to future following the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
|
||||
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4258 #4258] Linking with boost thread does not work on mingw/gcc 4.5.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4885 #4885] Access violation in set_tss_data at process exit due to invalid assumption about TlsAlloc.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel Compiler and /debug:parallel
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7044 #7044] boost 1.50.0 header missing.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7052 #7052] Thread: BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 only masks thread::operator==, thread::operator!= forward declarations, not definitions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7066 #7066] An attempt to fix current_thread_tls_key static initialization order.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7074 #7074] Multiply defined symbol boost::allocator_arg.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7078 #7078] Trivial 64-bit warning fix on Windows for thread attribute stack size
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7089 #7089] BOOST_THREAD_WAIT_BUG limits functionality without solving anything
|
||||
|
||||
|
||||
[heading Version 3.0.0 - boost 1.50]
|
||||
|
||||
Breaking changes when BOOST_THREAD_VERSION==3:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Breaking change: Rename the unique_future to future following the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
|
||||
|
||||
New Features:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/1850 #1850] Request for unlock_guard to compliment lock_guard.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2637 #2637] Request for shared_mutex duration timed_lock and timed_lock_shared.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2741 #2741] Proposal to manage portable and non portable thread attributes.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3567 #3567] Request for shared_lock_guard.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6194 #6194] Adapt to Boost.Move.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6195 #6195] c++11 compliance: Provide the standard time related interface using Boost.Chrono.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6217 #6217] Enhance Boost.Thread shared mutex interface following Howard Hinnant proposal.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6224 #6224] c++11 compliance: Add the use of standard noexcept on compilers supporting them.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6225 #6225] Add the use of standard =delete defaulted operations on compilers supporting them.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6226 #6226] c++11 compliance: Add explicit bool conversion from locks.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6228 #6228] Add promise constructor with allocator following the standard c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6230 #6230] c++11 compliance: Follows the exception reporting mechanism as defined in the c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6231 #6231] Add BasicLockable requirements in the documentation to follow c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6272 #6272] c++11 compliance: Add thread::id hash specialization.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6273 #6273] c++11 compliance: Add cv_status enum class and use it on the conditions wait functions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6342 #6342] c++11 compliance: Adapt the one_flag to the c++11 interface.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6671 #6671] upgrade_lock: missing mutex and release functions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6672 #6672] upgrade_lock:: missing constructors from time related types.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6675 #6675] upgrade_lock:: missing non-member swap.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6676 #6676] lock conversion should be explicit.
|
||||
* Added missing packaged_task::result_type and packaged_task:: constructor with allocator.
|
||||
* Added packaged_task::reset()
|
||||
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2380 #2380] boost::move from lvalue does not work with gcc.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2430 #2430] shared_mutex for win32 doesn't have timed_lock_upgrade.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2575 #2575] Bug- Boost 1.36.0 on Itanium platform.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3160 #3160] Duplicate tutorial code in boost::thread.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4345 #4345] thread::id and joining problem with cascade of threads.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4521 #4521] Error using boost::move on packaged_task (MSVC 10).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4711 #4711] Must use implementation details to return move-only types.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4921 #4921] BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB are crucial and need to be documented.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5013 #5013] documentation: boost::thread: pthreas_exit causes terminate().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5173 #5173] boost::this_thread::get_id is very slow.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5351 #5351] interrupt a future get boost::unknown_exception.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5516 #5516] Upgrade lock is not acquired when previous upgrade lock releases if another read lock is present.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5990 #5990] shared_future<T>::get() has wrong return type.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6174 #6174] packaged_task doesn't correctly handle moving results.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6222 #6222] Compile error with SunStudio: unique_future move.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6354 #6354] PGI: Compiler threading support is not turned on.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6673 #6673] shared_lock: move assign doesn't works with c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6674 #6674] shared_mutex: try_lock_upgrade_until doesn't works.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6908 #6908] Compile error due to unprotected definitions of _WIN32_WINNT and WINVER.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6940 #6940] TIME_UTC is a macro in C11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6959 #6959] call of abs is ambiguous.
|
||||
* Fix issue signaled on the ML with task_object(task_object const&) in presence of task_object(task_object &&)
|
||||
|
||||
|
||||
|
||||
[heading Version 2.1.1 - boost 1.49]
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2309 #2309] Lack of g++ symbol visibility support in Boost.Thread.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2639 #2639] documentation should be extended(defer_lock, try_to_lock, ...).
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3639 #3639] Boost.Thread doesn't build with Sun-5.9 on Linux.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3762 #3762] Thread can't be compiled with winscw (Codewarrior by Nokia).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3885 #3885] document about mix usage of boost.thread and native thread api.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3975 #3975] Incorrect precondition for promise::set_wait_callback().
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4048 #4048] thread::id formatting involves locale
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4315 #4315] gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5839 #5839] thread.cpp: ThreadProxy leaks on exceptions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6207 #6207] shared_lock swap compiler error on clang 3.0 c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6208 #6208] try_lock_wrapper swap compiler error on clang 3.0 c++11.
|
||||
|
||||
[heading Version 2.1.0 - Changes since boost 1.40]
|
||||
|
||||
The 1.41.0 release of Boost adds futures to the thread library. There are also a few minor changes.
|
||||
|
||||
[heading Changes since boost 1.35]
|
||||
|
||||
The 1.36.0 release of Boost includes a few new features in the thread library:
|
||||
|
||||
* New generic __lock_multiple_ref__ and __try_lock_multiple_ref__ functions for locking multiple mutexes at once.
|
||||
|
||||
* Rvalue reference support for move semantics where the compilers supports it.
|
||||
|
||||
* A few bugs fixed and missing functions added (including the serious win32 condition variable bug).
|
||||
|
||||
* `scoped_try_lock` types are now backwards-compatible with Boost 1.34.0 and previous releases.
|
||||
|
||||
* Support for passing function arguments to the thread function by supplying additional arguments to the __thread__ constructor.
|
||||
|
||||
* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts.
|
||||
|
||||
[heading Version 2.0.0 - Changes since boost 1.34]
|
||||
|
||||
Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface
|
||||
changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking
|
||||
changes are described below.
|
||||
|
||||
[heading New Features]
|
||||
|
||||
* Instances of __thread__ and of the various lock types are now movable.
|
||||
|
||||
* Threads can be interrupted at __interruption_points__.
|
||||
|
||||
* Condition variables can now be used with any type that implements the __lockable_concept__, through the use of
|
||||
`boost::condition_variable_any` (`boost::condition` is a `typedef` to `boost::condition_variable_any`, provided for backwards
|
||||
compatibility). `boost::condition_variable` is provided as an optimization, and will only work with
|
||||
`boost::unique_lock<boost::mutex>` (`boost::mutex::scoped_lock`).
|
||||
|
||||
* Thread IDs are separated from __thread__, so a thread can obtain it's own ID (using `boost::this_thread::get_id()`), and IDs can
|
||||
be used as keys in associative containers, as they have the full set of comparison operators.
|
||||
|
||||
* Timeouts are now implemented using the Boost DateTime library, through a typedef `boost::system_time` for absolute timeouts, and
|
||||
with support for relative timeouts in many cases. `boost::xtime` is supported for backwards compatibility only.
|
||||
|
||||
* Locks are implemented as publicly accessible templates `boost::lock_guard`, `boost::unique_lock`, `boost::shared_lock`, and
|
||||
`boost::upgrade_lock`, which are templated on the type of the mutex. The __lockable_concept__ has been extended to include publicly
|
||||
available __lock_ref__ and __unlock_ref__ member functions, which are used by the lock types.
|
||||
|
||||
[heading Breaking Changes]
|
||||
|
||||
The list below should cover all changes to the public interface which break backwards compatibility.
|
||||
|
||||
* __try_mutex__ has been removed, and the functionality subsumed into __mutex__. __try_mutex__ is left as a `typedef`,
|
||||
but is no longer a separate class.
|
||||
|
||||
* __recursive_try_mutex__ has been removed, and the functionality subsumed into
|
||||
__recursive_mutex__. __recursive_try_mutex__ is left as a `typedef`, but is no longer a separate class.
|
||||
|
||||
* `boost::detail::thread::lock_ops` has been removed. Code that relies on the `lock_ops` implementation detail will no longer work,
|
||||
as this has been removed, as it is no longer necessary now that mutex types now have public __lock_ref__ and __unlock_ref__ member
|
||||
functions.
|
||||
|
||||
* `scoped_lock` constructors with a second parameter of type `bool` are no longer provided. With previous boost releases,
|
||||
``boost::mutex::scoped_lock some_lock(some_mutex,false);`` could be used to create a lock object that was associated with a mutex,
|
||||
but did not lock it on construction. This facility has now been replaced with the constructor that takes a
|
||||
`boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);``
|
||||
|
||||
* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__.
|
||||
|
||||
* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not
|
||||
associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has
|
||||
been moved to __thread_id__.
|
||||
|
||||
* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__.
|
||||
|
||||
* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
|
||||
|
||||
* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
|
||||
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:future Future]
|
||||
|
||||
The following features will be included in next releases.
|
||||
|
||||
# Complete the C++11 missing features, in particular
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] Missing async().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Use of variadic templates on Generic Locking Algorithms on compilers providing them.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6270 #6270] Add thread constructor from movable callable and movable arguments following C++11.
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
110
doc/compliance.qbk
Normal file
110
doc/compliance.qbk
Normal file
@@ -0,0 +1,110 @@
|
||||
[/
|
||||
(C) Copyright 2011-12 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]
|
||||
|
||||
|
||||
[table C++11 standard Conformance
|
||||
[[Section] [Description] [Status] [Comments] [Ticket]]
|
||||
[[30] [Thread support library] [Partial] [-] [-]]
|
||||
[[30.1] [General] [-] [-] [-]]
|
||||
[[30.2] [Requirements] [-] [-] [-]]
|
||||
[[30.2.1] [Template parameter names] [-] [-] [-]]
|
||||
[[30.2.2] [Exceptions] [Yes] [-] [-]]
|
||||
[[30.2.3] [Native handles] [Yes] [-] [-]]
|
||||
[[30.2.4] [Timing specifications] [Yes] [-] [-]]
|
||||
[[30.2.5] [Requirements for Lockable types] [Yes] [-] [-]]
|
||||
[[30.2.5.1] [In general] [-] [-] [-]]
|
||||
[[30.2.5.2] [BasicLockable requirements] [Yes] [-] [-]]
|
||||
[[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
|
||||
[[30.2.5.4] [TimedLockable requirements] [Yes] [-] [-]]
|
||||
[[30.2.6] [decay_copy] [-] [-] [-]]
|
||||
[[30.3] [Threads] [Partial] [-] [-]]
|
||||
[[30.3.1] [Class thread] [Partial] [move,variadic,terminate] [#zzzz,#6270,#6269]]
|
||||
[[30.3.1.1] [Class thread::id] [Yes] [-] [-]]
|
||||
[[30.3.1.2] [thread constructors] [Partial] [move,variadic] [#zzzz,#6270]]
|
||||
[[30.3.1.3] [thread destructor] [Partial] [terminate] [#6266]]
|
||||
[[30.3.1.4] [thread assignment] [Partial] [terminate] [#6269]]
|
||||
[[30.3.1.5] [thread members] [Yes] [-] [-]]
|
||||
[[30.3.1.6] [thread static members] [Yes] [-] [-]]
|
||||
[[30.3.1.7] [thread specialized algorithms] [Yes] [-] [-]]
|
||||
|
||||
[[30.3.2] [Namespace this_thread] [Yes] [-] [-]]
|
||||
[[30.4] [Mutual exclusion] [Partial] [-] [-]]
|
||||
[[30.4.1] [Mutex requirements] [Yes] [-] [-]]
|
||||
[[30.4.1.1] [In general] [Yes] [-] [-]]
|
||||
[[30.4.1.2] [Mutex types] [Yes] [-] [-]]
|
||||
[[30.4.1.2.1] [Class mutex] [Yes] [-] [-]]
|
||||
[[30.4.1.2.2] [Class recursive_mutex] [Yes] [-] [-]]
|
||||
[[30.4.1.3] [Timed mutex types] [Yes] [-] [-]]
|
||||
[[30.4.1.3.1] [Class timed_mutex] [Yes] [-] [-]]
|
||||
[[30.4.1.3.1] [Class recursive_timed_mutex] [Yes] [-] [-]]
|
||||
[[30.4.2] [Locks] [Partial] [variadic] [#6227]]
|
||||
[[30.4.2.1] [Class template lock_guard] [Yes] [-] [-]]
|
||||
[[30.4.2.2] [Class template unique_lock] [Yes] [-] [-]]
|
||||
[[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Yes] [-] [-]]
|
||||
[[30.4.2.2.2] [unique_lock locking] [Yes] [-] [-]]
|
||||
[[30.4.2.2.3] [unique_lock modifiers] [Yes] [-] [-]]
|
||||
[[30.4.2.2.4] [unique_lock observers] [Yes] [] [-]]
|
||||
[[30.4.3] [Generic locking algorithms] [Partial] [variadic] [#6227]]
|
||||
[[30.4.4] [Call once] [Partial] [The interface doesn't corresponds] [#6342]]
|
||||
[[30.4.4.1] [Struct once_flag] [Partial] [interface] [#6342]]
|
||||
[[30.4.4.2] [Function call_once] [Partial] [interface] [#6342]]
|
||||
[[30.5] [Condition variables] [Partial] [notify_all_at_thread_exit] [#xxxx]]
|
||||
[[30.5 6-10] [Function notify_all_at_thread_exit] [No] [-] [#xxxx]]
|
||||
[[30.5.1] [Class condition_variable] [Yes] [-] [-]]
|
||||
[[30.5.2] [Class condition_variable_any] [Yes] [-] [-]]
|
||||
[[30.6] [Futures] [Partial] [-] [-]]
|
||||
[[30.6.1] [Overview] [Partial] [-] [-]]
|
||||
[[30.6.2] [Error handling] [Yes] [-] [-]]
|
||||
[[30.6.3] [Class future_error] [Yes] [-] [-]]
|
||||
[[30.6.4] [Shared state] [-] [-] [-]]
|
||||
[[30.6.5] [Class template promise] [Partial] [allocator] [#6228]]
|
||||
[[30.6.6] [Class template future] [Partial] [allocator,unique_future is the closest to future, renamed in V3] [#6228]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [allocator] [#6228]]
|
||||
[[30.6.8] [Function template async] [No] [async] [#4710]]
|
||||
[[30.6.9] [Class template packaged_task] [Partial] [move] [#yyyy]]
|
||||
]
|
||||
|
||||
[/
|
||||
[table Extension
|
||||
[[Section] [Description] [Comments]]
|
||||
[[30.3.1.5.x] [interrupt] [-]]
|
||||
[[30.3.2.x] [Interruption] [-]]
|
||||
[[30.3.2.y] [at_thread_exit] [-]]
|
||||
[[30.4.3.x] [Generic locking algorithms begin/end] [-]]
|
||||
[[30.x] [Barriers] [-]]
|
||||
[[30.y] [Thread Local Storage] [-]]
|
||||
[[30.z] [Class thread_group] [-]]
|
||||
]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:shared Shared Locking extensions]
|
||||
|
||||
[table Howard's Shared Locking Proposal Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X] [Shared Locking] [Yes] [Needs `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION]]
|
||||
[[X.1] [Shared Lockables Concepts] [Yes] [ - ]]
|
||||
[[X.1.1] [SharedLockable concept] [Yes] [ - ]]
|
||||
[[X.1.2] [UpgradeLockable concept] [Yes] [ - ]]
|
||||
[[X.2] [Shared Mutex Types] [Yes] [ - ]]
|
||||
[[X.2.1] [shared_mutex class] [Yes] [ - ]]
|
||||
[[X.2.2] [upgrade_mutex class] [Yes] [ - ]]
|
||||
[[X.3] [Locks] [Yes] [-]]
|
||||
[[X.3.1] [unique_lock class adaptations] [Yes] [-]]
|
||||
[[X.3.2] [shared_lock class] [Yes] [ - ]]
|
||||
[[X.3.3] [upgrade_lock class] [Yes] [-]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
764
doc/condition_variables.qbk
Normal file
764
doc/condition_variables.qbk
Normal file
@@ -0,0 +1,764 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-12 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:condvar_ref Condition Variables]
|
||||
|
||||
[heading Synopsis]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
enum class cv_status;
|
||||
{
|
||||
no_timeout,
|
||||
timeout
|
||||
};
|
||||
class condition_variable;
|
||||
class condition_variable_any;
|
||||
}
|
||||
|
||||
The classes `condition_variable` and `condition_variable_any` provide a
|
||||
mechanism for one thread to wait for notification from another thread that a
|
||||
particular condition has become true. The general usage pattern is that one
|
||||
thread locks a mutex and then calls `wait` on an instance of
|
||||
`condition_variable` or `condition_variable_any`. When the thread is woken from
|
||||
the wait, then it checks to see if the appropriate condition is now true, and
|
||||
continues if so. If the condition is not true, then the thread then calls `wait`
|
||||
again to resume waiting. In the simplest case, this condition is just a boolean
|
||||
variable:
|
||||
|
||||
boost::condition_variable cond;
|
||||
boost::mutex mut;
|
||||
bool data_ready;
|
||||
|
||||
void process_data();
|
||||
|
||||
void wait_for_data_to_process()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lock(mut);
|
||||
while(!data_ready)
|
||||
{
|
||||
cond.wait(lock);
|
||||
}
|
||||
process_data();
|
||||
}
|
||||
|
||||
Notice that the `lock` is passed to `wait`: `wait` will atomically add the
|
||||
thread to the set of threads waiting on the condition variable, and unlock the
|
||||
mutex. When the thread is woken, the mutex will be locked again before the call
|
||||
to `wait` returns. This allows other threads to acquire the mutex in order to
|
||||
update the shared data, and ensures that the data associated with the condition
|
||||
is correctly synchronized.
|
||||
|
||||
In the mean time, another thread sets the condition to `true`, and then calls
|
||||
either `notify_one` or `notify_all` on the condition variable to wake one
|
||||
waiting thread or all the waiting threads respectively.
|
||||
|
||||
void retrieve_data();
|
||||
void prepare_data();
|
||||
|
||||
void prepare_data_for_processing()
|
||||
{
|
||||
retrieve_data();
|
||||
prepare_data();
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mut);
|
||||
data_ready=true;
|
||||
}
|
||||
cond.notify_one();
|
||||
}
|
||||
|
||||
Note that the same mutex is locked before the shared data is updated, but that
|
||||
the mutex does not have to be locked across the call to `notify_one`.
|
||||
|
||||
This example uses an object of type `condition_variable`, but would work just as
|
||||
well with an object of type `condition_variable_any`: `condition_variable_any`
|
||||
is more general, and will work with any kind of lock or mutex, whereas
|
||||
`condition_variable` requires that the lock passed to `wait` is an instance of
|
||||
`boost::unique_lock<boost::mutex>`. This enables `condition_variable` to make
|
||||
optimizations in some cases, based on the knowledge of the mutex type;
|
||||
`condition_variable_any` typically has a more complex implementation than
|
||||
`condition_variable`.
|
||||
|
||||
[section:condition_variable Class `condition_variable`]
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable
|
||||
{
|
||||
public:
|
||||
condition_variable();
|
||||
~condition_variable();
|
||||
|
||||
void notify_one() noexcept;
|
||||
void notify_all() noexcept;
|
||||
|
||||
void wait(boost::unique_lock<boost::mutex>& lock);
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);
|
||||
|
||||
template <class Clock, class Duration>
|
||||
typename cv_status::type
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& t);
|
||||
|
||||
template <class Clock, class Duration, class Predicate>
|
||||
bool
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& t,
|
||||
Predicate pred);
|
||||
|
||||
template <class Rep, class Period>
|
||||
typename cv_status::type
|
||||
wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& d);
|
||||
|
||||
template <class Rep, class Period, class Predicate>
|
||||
bool
|
||||
wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred);
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
|
||||
template<typename duration_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
|
||||
#endif
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[section:constructor `condition_variable()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an object of class `condition_variable`.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor `~condition_variable()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
|
||||
`notify_one` or `notify_all` (though the respective calls to `wait` or
|
||||
`timed_wait` need not have returned).]]
|
||||
|
||||
[[Effects:] [Destroys the object.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_one `void notify_one()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks one of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_all `void notify_all()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks all of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait `void wait(boost::unique_lock<boost::mutex>& lock)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_predicate `template<typename predicate_type> void wait(boost::unique_lock<boost::mutex>& lock, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
wait(lock);
|
||||
}
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait `bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
|
||||
would be equal to or later than the specified `abs_time`, or spuriously. When
|
||||
the thread is unblocked (for whatever reason), the lock is reacquired by
|
||||
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
||||
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_rel `template<typename duration_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
||||
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_predicate `template<typename predicate_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock, boost::system_time const& abs_time, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!timed_wait(lock,abs_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:wait_until `template <class Clock, class Duration> cv_status wait_until(boost::unique_lock<boost::mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `wait_for` or `wait_until`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, when the time as reported by `Clock::now()`
|
||||
would be equal to or later than the specified `abs_time`, or spuriously. When
|
||||
the thread is unblocked (for whatever reason), the lock is reacquired by
|
||||
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
||||
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`cv_status::no_timeout` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `cv_status::timeout` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for `template <class Rep, class Period> cv_status wait_for(boost::unique_lock<boost::mutex>& lock, const chrono::duration<Rep, Period>& rel_time)`]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`lock` is locked by the current thread, and either no other
|
||||
thread is currently waiting on `*this`, or the execution of the `mutex()` member
|
||||
function on the `lock` objects supplied in the calls to `wait` or `wait_until` or `wait_for`
|
||||
in all the threads currently waiting on `*this` would return the same value as
|
||||
`lock->mutex()` for this call to `wait`.]]
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
||||
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`cv_status::no_timeout ` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `cv_status::timeout ` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_until_predicate `template <class Clock, class Duration, class Predicate> bool wait_until(boost::unique_lock<boost::mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred)`]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!wait_until(lock,abs_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for_predicate `template <class Rep, class Period, class Predicate> bool wait_for(boost::unique_lock<boost::mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!wait_for(lock,rel_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:condition_variable_any Class `condition_variable_any`]
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class condition_variable_any
|
||||
{
|
||||
public:
|
||||
condition_variable_any();
|
||||
~condition_variable_any();
|
||||
|
||||
void notify_one();
|
||||
void notify_all();
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& lock);
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& lock,predicate_type predicate);
|
||||
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<Clock, Duration>& t);
|
||||
|
||||
template <class lock_type, class Clock, class Duration, class Predicate>
|
||||
bool wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<Clock, Duration>& t,
|
||||
Predicate pred);
|
||||
|
||||
|
||||
template <class lock_type, class Rep, class Period>
|
||||
cv_status wait_for(
|
||||
lock_type& lock,
|
||||
const chrono::duration<Rep, Period>& d);
|
||||
|
||||
template <class lock_type, class Rep, class Period, class Predicate>
|
||||
bool wait_for(
|
||||
lock_type& lock,
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred);
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& lock,duration_type const& rel_time);
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
[section:constructor `condition_variable_any()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an object of class `condition_variable_any`.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor `~condition_variable_any()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
|
||||
`notify_one` or `notify_all` (though the respective calls to `wait` or
|
||||
`timed_wait` need not have returned).]]
|
||||
|
||||
[[Effects:] [Destroys the object.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_one `void notify_one()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks one of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:notify_all `void notify_all()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
|
||||
to `wait` or `timed_wait`, unblocks all of those threads.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait `template<typename lock_type> void wait(lock_type& lock)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_predicate `template<typename lock_type,typename predicate_type> void wait(lock_type& lock, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
wait(lock);
|
||||
}
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait `template<typename lock_type> bool timed_wait(lock_type& lock,boost::system_time const& abs_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
|
||||
would be equal to or later than the specified `abs_time`, or spuriously. When
|
||||
the thread is unblocked (for whatever reason), the lock is reacquired by
|
||||
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
||||
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_rel `template<typename lock_type,typename duration_type> bool timed_wait(lock_type& lock,duration_type const& rel_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
||||
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`false` if the call is returning because the time period specified
|
||||
by `rel_time` has elapsed, `true` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_wait_predicate `template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& lock, boost::system_time const& abs_time, predicate_type pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!timed_wait(lock,abs_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_until `template <class lock_type, class Clock, class Duration> cv_status wait_until(lock_type& lock, const chrono::time_point<Clock, Duration>& abs_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, when the time as reported by `Clock::now()`
|
||||
would be equal to or later than the specified `abs_time`, or spuriously. When
|
||||
the thread is unblocked (for whatever reason), the lock is reacquired by
|
||||
invoking `lock.lock()` before the call to `wait` returns. The lock is also
|
||||
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`cv_status::timeout` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `cv_status::no_timeout` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for `template <class lock_type, class Rep, class Period> cv_status wait_for(lock_type& lock, const chrono::duration<Rep, Period>& rel_time)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
|
||||
thread will unblock when notified by a call to `this->notify_one()` or
|
||||
`this->notify_all()`, after the period of time indicated by the `rel_time`
|
||||
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
|
||||
reason), the lock is reacquired by invoking `lock.lock()` before the call to
|
||||
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
|
||||
function exits with an exception.]]
|
||||
|
||||
[[Returns:] [`cv_status::timeout` if the call is returning because the time specified by
|
||||
`abs_time` was reached, `cv_status::no_timeout` otherwise.]]
|
||||
|
||||
[[Postcondition:] [`lock` is locked by the current thread.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error
|
||||
occurs. __thread_interrupted__ if the wait was interrupted by a call to
|
||||
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
|
||||
|
||||
]
|
||||
|
||||
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_until_predicate `template <class lock_type, class Clock, class Duration, class Predicate> bool wait_until(lock_type& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!__cvany_wait_until(lock,abs_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for_predicate `template <class lock_type, class Rep, class Period, class Predicate> bool wait_until(lock_type& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [As-if ``
|
||||
while(!pred())
|
||||
{
|
||||
if(!__cvany_wait_for(lock,rel_time))
|
||||
{
|
||||
return pred();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
``]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:condition Typedef `condition`]
|
||||
|
||||
#include <boost/thread/condition.hpp>
|
||||
|
||||
typedef condition_variable_any condition;
|
||||
|
||||
The typedef `condition` is provided for backwards compatibility with previous boost releases.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
217
doc/configuration.qbk
Normal file
217
doc/configuration.qbk
Normal file
@@ -0,0 +1,217 @@
|
||||
[/
|
||||
(C) Copyright 20012 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:configuration Configuration]
|
||||
|
||||
[section:system Boost.System]
|
||||
|
||||
Boost.Thread uses by default Boost.System to define the exceptions. For backward compatibility and also for compilers that don't work well with Boost.System the user can define `BOOST_THREAD_DONT_USE_SYSTEM `.
|
||||
|
||||
`BOOST_THREAD_USES_SYSTEM` is defined when Boost.Thread uses Boost.Move.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:chrono Boost.Chrono]
|
||||
|
||||
Boost.Thread uses by default Boost.Chrono for the time related functions. For backward compatibility and also for compilers that don't work well with Boost.Chrono the user can define `BOOST_THREAD_DONT_USE_CHRONO`. If `BOOST_THREAD_DONT_USE_SYSTEM` is defined then `BOOST_THREAD_DONT_USE_CHRONO` is defined implicitly.
|
||||
|
||||
`BOOST_THREAD_USES_CHRONO` is defined when Boost.Thread uses Boost.Chrono.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move Boost.Move]
|
||||
|
||||
Boost.Thread uses by default an internal move semantic implementation. Since version 3.0.0 you can use the move emulation emulation provided by Boost.Move.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_USES_MOVE ` if you want to use Boost.Move interface.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_USE_MOVE ` if you want to use boost::unique_future.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared_gen Shared Locking Generic]
|
||||
|
||||
The shared mutex implementation on Windows platform provides currently less functionality than the generic one that is used for PTheads based platforms. In order to have access to these functions, the user needs to define `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` to use the generic implementation, that while could be less efficient, provides all the functions.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared_upwards Shared Locking Upwards Conversion]
|
||||
|
||||
Boost.Threads includes in version 2 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.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION ` 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]
|
||||
|
||||
[section:explicit_cnv Explicit Lock Conversion]
|
||||
|
||||
In [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] the lock conversions are explicit. As this explicit conversion breaks the lock interfaces, it is provided only if the `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION` is defined.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:future unique_future versus future]
|
||||
|
||||
C++11 uses `std::future`. Versions of Boost.Thread previous to version 3.0.0 uses `boost:unique_future`.
|
||||
Since version 3.0.0 `boost::future` replaces `boost::unique_future` when `BOOST_THREAD_PROVIDES_FUTURE` is defined. The documentation doesn't contains anymore however `boost::unique_future`.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_FUTURE` if you want to use boost::future.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE` if you want to use boost::unique_future.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lazy promise lazy initialization]
|
||||
|
||||
C++11 promise initialize the associated state at construction time. Versions of Boost.Thread previous to version 3.0.0 initialize it lazily at any point in time in which this associated state is needed.
|
||||
|
||||
Since version 3.0.0 this difference in behavior can be configured. When `BOOST_THREAD_PROVIDES_PROMISE_LAZY` is defined the backward compatible behavior is provided.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY ` if you want to use boost::future.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_PROVIDES_PROMISE_LAZY ` if you want to use boost::unique_future.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:alloc promise Allocator constructor]
|
||||
|
||||
C++11 std::promise provides constructors with allocators.
|
||||
|
||||
template <typename R>
|
||||
class promise
|
||||
{
|
||||
public:
|
||||
template <class Allocator>
|
||||
explicit promise(allocator_arg_t, Allocator a);
|
||||
// ...
|
||||
};
|
||||
template <class R, class Alloc> struct uses_allocator<promise<R>,Alloc>: true_type {};
|
||||
|
||||
where
|
||||
|
||||
struct allocator_arg_t { };
|
||||
constexpr allocator_arg_t allocator_arg = allocator_arg_t();
|
||||
|
||||
template <class T, class Alloc> struct uses_allocator;
|
||||
|
||||
Since version 3.0.0 Boost.Thread implements this constructor using the following interface
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef container::allocator_arg_t allocator_arg_t;
|
||||
constexpr allocator_arg_t allocator_arg = {};
|
||||
|
||||
namespace container
|
||||
{
|
||||
template <class R, class Alloc>
|
||||
struct uses_allocator<promise<R>,Alloc>: true_type {};
|
||||
}
|
||||
template <class T, class Alloc>
|
||||
struct uses_allocator : public container::uses_allocator<T, Alloc> {};
|
||||
}
|
||||
|
||||
which introduces a dependency on Boost.Container. This feature is provided only if `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS` is defined.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:terminate Call to terminate if joinable]
|
||||
|
||||
C++11 has a different semantic for the thread destructor and the move assignment. Instead of detaching the thread, calls to terminate() if the thread was joinable. When `BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE` and `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE` is defined Boost.Thread provides the C++ semantic.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features.
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:once_flag once_flag]
|
||||
|
||||
C++11 defines a default constructor for once_flag. When `BOOST_THREAD_PROVIDES_ONCE_CXX11 ` is defined Boost.Thread provides this C++ semantics. In this case, the previous aggregate syntax is not supported.
|
||||
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
|
||||
You should now just do
|
||||
|
||||
boost::once_flag once;
|
||||
|
||||
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_ONCE_CXX11` if you want these features.
|
||||
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11` if you don't want these features.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:deprecated Deprecated]
|
||||
|
||||
Version 3.0.0 deprecates some Boost.Thread features.
|
||||
|
||||
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define `BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define `BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:version Version]
|
||||
|
||||
`BOOST_THREAD_VERSION` defines the Boost.Thread version.
|
||||
The default version is 2. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
|
||||
* `BOOST_THREAD_PROVIDES_PROMISE_LAZY`
|
||||
* `BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0`
|
||||
|
||||
The user can request the version 3 by defining `BOOST_THREAD_VERSION` to 3. In this case the following breaking or extending macros are defined if the opposite is not requested:
|
||||
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION `
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_FUTURE`
|
||||
* Uniformity `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN`
|
||||
* Extension `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION`
|
||||
* Conformity `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS`
|
||||
* Breaking change BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Breaking change BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
* Breaking change `BOOST_THREAD_PROVIDES_ONCE_CXX11`
|
||||
|
||||
* Breaking change `BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY`
|
||||
* Breaking change `BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`
|
||||
|
||||
The default value for `BOOST_THREAD_VERSION` will be changed to 3 since Boost 1.53.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:limitations Limitations]
|
||||
|
||||
Some compilers don't work correctly with some of the added features.
|
||||
|
||||
[section:sun SunPro]
|
||||
|
||||
If __SUNPRO_CC < 0x5100 the library defines
|
||||
|
||||
* `BOOST_THREAD_DONT_USE_MOVE`
|
||||
* `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS`
|
||||
|
||||
|
||||
[endsect]
|
||||
[section:vacpp VACPP]
|
||||
|
||||
If __IBMCPP__ is defined the library defines
|
||||
|
||||
* `BOOST_THREAD_DONT_USE_CHRONO`
|
||||
|
||||
And Boost.Thread doesn't links with Boost.Chrono.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
365
doc/emulations.qbk
Normal file
365
doc/emulations.qbk
Normal file
@@ -0,0 +1,365 @@
|
||||
[/
|
||||
(C) Copyright 20012 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:emulations Emulations]
|
||||
[section:delete `=delete` emulation]
|
||||
|
||||
C++11 allows to delete some implicitly generated functions as constructors and assignment using '= delete' as in
|
||||
|
||||
public:
|
||||
thread(thread const&) = delete;
|
||||
|
||||
On compilers not supporting this feature, Boost.Thread relays on a partial simulation, it declares the function as private without definition.
|
||||
|
||||
private:
|
||||
thread(thread &);
|
||||
|
||||
The emulation is partial as the private function can be used for overload resolution for some compilers and prefer it to other overloads that need a conversion. See below the consequences on the move semantic emulation.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move Move semantics]
|
||||
|
||||
In order to implement Movable classes, move parameters and return types Boost.Thread uses the rvalue reference when the compiler support it.
|
||||
On compilers not supporting it Boost.Thread uses either the emulation provided by Boost.Move or the emulation provided by the previous versions of Boost.Thread depending whether `BOOST_THREAD_USES_MOVE` is defined or not. This macros is unset by default when `BOOST_THREAD_VERSION` is 2. Since `BOOST_THREAD_VERSION` 3, `BOOST_THREAD_USES_MOVE` is defined.
|
||||
|
||||
[section:deprecated Deprecated Version 2 interface]
|
||||
|
||||
Previous to version 1.50, Boost.Thread make use of its own move semantic emulation which had more limitations than the provided by Boost.Move. In addition, it is of interest of the whole Boost community that Boost.Thread uses Boost.Move so that boost::thread can be stored on Movable aware containers.
|
||||
|
||||
To preserve backward compatibility at least during some releases, Boost.Thread allows the user to use the deprecated move semantic emulation defining BOOST_THREAD_DONT_USE_MOVE.
|
||||
|
||||
Many aspects of move semantics can be emulated for compilers not supporting rvalue references and Boost.Thread legacy offers tools for that purpose.
|
||||
|
||||
[section:Helper Helpers class and function]
|
||||
|
||||
Next follows the interface of the legacy move semantic helper class and function.
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
struct thread_move_t
|
||||
{
|
||||
explicit thread_move_t(T& t_);
|
||||
T& operator*() const;
|
||||
T* operator->() const;
|
||||
private:
|
||||
void operator=(thread_move_t&);
|
||||
};
|
||||
}
|
||||
template<typename T>
|
||||
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t);
|
||||
}
|
||||
[endsect]
|
||||
|
||||
[section:movable Movable emulation]
|
||||
|
||||
We can write a MovableOny class as follows. You just need to follow these simple steps:
|
||||
|
||||
* Add a conversion to the `detail::thread_move_t<classname>`
|
||||
* Make the copy constructor private.
|
||||
* Write a constructor taking the parameter as `detail::thread_move_t<classname>`
|
||||
* Write an assignment taking the parameter as `detail::thread_move_t<classname>`
|
||||
|
||||
For example the thread class defines the following:
|
||||
|
||||
class thread
|
||||
{
|
||||
// ...
|
||||
private:
|
||||
thread(thread&);
|
||||
thread& operator=(thread&);
|
||||
public:
|
||||
detail::thread_move_t<thread> move()
|
||||
{
|
||||
detail::thread_move_t<thread> x(*this);
|
||||
return x;
|
||||
}
|
||||
operator detail::thread_move_t<thread>()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
thread(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread_info=x->thread_info;
|
||||
x->thread_info.reset();
|
||||
}
|
||||
thread& operator=(detail::thread_move_t<thread> x)
|
||||
{
|
||||
thread new_thread(x);
|
||||
swap(new_thread);
|
||||
return *this;
|
||||
}
|
||||
// ...
|
||||
|
||||
};
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:portable Portable interface]
|
||||
|
||||
In order to make the library code portable Boost.Thread uses some macros that will use either the ones provided by Boost.Move or the deprecated move semantics provided by previous versions of Boost.Thread.
|
||||
|
||||
See the Boost.Move documentation for a complete description on how to declare new Movable classes and its limitations.
|
||||
|
||||
* `BOOST_THREAD_RV_REF(TYPE)` is the equivalent of `BOOST_RV_REF(TYPE)`
|
||||
* `BOOST_THREAD_RV_REF_BEG` is the equivalent of `BOOST_RV_REF_BEG(TYPE)`
|
||||
* `BOOST_THREAD_RV_REF_END` is the equivalent of `BOOST_RV_REF_END(TYPE)`
|
||||
* `BOOST_THREAD_FWD_REF(TYPE)` is the equivalent of `BOOST_FWD_REF(TYPE)
|
||||
|
||||
In addition the following macros are needed to make the code portable:
|
||||
|
||||
* `BOOST_THREAD_RV(V)` macro to access the rvalue from a BOOST_THREAD_RV_REF(TYPE),
|
||||
* `BOOST_THREAD_MAKE_RV_REF(RVALUE)` makes a rvalue.
|
||||
* `BOOST_THREAD_DCL_MOVABLE(CLASS)` to avoid conflicts with Boost.Move
|
||||
* `BOOST_THREAD_DCL_MOVABLE_BEG(T1)` and `BOOST_THREAD_DCL_MOVABLE_END` are variant of `BOOST_THREAD_DCL_MOVABLE` when the parameter is a template instantiation.
|
||||
|
||||
Other macros are provided and must be included on the public section:
|
||||
|
||||
* `BOOST_THREAD_NO_COPYABLE` declares a class no-copyable either deleting the copy constructors and copy assignment or moving them to the private section.
|
||||
* `BOOST_THREAD_MOVABLE(CLASS)` declares all the implicit conversions to an rvalue-reference.
|
||||
* `BOOST_THREAD_MOVABLE_ONLY(CLASS)` is the equivalent of `BOOST_MOVABLE_BUT_NOT_COPYABLE(CLASS)`
|
||||
* `BOOST_THREAD_COPYABLE_AND_MOVABLE(CLASS)` is the equivalent of `BOOST_COPYABLE_AND_MOVABLE(CLASS)`
|
||||
|
||||
|
||||
[section:NO_COPYABLE `BOOST_THREAD_NO_COPYABLE(CLASS)`]
|
||||
|
||||
This macro marks a class as no copyable, disabling copy construction and assignment.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:MOVABLE `BOOST_THREAD_MOVABLE(CLASS)`]
|
||||
|
||||
This macro marks a class as movable, declaring all the implicit conversions to an rvalue-reference.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:MOVABLE_ONLY `BOOST_THREAD_MOVABLE_ONLY(CLASS)`]
|
||||
|
||||
This macro marks a type as movable but not copyable, disabling copy construction and assignment. The user will need to write a move constructor/assignment to fully write a movable but not copyable class.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:COPYABLE_AND_MOVABLE `BOOST_THREAD_COPYABLE_AND_MOVABLE(CLASS)`]
|
||||
|
||||
This macro marks a type as copyable and movable. The user will need to write a move constructor/assignment and a copy assignment to fully write a copyable and movable class.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:RV_REF `BOOST_THREAD_RV_REF(TYPE)`, `BOOST_THREAD_RV_REF_BEG` and `BOOST_THREAD_RV_REF_END`]
|
||||
|
||||
This macro is used to achieve portable syntax in move constructors and assignments for classes marked as `BOOST_THREAD_COPYABLE_AND_MOVABLE` or `BOOST_THREAD_MOVABLE_ONLY`.
|
||||
|
||||
`BOOST_THREAD_RV_REF_BEG` and `BOOST_THREAD_RV_REF_END` are used when the parameter end with a `>` to avoid the compiler error.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:RV `BOOST_THREAD_RV(V)`]
|
||||
|
||||
While Boost.Move emulation allows to access an rvalue reference `BOOST_THREAD_RV_REF(TYPE)` using the dot operator, the legacy defines the `operator->`. We need then a macro `BOOST_THREAD_RV` that mask this difference. E.g.
|
||||
|
||||
thread(BOOST_THREAD_RV_REF(thread) x)
|
||||
{
|
||||
thread_info=BOOST_THREAD_RV(x).thread_info;
|
||||
BOOST_THREAD_RV(x).thread_info.reset();
|
||||
}
|
||||
|
||||
The use of this macros has reduced considerably the size of the Boost.Thread move related code.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:MAKE_RV_REF `BOOST_THREAD_MAKE_RV_REF(RVALUE)`]
|
||||
|
||||
While Boost.Move is the best C++03 move emulation there are some limitations that impact the way the library can be used.
|
||||
For example, with the following declarations
|
||||
|
||||
class thread {
|
||||
// ...
|
||||
private:
|
||||
thread(thread &);
|
||||
public:
|
||||
thread(rv<thread>&);
|
||||
// ...
|
||||
};
|
||||
|
||||
This could not work on some compilers even if thread is convertible to `rv<thread>` because the compiler prefers the private copy constructor.
|
||||
|
||||
thread mkth()
|
||||
{
|
||||
return thread(f);
|
||||
}
|
||||
|
||||
On these compilers we need to use instead an explicit conversion. The library provides a move member function that allows to workaround the issue.
|
||||
|
||||
thread mkth()
|
||||
{
|
||||
return thread(f).move();
|
||||
}
|
||||
|
||||
Note that `::boost::move` can not be used in this case as thread is not implicitly convertible to `thread&`.
|
||||
|
||||
thread mkth()
|
||||
{
|
||||
return ::boost::move(thread(f));
|
||||
}
|
||||
|
||||
To make the code portable Boost.Thread the user needs to use a macro `BOOST_THREAD_MAKE_RV_REF` that can be used as in
|
||||
|
||||
thread mkth()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF(thread(f));
|
||||
}
|
||||
|
||||
Note that this limitation is shared also by the legacy Boost.Thread move emulation.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:DCL_MOVABLE `BOOST_THREAD_DCL_MOVABLE`, `BOOST_THREAD_DCL_MOVABLE_BEG(T1)` and `BOOST_THREAD_DCL_MOVABLE_END`]
|
||||
|
||||
As Boost.Move defines also the `boost::move` function we need to specialize the `has_move_emulation_enabled_aux` metafunction.
|
||||
|
||||
template <>
|
||||
struct has_move_emulation_enabled_aux<thread>
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
|
||||
so that the following Boost.Move overload is disabled
|
||||
|
||||
template <class T>
|
||||
inline typename BOOST_MOVE_BOOST_NS::disable_if<has_move_emulation_enabled_aux<T>, T&>::type move(T& x);
|
||||
|
||||
The macros `BOOST_THREAD_DCL_MOVABLE(CLASS)`, `BOOST_THREAD_DCL_MOVABLE_BEG(T1)` and `BOOST_THREAD_DCL_MOVABLE_END` are used for this purpose. E.g.
|
||||
|
||||
BOOST_THREAD_DCL_MOVABLE(thread)
|
||||
|
||||
and
|
||||
|
||||
BOOST_THREAD_DCL_MOVABLE_BEG(T) promise<T> BOOST_THREAD_DCL_MOVABLE_END
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:bool_explicit_conversion Bool explicit conversion]
|
||||
|
||||
Locks provide an explicit bool conversion operator when the compiler provides them.
|
||||
|
||||
explicit operator bool() const;
|
||||
|
||||
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)
|
||||
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.
|
||||
|
||||
[section:bool_conversion `operator `['unspecified-bool-type]`() const`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [If __owns_lock_ref__ would return `true`, a value that evaluates to
|
||||
`true` in boolean contexts, otherwise a value that evaluates to `false` in
|
||||
boolean contexts.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:operator_not `bool operator!() const`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [`!` __owns_lock_ref__.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:scoped_enums Scoped Enums]
|
||||
|
||||
Some of the enumerations defined in the standard library are scoped enums.
|
||||
|
||||
On compilers that don't support them, the library uses a class to wrap the underlying type. Instead of
|
||||
|
||||
enum class future_errc
|
||||
{
|
||||
broken_promise,
|
||||
future_already_retrieved,
|
||||
promise_already_satisfied,
|
||||
no_state
|
||||
};
|
||||
|
||||
the library declare these types as
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
|
||||
{
|
||||
broken_promise,
|
||||
future_already_retrieved,
|
||||
promise_already_satisfied,
|
||||
no_state
|
||||
}
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
|
||||
|
||||
These macros allows to use 'future_errc' in almost all the cases as an scoped enum.
|
||||
|
||||
There are however some limitations:
|
||||
|
||||
* The type is not a C++ enum, so 'is_enum<future_errc>' will be false_type.
|
||||
* The emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some macros.
|
||||
|
||||
Instead of
|
||||
|
||||
switch (ev)
|
||||
{
|
||||
case future_errc::broken_promise:
|
||||
// ...
|
||||
|
||||
use
|
||||
|
||||
switch (boost::native_value(ev))
|
||||
{
|
||||
case future_errc::broken_promise:
|
||||
|
||||
And instead of
|
||||
|
||||
#ifdef BOOST_NO_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type { };
|
||||
#endif
|
||||
|
||||
use
|
||||
|
||||
#ifdef BOOST_NO_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
1202
doc/future_ref.qbk
Normal file
1202
doc/future_ref.qbk
Normal file
File diff suppressed because it is too large
Load Diff
187
doc/futures.qbk
Executable file
187
doc/futures.qbk
Executable file
@@ -0,0 +1,187 @@
|
||||
[/
|
||||
(C) Copyright 2008-11 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:futures Futures]
|
||||
|
||||
[template future_state_link[link_text] [link thread.synchronization.futures.reference.future_state [link_text]]]
|
||||
[def __uninitialized__ [future_state_link `boost::future_state::uninitialized`]]
|
||||
[def __ready__ [future_state_link `boost::future_state::ready`]]
|
||||
[def __waiting__ [future_state_link `boost::future_state::waiting`]]
|
||||
|
||||
[def __future_uninitialized__ `boost::future_uninitialized`]
|
||||
[def __broken_promise__ `boost::broken_promise`]
|
||||
[def __future_already_retrieved__ `boost::future_already_retrieved`]
|
||||
[def __task_moved__ `boost::task_moved`]
|
||||
[def __task_already_started__ `boost::task_already_started`]
|
||||
[def __promise_already_satisfied__ `boost::promise_already_satisfied`]
|
||||
|
||||
[def __thread_interrupted__ `boost::thread_interrupted`]
|
||||
|
||||
|
||||
[template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]]
|
||||
[def __unique_future__ [unique_future_link `boost::unique_future`]]
|
||||
|
||||
[template unique_future_get_link[link_text] [link thread.synchronization.futures.reference.unique_future.get [link_text]]]
|
||||
[def __unique_future_get__ [unique_future_get_link `boost::unique_future<R>::get()`]]
|
||||
|
||||
[template unique_future_wait_link[link_text] [link thread.synchronization.futures.reference.unique_future.wait [link_text]]]
|
||||
[def __unique_future_wait__ [unique_future_wait_link `boost::unique_future<R>::wait()`]]
|
||||
|
||||
[template unique_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.unique_future.is_ready [link_text]]]
|
||||
[def __unique_future_is_ready__ [unique_future_is_ready_link `boost::unique_future<R>::is_ready()`]]
|
||||
|
||||
[template unique_future_has_value_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_value [link_text]]]
|
||||
[def __unique_future_has_value__ [unique_future_has_value_link `boost::unique_future<R>::has_value()`]]
|
||||
|
||||
[template unique_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_exception [link_text]]]
|
||||
[def __unique_future_has_exception__ [unique_future_has_exception_link `boost::unique_future<R>::has_exception()`]]
|
||||
|
||||
[template unique_future_get_state_link[link_text] [link thread.synchronization.futures.reference.unique_future.get_state [link_text]]]
|
||||
[def __unique_future_get_state__ [unique_future_get_state_link `boost::unique_future<R>::get_state()`]]
|
||||
|
||||
[template shared_future_link[link_text] [link thread.synchronization.futures.reference.shared_future [link_text]]]
|
||||
[def __shared_future__ [shared_future_link `boost::shared_future`]]
|
||||
|
||||
[template shared_future_get_link[link_text] [link thread.synchronization.futures.reference.shared_future.get [link_text]]]
|
||||
[def __shared_future_get__ [shared_future_get_link `boost::shared_future<R>::get()`]]
|
||||
|
||||
[template shared_future_wait_link[link_text] [link thread.synchronization.futures.reference.shared_future.wait [link_text]]]
|
||||
[def __shared_future_wait__ [shared_future_wait_link `boost::shared_future<R>::wait()`]]
|
||||
|
||||
[template shared_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.shared_future.is_ready [link_text]]]
|
||||
[def __shared_future_is_ready__ [shared_future_is_ready_link `boost::shared_future<R>::is_ready()`]]
|
||||
|
||||
[template shared_future_has_value_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_value [link_text]]]
|
||||
[def __shared_future_has_value__ [shared_future_has_value_link `boost::shared_future<R>::has_value()`]]
|
||||
|
||||
[template shared_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_exception [link_text]]]
|
||||
[def __shared_future_has_exception__ [shared_future_has_exception_link `boost::shared_future<R>::has_exception()`]]
|
||||
|
||||
[template shared_future_get_state_link[link_text] [link thread.synchronization.futures.reference.shared_future.get_state [link_text]]]
|
||||
[def __shared_future_get_state__ [shared_future_get_state_link `boost::shared_future<R>::get_state()`]]
|
||||
|
||||
[template promise_link[link_text] [link thread.synchronization.futures.reference.promise [link_text]]]
|
||||
[def __promise__ [promise_link `boost::promise`]]
|
||||
|
||||
[template packaged_task_link[link_text] [link thread.synchronization.futures.reference.packaged_task [link_text]]]
|
||||
[def __packaged_task__ [packaged_task_link `boost::packaged_task`]]
|
||||
|
||||
[template wait_for_any_link[link_text] [link thread.synchronization.futures.reference.wait_for_any [link_text]]]
|
||||
[def __wait_for_any__ [wait_for_any_link `boost::wait_for_any()`]]
|
||||
|
||||
[template wait_for_all_link[link_text] [link thread.synchronization.futures.reference.wait_for_all [link_text]]]
|
||||
[def __wait_for_all__ [wait_for_all_link `boost::wait_for_all()`]]
|
||||
|
||||
|
||||
[section:overview Overview]
|
||||
|
||||
The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or
|
||||
on a single thread in response to external stimuli, or on-demand.
|
||||
|
||||
This is done through the provision of four class templates: __unique_future__ and __shared_future__ which are used to retrieve the
|
||||
asynchronous results, and __promise__ and __packaged_task__ which are used to generate the asynchronous results.
|
||||
|
||||
An instance of __unique_future__ holds the one and only reference to a result. Ownership can be transferred between instances using
|
||||
the move constructor or move-assignment operator, but at most one instance holds a reference to a given asynchronous result. When
|
||||
the result is ready, it is returned from __unique_future_get__ by rvalue-reference to allow the result to be moved or copied as
|
||||
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 `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.
|
||||
|
||||
You can wait for futures either individually or with one of the __wait_for_any__ and __wait_for_all__ functions.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:creating Creating asynchronous values]
|
||||
|
||||
You can set the value in a future with either a __promise__ or a __packaged_task__. A __packaged_task__ is a callable object that
|
||||
wraps a function or callable object. When the packaged task is invoked, it invokes the contained function in turn, and populates a
|
||||
future with the return value. This is an answer to the perennial question: "how do I return a value from a thread?": package the
|
||||
function you wish to run as a __packaged_task__ and pass the packaged task to the thread constructor. The future retrieved from the
|
||||
packaged task can then be used to obtain the return value. If the function throws an exception, that is stored in the future in
|
||||
place of the return value.
|
||||
|
||||
int calculate_the_answer_to_life_the_universe_and_everything()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
|
||||
boost::unique_future<int> fi=pt.get_future();
|
||||
|
||||
boost::thread task(boost::move(pt)); // launch task on a thread
|
||||
|
||||
fi.wait(); // wait for it to finish
|
||||
|
||||
assert(fi.is_ready());
|
||||
assert(fi.has_value());
|
||||
assert(!fi.has_exception());
|
||||
assert(fi.get_state()==boost::future_state::ready);
|
||||
assert(fi.get()==42);
|
||||
|
||||
|
||||
A __promise__ is a bit more low level: it just provides explicit functions to store a value or an exception in the associated
|
||||
future. A promise can therefore be used where the value may come from more than one possible source, or where a single operation may
|
||||
produce multiple values.
|
||||
|
||||
boost::promise<int> pi;
|
||||
boost::unique_future<int> fi;
|
||||
fi=pi.get_future();
|
||||
|
||||
pi.set_value(42);
|
||||
|
||||
assert(fi.is_ready());
|
||||
assert(fi.has_value());
|
||||
assert(!fi.has_exception());
|
||||
assert(fi.get_state()==boost::future_state::ready);
|
||||
assert(fi.get()==42);
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lazy_futures Wait Callbacks and Lazy Futures]
|
||||
|
||||
Both __promise__ and __packaged_task__ support ['wait callbacks] that are invoked when a thread blocks in a call to `wait()` or
|
||||
`timed_wait()` on a future that is waiting for the result from the __promise__ or __packaged_task__, in the thread that is doing the
|
||||
waiting. These can be set using the `set_wait_callback()` member function on the __promise__ or __packaged_task__ in question.
|
||||
|
||||
This allows ['lazy futures] where the result is not actually computed until it is needed by some thread. In the example below, the
|
||||
call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task to set the value. If you remove the call to
|
||||
`f.get()`, the task is not ever run.
|
||||
|
||||
int calculate_the_answer_to_life_the_universe_and_everything()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
void invoke_lazy_task(boost::packaged_task<int>& task)
|
||||
{
|
||||
try
|
||||
{
|
||||
task();
|
||||
}
|
||||
catch(boost::task_already_started&)
|
||||
{}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything);
|
||||
task.set_wait_callback(invoke_lazy_task);
|
||||
boost::unique_future<int> f(task.get_future());
|
||||
|
||||
assert(f.get()==42);
|
||||
}
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[include future_ref.qbk]
|
||||
|
||||
[endsect]
|
||||
12
doc/index.html
Normal file
12
doc/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=../../../doc/html/thread.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to <a href="../../../doc/html/thread.html">../../../doc/html/thread.html</a>
|
||||
</body>
|
||||
</html>
|
||||
1950
doc/mutex_concepts.qbk
Normal file
1950
doc/mutex_concepts.qbk
Normal file
File diff suppressed because it is too large
Load Diff
241
doc/mutexes.qbk
Normal file
241
doc/mutexes.qbk
Normal file
@@ -0,0 +1,241 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams
|
||||
(C) Copyright 2011-12 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:mutex_types Mutex Types]
|
||||
|
||||
[section:mutex Class `mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
class mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
mutex();
|
||||
~mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
};
|
||||
|
||||
__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given
|
||||
instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_mutex Typedef `try_mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:timed_mutex Class `timed_mutex`]
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
class timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
timed_mutex();
|
||||
~timed_mutex();
|
||||
|
||||
void lock();
|
||||
void unlock();
|
||||
bool try_lock();
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t);
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_lock(system_time const & abs_time);
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
__timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the
|
||||
lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__,
|
||||
__timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:recursive_mutex Class `recursive_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
class recursive_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
recursive_mutex();
|
||||
~recursive_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
};
|
||||
|
||||
__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can
|
||||
own the lock on a given instance of __recursive_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and
|
||||
__unlock_ref__ shall be permitted. A thread that already has exclusive ownership of a given __recursive_mutex__ instance can call
|
||||
__lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for
|
||||
each level of ownership acquired by a single thread before ownership can be acquired by another thread.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:recursive_try_mutex Typedef `recursive_try_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:recursive_timed_mutex Class `recursive_timed_mutex`]
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
|
||||
class recursive_timed_mutex:
|
||||
boost::noncopyable
|
||||
{
|
||||
public:
|
||||
recursive_timed_mutex();
|
||||
~recursive_timed_mutex();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
void unlock();
|
||||
|
||||
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t);
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_lock;
|
||||
typedef unspecified-type scoped_try_lock;
|
||||
typedef scoped_lock scoped_timed_lock;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_lock(system_time const & abs_time);
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
__recursive_timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one
|
||||
thread can own the lock on a given instance of __recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__,
|
||||
__try_lock_ref__, __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. A thread that already has
|
||||
exclusive ownership of a given __recursive_timed_mutex__ instance can call __lock_ref__, __timed_lock_ref__,
|
||||
__timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be
|
||||
called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
|
||||
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[include shared_mutex_ref.qbk]
|
||||
|
||||
[endsect]
|
||||
84
doc/once.qbk
Normal file
84
doc/once.qbk
Normal file
@@ -0,0 +1,84 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:once One-time Initialization]
|
||||
|
||||
#include <boost/thread/once.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct once_flag;
|
||||
template<typename Callable>
|
||||
void call_once(once_flag& flag,Callable func);
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
void call_once(void (*func)(),once_flag& flag);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
|
||||
|
||||
[section:once_flag Typedef `once_flag`]
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
struct once_flag
|
||||
{
|
||||
constexprr once_flag() noexcept;
|
||||
once_flag(const once_flag&) = delete;
|
||||
once_flag& operator=(const once_flag&) = delete;
|
||||
};
|
||||
#else
|
||||
typedef platform-specific-type once_flag;
|
||||
#define BOOST_ONCE_INIT platform-specific-initializer
|
||||
#endif
|
||||
|
||||
Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT` if BOOST_THREAD_PROVIDES_ONCE_CXX11 is not defined
|
||||
|
||||
boost::once_flag f=BOOST_ONCE_INIT;
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:call_once Non-member function `call_once`]
|
||||
|
||||
template<typename Callable>
|
||||
void call_once(once_flag& flag,Callable func);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall
|
||||
be equivalent to calling the original. ]]
|
||||
|
||||
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
|
||||
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
|
||||
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
|
||||
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
|
||||
without invoking `func`. ]]
|
||||
|
||||
[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with
|
||||
all subsequent `call_once` invocations on the same `once_flag` object. ]]
|
||||
|
||||
[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]]
|
||||
|
||||
[[Note:] [The function passed to `call_once` must not also call
|
||||
`call_once` passing the same `once_flag` object. This may cause
|
||||
deadlock, or invoking the passed function a second time. The
|
||||
alternative is to allow the second call to return immediately, but
|
||||
that assumes the code knows it has been called recursively, and can
|
||||
proceed even though the call to `call_once` didn't actually call the
|
||||
function, in which case it could also avoid calling `call_once`
|
||||
recursively.]]
|
||||
|
||||
]
|
||||
|
||||
void call_once(void (*func)(),once_flag& flag);
|
||||
|
||||
This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of
|
||||
`call_once(flag,func)`.
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
51
doc/overview.qbk
Normal file
51
doc/overview.qbk
Normal file
@@ -0,0 +1,51 @@
|
||||
[/
|
||||
(C) Copyright 2007-12 Anthony Williams.
|
||||
(C) Copyright 20012 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:overview Overview]
|
||||
|
||||
__boost_thread__ enables the use of multiple threads of execution with shared data in portable C++ code. It provides classes and
|
||||
functions for managing the threads themselves, along with others for synchronizing data between the threads or providing separate
|
||||
copies of data specific to individual threads.
|
||||
|
||||
The __boost_thread__ library was originally written and designed by William E. Kempf (version 0). Anthony Williams version (version 1) was a major rewrite designed to
|
||||
closely follow the proposals presented to the C++ Standards Committee, in particular
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html N2497],
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html N2320],
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2184.html N2184],
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
|
||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
|
||||
|
||||
Vicente J. Botet Escriba started in version 2 the adaptation to comply with the accepted Thread C++11 library (Make use of Boost.Chrono and Boost.Move) and the [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] Howard Hinnant proposal except for the upward conversions.
|
||||
Some minor features have been added also as thread attributes, reverse_lock, shared_lock_guard.
|
||||
|
||||
In order to use the classes and functions described here, you can
|
||||
either include the specific headers specified by the descriptions of
|
||||
each class or function, or include the master thread library header:
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
which includes all the other headers in turn.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:build Using and building the library]
|
||||
|
||||
Boost.Thread is configured following the conventions used to build [@http://www.boost.org/doc/libs/1_48_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_for_libraries_with_separate_source_code libraries with separate source code]. Boost.Thread will import/export the code only if the user has specifically asked for it, by defining either BOOST_ALL_DYN_LINK if they want all boost libraries to be dynamically linked, or BOOST_THREAD_DYN_LINK if they want just this one to be dynamically liked.
|
||||
|
||||
The definition of these macros determines whether BOOST_THREAD_USE_DLL is defined. If BOOST_THREAD_USE_DLL is not defined, the library will define BOOST_THREAD_USE_DLL or BOOST_THREAD_USE_LIB depending on whether the platform. On non windows platforms BOOST_THREAD_USE_LIB is defined if is not defined. In windows platforms, BOOST_THREAD_USE_LIB is defined if BOOST_THREAD_USE_DLL and the compiler supports auto-tss cleanup with Boost.Threads (for the time been Msvc and Intel)
|
||||
|
||||
The source code compiled when building the library defines a macros BOOST_THREAD_SOURCE that is used to import or export it. The user must not define this macro in any case.
|
||||
|
||||
The following section describes all the macros used to configure Boost.Thread.
|
||||
|
||||
[include configuration.qbk]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
143
doc/shared_mutex_ref.qbk
Normal file
143
doc/shared_mutex_ref.qbk
Normal file
@@ -0,0 +1,143 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:shared_mutex Class `shared_mutex`]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
class shared_mutex
|
||||
{
|
||||
public:
|
||||
shared_mutex(shared_mutex const&) = delete;
|
||||
shared_mutex& operator=(shared_mutex const&) = delete;
|
||||
|
||||
shared_mutex();
|
||||
~shared_mutex();
|
||||
|
||||
void lock_shared();
|
||||
bool try_lock_shared();
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void unlock_shared();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void unlock();
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
// use upgrade_mutex instead.
|
||||
void lock_upgrade();
|
||||
void unlock_upgrade();
|
||||
|
||||
void unlock_upgrade_and_lock();
|
||||
void unlock_and_lock_upgrade();
|
||||
void unlock_and_lock_shared();
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
bool timed_lock_shared(system_time const& timeout);
|
||||
bool timed_lock(system_time const& timeout);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
The class `boost::shared_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
|
||||
__shared_lockable_concept__.
|
||||
|
||||
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`, `__try_lock_until()`, __timed_lock_ref__, __lock_shared_ref__,
|
||||
`__try_lock_shared_for()`, `__try_lock_shared_until()`, __try_lock_shared_ref__ and __timed_lock_shared_ref__ are permitted.
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:upgrade_mutex Class `upgrade_mutex`]
|
||||
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
class upgrade_mutex
|
||||
{
|
||||
public:
|
||||
upgrade_mutex(upgrade_mutex const&) = delete;
|
||||
upgrade_mutex& operator=(upgrade_mutex const&) = delete;
|
||||
|
||||
upgrade_mutex();
|
||||
~upgrade_mutex();
|
||||
|
||||
void lock_shared();
|
||||
bool try_lock_shared();
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void unlock_shared();
|
||||
|
||||
void lock();
|
||||
bool try_lock();
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void unlock();
|
||||
|
||||
void lock_upgrade();
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void unlock_upgrade();
|
||||
|
||||
// Shared <-> Exclusive
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock();
|
||||
template <class Rep, class Period>
|
||||
bool try_unlock_shared_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_unlock_shared_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_and_lock_shared();
|
||||
|
||||
// Shared <-> Upgrade
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock_upgrade();
|
||||
template <class Rep, class Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_upgrade_and_lock_shared();
|
||||
|
||||
// Upgrade <-> Exclusive
|
||||
|
||||
void unlock_upgrade_and_lock();
|
||||
#if defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
|| defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
|
||||
bool try_unlock_upgrade_and_lock();
|
||||
template <class Rep, class Period>
|
||||
bool try_unlock_upgrade_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
template <class Clock, class Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
#endif
|
||||
void unlock_and_lock_upgrade();
|
||||
};
|
||||
|
||||
The class `boost::upgrade_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
|
||||
__upgrade_lockable_concept__.
|
||||
|
||||
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`, `__try_lock_until()`, __timed_lock_ref__, __lock_shared_ref__,
|
||||
`__try_lock_shared_for()`, `__try_lock_shared_until()`, __try_lock_shared_ref__ and __timed_lock_shared_ref__ are permitted.
|
||||
|
||||
|
||||
[endsect]
|
||||
14
doc/sync_tutorial.qbk
Normal file
14
doc/sync_tutorial.qbk
Normal file
@@ -0,0 +1,14 @@
|
||||
[/
|
||||
(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).
|
||||
]
|
||||
|
||||
[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://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.
|
||||
|
||||
[endsect]
|
||||
242
doc/thread.qbk
Normal file
242
doc/thread.qbk
Normal file
@@ -0,0 +1,242 @@
|
||||
[/
|
||||
(C) Copyright 2008-11 Anthony Williams
|
||||
(C) Copyright 2011-12 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).
|
||||
]
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 3.0.1]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-12 Vicente J. Botet Escriba]
|
||||
[purpose C++ Library for launching threads and synchronizing data between them]
|
||||
[category text]
|
||||
[license
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
[@http://www.boost.org/LICENSE_1_0.txt])
|
||||
]
|
||||
]
|
||||
|
||||
[template lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.lockable [link_text]]]
|
||||
[def __lockable_concept__ [lockable_concept_link `Lockable` concept]]
|
||||
[def __lockable_concept_type__ [lockable_concept_link `Lockable`]]
|
||||
[def __BasicLockable [link thread.synchronization.mutex_concepts.basic_lockable `BasicLockable`]]
|
||||
[def __Lockable [link thread.synchronization.mutex_concepts.lockable `Lockable`]]
|
||||
[def __TimedLockable [link thread.synchronization.mutex_concepts.timed_lockable `TimedLockable `]]
|
||||
[def __SharedLockable [link thread.synchronization.mutex_concepts.shared_lockable `SharedLockable `]]
|
||||
[def __UpgradeLockable [link thread.synchronization.mutex_concepts.upgrade_lockable `UpgradeLockable `]]
|
||||
|
||||
[template timed_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable [link_text]]]
|
||||
[def __timed_lockable_concept__ [timed_lockable_concept_link `TimedLockable` concept]]
|
||||
[def __timed_lockable_concept_type__ [timed_lockable_concept_link `TimedLockable`]]
|
||||
|
||||
[template shared_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable [link_text]]]
|
||||
[def __shared_lockable_concept__ [shared_lockable_concept_link `SharedLockable` concept]]
|
||||
[def __shared_lockable_concept_type__ [shared_lockable_concept_link `SharedLockable`]]
|
||||
|
||||
[template upgrade_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable [link_text]]]
|
||||
[def __upgrade_lockable_concept__ [upgrade_lockable_concept_link `UpgradeLockable` concept]]
|
||||
[def __upgrade_lockable_concept_type__ [upgrade_lockable_concept_link `UpgradeLockable`]]
|
||||
|
||||
|
||||
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.basic_lockable.lock [link_text]]]
|
||||
[def __lock_ref__ [lock_ref_link `lock()`]]
|
||||
[def __lock [link thread.synchronization.mutex_concepts.basic_lockable.lock `lock`]]
|
||||
|
||||
[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]]
|
||||
[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]]
|
||||
|
||||
[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]]
|
||||
[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]]
|
||||
|
||||
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.basic_lockable.unlock [link_text]]]
|
||||
[def __unlock_ref__ [unlock_ref_link `unlock()`]]
|
||||
[def __unlock [link thread.synchronization.mutex_concepts.basic_lockable.unlock `unlock`]]
|
||||
|
||||
[template try_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.try_lock [link_text]]]
|
||||
[def __try_lock_ref__ [try_lock_ref_link `try_lock()`]]
|
||||
[def __try_lock [link thread.synchronization.mutex_concepts.lockable.try_lock `try_lock`]]
|
||||
|
||||
[template timed_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock [link_text]]]
|
||||
[def __timed_lock_ref__ [timed_lock_ref_link `timed_lock()`]]
|
||||
[def __timed_lock [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock `timed_lock`]]
|
||||
|
||||
[def __try_lock_for [link thread.synchronization.mutex_concepts.timed_lockable.try_lock_for `try_lock_for`]]
|
||||
[def __try_lock_until [link thread.synchronization.mutex_concepts.timed_lockable.try_lock_until `try_lock_until`]]
|
||||
|
||||
[template timed_lock_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration [link_text]]]
|
||||
[def __timed_lock_duration_ref__ [timed_lock_duration_ref_link `timed_lock()`]]
|
||||
[def __timed_lock_duration [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration `timed_lock`]]
|
||||
|
||||
[template lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared [link_text]]]
|
||||
[def __lock_shared_ref__ [lock_shared_ref_link `lock_shared()`]]
|
||||
[def __lock_shared [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared `lock_shared()`]]
|
||||
|
||||
[template unlock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared [link_text]]]
|
||||
[def __unlock_shared_ref__ [unlock_shared_ref_link `unlock_shared()`]]
|
||||
[def __unlock_shared [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared `unlock_shared()`]]
|
||||
|
||||
[template try_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared [link_text]]]
|
||||
[def __try_lock_shared_ref__ [try_lock_shared_ref_link `try_lock_shared()`]]
|
||||
[def __try_lock_shared [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared `try_lock_shared`]]
|
||||
|
||||
[template timed_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared [link_text]]]
|
||||
[def __timed_lock_shared_ref__ [timed_lock_shared_ref_link `timed_lock_shared()`]]
|
||||
[def __try_lock_shared_for [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_for `try_lock_shared_for`]]
|
||||
[def __try_lock_shared_for [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_until `try_lock_shared_until`]]
|
||||
|
||||
[template timed_lock_shared_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared_duration [link_text]]]
|
||||
[def __timed_lock_shared_duration_ref__ [timed_lock_shared_duration_ref_link `timed_lock_shared()`]]
|
||||
[def __try_lock_shared_for [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_for `try_lock_shared_for`]]
|
||||
[def __try_lock_shared_until [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_until `try_lock_shared_until`]]
|
||||
|
||||
[template lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade [link_text]]]
|
||||
[def __lock_upgrade_ref__ [lock_upgrade_ref_link `lock_upgrade()`]]
|
||||
[def __lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade `lock_upgrade`]]
|
||||
[def __try_lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.try_lock_upgrade `try_lock_upgrade`]]
|
||||
[def __try_lock_upgrade_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_lock_upgrade_for `try_lock_upgrade_for`]]
|
||||
[def __try_lock_upgrade_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_lock_upgrade_until `try_lock_upgrade_until`]]
|
||||
|
||||
[template unlock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade [link_text]]]
|
||||
[def __unlock_upgrade_ref__ [unlock_upgrade_ref_link `unlock_upgrade()`]]
|
||||
[def __unlock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade `unlock_upgrade`]]
|
||||
|
||||
[template unlock_upgrade_and_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock [link_text]]]
|
||||
[def __unlock_upgrade_and_lock_ref__ [unlock_upgrade_and_lock_ref_link `unlock_upgrade_and_lock()`]]
|
||||
[def __unlock_upgrade_and_lock [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock `unlock_upgrade_and_lock`]]
|
||||
|
||||
[template unlock_and_lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade [link_text]]]
|
||||
[def __unlock_and_lock_upgrade_ref__ [unlock_and_lock_upgrade_ref_link `unlock_and_lock_upgrade()`]]
|
||||
[def __unlock_and_lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade `unlock_and_lock_upgrade`]]
|
||||
|
||||
[template unlock_upgrade_and_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared [link_text]]]
|
||||
[def __unlock_upgrade_and_lock_shared_ref__ [unlock_upgrade_and_lock_shared_ref_link `unlock_upgrade_and_lock_shared()`]]
|
||||
[def __unlock_upgrade_and_lock_shared [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared `unlock_upgrade_and_lock_shared`]]
|
||||
|
||||
|
||||
[def __try_unlock_shared_and_lock [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock `try_unlock_shared_and_lock`]]
|
||||
[def __try_unlock_shared_and_lock_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_for `try_unlock_shared_and_lock_for`]]
|
||||
[def __try_unlock_shared_and_lock_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_until `try_unlock_shared_and_lock_until`]]
|
||||
|
||||
[def __unlock_and_lock_shared [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_shared `unlock_and_lock_shared`]]
|
||||
|
||||
[def __try_unlock_shared_and_lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_upgrade `try_unlock_shared_and_lock_upgrade`]]
|
||||
[def __try_unlock_shared_and_lock_upgrade_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_upgrade_for `try_unlock_shared_and_lock_upgrade_for`]]
|
||||
[def __try_unlock_shared_and_lock_upgrade_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_upgrade_until `try_unlock_shared_and_lock_upgrade_until`]]
|
||||
|
||||
[def __try_unlock_upgrade_and_lock [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_upgrade_and_lock `try_unlock_upgrade_and_lock`]]
|
||||
[def __try_unlock_upgrade_and_lock_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_upgrade_and_lock_for `try_unlock_upgrade_and_lock_for`]]
|
||||
[def __try_unlock_upgrade_and_lock_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_upgrade_and_lock_until `try_unlock_upgrade_and_lock_until`]]
|
||||
|
||||
|
||||
[template owns_lock_ref_link[link_text] [link thread.synchronization.locks.unique_lock.owns_lock [link_text]]]
|
||||
[def __owns_lock_ref__ [owns_lock_ref_link `owns_lock()`]]
|
||||
|
||||
[template owns_lock_shared_ref_link[link_text] [link thread.synchronization.locks.shared_lock.owns_lock [link_text]]]
|
||||
[def __owns_lock_shared_ref__ [owns_lock_shared_ref_link `owns_lock()`]]
|
||||
|
||||
[template mutex_func_ref_link[link_text] [link thread.synchronization.locks.unique_lock.mutex [link_text]]]
|
||||
[def __mutex_func_ref__ [mutex_func_ref_link `mutex()`]]
|
||||
|
||||
[def __boost_thread__ [*Boost.Thread]]
|
||||
[def __not_a_thread__ ['Not-a-Thread]]
|
||||
[def __interruption_points__ [link interruption_points ['interruption points]]]
|
||||
|
||||
[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]]
|
||||
[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]]
|
||||
[def __timed_mutex__ [link thread.synchronization.mutex_types.timed_mutex `boost::timed_mutex`]]
|
||||
[def __recursive_mutex__ [link thread.synchronization.mutex_types.recursive_mutex `boost::recursive_mutex`]]
|
||||
[def __recursive_try_mutex__ [link thread.synchronization.mutex_types.recursive_try_mutex `boost::recursive_try_mutex`]]
|
||||
[def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]]
|
||||
[def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]]
|
||||
|
||||
[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]]
|
||||
|
||||
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
|
||||
[def __unique_lock__ [unique_lock_link `boost::unique_lock`]]
|
||||
[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]]
|
||||
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
|
||||
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
|
||||
[def __reverse_lock [link thread.synchronization.other_locks.reverse_lock `reverse_lock`]]
|
||||
[def __shared_lock_guard [link thread.synchronization.other_locks.shared_lock_guard `shared_lock_guard`]]
|
||||
|
||||
|
||||
[def __thread__ [link thread.thread_management.thread `boost::thread`]]
|
||||
[def __thread [link thread.thread_management.thread `boost::thread`]]
|
||||
[def __thread_id__ [link thread.thread_management.thread.id `boost::thread::id`]]
|
||||
[template join_link[link_text] [link thread.thread_management.thread.join [link_text]]]
|
||||
[def __join__ [join_link `join()`]]
|
||||
|
||||
[def __try_join_for [link thread.thread_management.thread.try_join_for `try_join_for`]]
|
||||
[def __try_join_until [link thread.thread_management.thread.try_join_until `try_join_until`]]
|
||||
|
||||
|
||||
[template timed_join_link[link_text] [link thread.thread_management.thread.timed_join [link_text]]]
|
||||
[def __timed_join__ [timed_join_link `timed_join()`]]
|
||||
[def __detach__ [link thread.thread_management.thread.detach `detach()`]]
|
||||
[def __interrupt__ [link thread.thread_management.thread.interrupt `interrupt()`]]
|
||||
[def __sleep__ [link thread.thread_management.this_thread.sleep `boost::this_thread::sleep()`]]
|
||||
[def __sleep_for [link thread.thread_management.this_thread.sleep_for `sleep_for`]]
|
||||
[def __sleep_until [link thread.thread_management.this_thread.sleep_until `sleep_until`]]
|
||||
[def __yield [link thread.thread_management.this_thread.yield `yield`]]
|
||||
[def __get_id [link thread.thread_management.thread.get_id `get_id`]]
|
||||
|
||||
[def __interruption_enabled__ [link thread.thread_management.this_thread.interruption_enabled `boost::this_thread::interruption_enabled()`]]
|
||||
[def __interruption_requested__ [link thread.thread_management.this_thread.interruption_requested `boost::this_thread::interruption_requested()`]]
|
||||
[def __interruption_point__ [link thread.thread_management.this_thread.interruption_point `boost::this_thread::interruption_point()`]]
|
||||
[def __disable_interruption__ [link thread.thread_management.this_thread.disable_interruption `boost::this_thread::disable_interruption`]]
|
||||
[def __restore_interruption__ [link thread.thread_management.this_thread.restore_interruption `boost::this_thread::restore_interruption`]]
|
||||
|
||||
[def __thread_resource_error__ `boost::thread_resource_error`]
|
||||
[def __thread_interrupted__ `boost::thread_interrupted`]
|
||||
[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]]
|
||||
|
||||
[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]]
|
||||
[def __cond_wait__ [cond_wait_link `wait()`]]
|
||||
[template cond_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.timed_wait [link_text]]]
|
||||
[def __cond_timed_wait__ [cond_timed_wait_link `timed_wait()`]]
|
||||
|
||||
[def __condition_variable [link thread.synchronization.condvar_ref.condition_variable `condition_variable`]]
|
||||
[def __wait_for [link thread.synchronization.condvar_ref.condition_variable.wait_for `wait_for`]]
|
||||
[def __wait_until [link thread.synchronization.condvar_ref.condition_variable.wait_until `wait_until`]]
|
||||
|
||||
|
||||
[template cond_any_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.wait [link_text]]]
|
||||
[def __cond_any_wait__ [cond_any_wait_link `wait()`]]
|
||||
[template cond_any_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.timed_wait [link_text]]]
|
||||
[def __cond_any_timed_wait__ [cond_any_timed_wait_link `timed_wait()`]]
|
||||
|
||||
[def __condition_variable_any [link thread.synchronization.condvar_ref.condition_variable_any `condition_variable_any`]]
|
||||
[def __cvany_wait_for [link thread.synchronization.condvar_ref.condition_variable_any.wait_for `wait_for`]]
|
||||
[def __cvany_wait_until [link thread.synchronization.condvar_ref.condition_variable_any.wait_until `wait_until`]]
|
||||
|
||||
[def __blocked__ ['blocked]]
|
||||
|
||||
[include overview.qbk]
|
||||
[include changes.qbk]
|
||||
|
||||
[include thread_ref.qbk]
|
||||
|
||||
[section:synchronization Synchronization]
|
||||
[include sync_tutorial.qbk]
|
||||
[include mutex_concepts.qbk]
|
||||
[include mutexes.qbk]
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[include futures.qbk]
|
||||
[endsect]
|
||||
|
||||
[include tss.qbk]
|
||||
|
||||
[include time.qbk]
|
||||
|
||||
[include emulations.qbk]
|
||||
|
||||
[include acknowledgements.qbk]
|
||||
|
||||
[include compliance.qbk]
|
||||
1712
doc/thread_ref.qbk
Normal file
1712
doc/thread_ref.qbk
Normal file
File diff suppressed because it is too large
Load Diff
88
doc/time.qbk
Normal file
88
doc/time.qbk
Normal file
@@ -0,0 +1,88 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:time Time Requirements]
|
||||
|
||||
As of Boost 1.50.0, the __boost_thread__ library uses Boost.Chrono library for all operations that require a
|
||||
time out as defined in the standard c++11. These include (but are not limited to):
|
||||
|
||||
* __sleep_for
|
||||
* __sleep_until
|
||||
* __try_join_for
|
||||
* __try_join_until
|
||||
* __wait_for
|
||||
* __wait_until
|
||||
* __try_lock_for
|
||||
* __try_lock_until
|
||||
|
||||
[section:deprecated Deprecated]
|
||||
The time related functions introduced in Boost 1.35.0, using the [link date_time Boost.Date_Time] library are deprecated. These include (but are not limited to):
|
||||
|
||||
* __sleep__
|
||||
* __timed_join__
|
||||
* __cond_timed_wait__
|
||||
* __timed_lock_ref__
|
||||
|
||||
For the overloads that accept an absolute time parameter, an object of type [link thread.time.deprecated.system_time `boost::system_time`] is
|
||||
required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link
|
||||
thread.time.deprecated.get_system_time `boost::get_system_time()`]. e.g.
|
||||
|
||||
boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500);
|
||||
|
||||
extern bool done;
|
||||
extern boost::mutex m;
|
||||
extern boost::condition_variable cond;
|
||||
|
||||
boost::unique_lock<boost::mutex> lk(m);
|
||||
while(!done)
|
||||
{
|
||||
if(!cond.timed_wait(lk,timeout))
|
||||
{
|
||||
throw "timed out";
|
||||
}
|
||||
}
|
||||
|
||||
For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link
|
||||
date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g.
|
||||
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(25));
|
||||
|
||||
boost::mutex m;
|
||||
if(m.timed_lock(boost::posix_time::nanoseconds(100)))
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
[section:system_time Typedef `system_time`]
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get_system_time Non-member function `get_system_time()`]
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
|
||||
system_time get_system_time();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The current time.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
189
doc/tss.qbk
Normal file
189
doc/tss.qbk
Normal file
@@ -0,0 +1,189 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section Thread Local Storage]
|
||||
|
||||
[heading Synopsis]
|
||||
|
||||
Thread local storage allows multi-threaded applications to have a separate instance of a given data item for each thread. Where a
|
||||
single-threaded application would use static or global data, this could lead to contention, deadlock or data corruption in a
|
||||
multi-threaded application. One example is the C `errno` variable, used for storing the error code related to functions from the
|
||||
Standard C library. It is common practice (and required by POSIX) for compilers that support multi-threaded applications to provide
|
||||
a separate instance of `errno` for each thread, in order to avoid different threads competing to read or update the value.
|
||||
|
||||
Though compilers often provide this facility in the form of extensions to the declaration syntax (such as `__declspec(thread)` or
|
||||
`__thread` annotations on `static` or namespace-scope variable declarations), such support is non-portable, and is often limited in
|
||||
some way, such as only supporting POD types.
|
||||
|
||||
[heading Portable thread-local storage with `boost::thread_specific_ptr`]
|
||||
|
||||
`boost::thread_specific_ptr` provides a portable mechanism for thread-local storage that works on all compilers supported by
|
||||
__boost_thread__. Each instance of `boost::thread_specific_ptr` represents a pointer to an object (such as `errno`) where each
|
||||
thread must have a distinct value. The value for the current thread can be obtained using the `get()` member function, or by using
|
||||
the `*` and `->` pointer deference operators. Initially the pointer has a value of `NULL` in each thread, but the value for the
|
||||
current thread can be set using the `reset()` member function.
|
||||
|
||||
If the value of the pointer for the current thread is changed using `reset()`, then the previous value is destroyed by calling the
|
||||
cleanup routine. Alternatively, the stored value can be reset to `NULL` and the prior value returned by calling the `release()`
|
||||
member function, allowing the application to take back responsibility for destroying the object.
|
||||
|
||||
[heading Cleanup at thread exit]
|
||||
|
||||
When a thread exits, the objects associated with each `boost::thread_specific_ptr` instance are destroyed. By default, the object
|
||||
pointed to by a pointer `p` is destroyed by invoking `delete p`, but this can be overridden for a specific instance of
|
||||
`boost::thread_specific_ptr` by providing a cleanup routine to the constructor. In this case, the object is destroyed by invoking
|
||||
`func(p)` where `func` is the cleanup routine supplied to the constructor. The cleanup functions are called in an unspecified
|
||||
order. If a cleanup routine sets the value of associated with an instance of `boost::thread_specific_ptr` that has already been
|
||||
cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of
|
||||
`boost::thread_specific_ptr` with values.
|
||||
|
||||
Note: on some platforms, cleanup of thread-specific data is not
|
||||
performed for threads created with the platform's native API. On those
|
||||
platforms such cleanup is only done for threads that are started with
|
||||
`boost::thread` unless `boost::on_thread_exit()` is called manually
|
||||
from that thread.
|
||||
|
||||
[section:thread_specific_ptr Class `thread_specific_ptr`]
|
||||
|
||||
#include <boost/thread/tss.hpp>
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
public:
|
||||
thread_specific_ptr();
|
||||
explicit thread_specific_ptr(void (*cleanup_function)(T*));
|
||||
~thread_specific_ptr();
|
||||
|
||||
T* get() const;
|
||||
T* operator->() const;
|
||||
T& operator*() const;
|
||||
|
||||
T* release();
|
||||
void reset(T* new_value=0);
|
||||
};
|
||||
|
||||
[section:default_constructor `thread_specific_ptr();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`delete this->get()` is well-formed.]]
|
||||
|
||||
[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
|
||||
default `delete`-based cleanup function will be used to destroy any thread-local objects when `reset()` is called, or the thread
|
||||
exits.]]
|
||||
|
||||
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:constructor_with_custom_cleanup `explicit thread_specific_ptr(void (*cleanup_function)(T*));`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`cleanup_function(this->get())` does not throw any exceptions.]]
|
||||
|
||||
[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
|
||||
supplied `cleanup_function` will be used to destroy any thread-local objects when `reset()` is called, or the thread exits.]]
|
||||
|
||||
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:destructor `~thread_specific_ptr();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been
|
||||
destroyed do not call any member functions on that instance.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:get `T* get() const;`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The pointer associated with the current thread.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[note The initial value associated with an instance of `boost::thread_specific_ptr` is `NULL` for each thread.]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:operator_arrow `T* operator->() const;`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [`this->get()`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:operator_star `T& operator*() const;`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`this->get` is not `NULL`.]]
|
||||
|
||||
[[Returns:] [`*(this->get())`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:reset `void reset(T* new_value=0);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If `this->get()!=new_value` and `this->get()` is non-`NULL`, invoke `delete this->get()` or
|
||||
`cleanup_function(this->get())` as appropriate. Store `new_value` as the pointer associated with the current thread.]]
|
||||
|
||||
[[Postcondition:] [`this->get()==new_value`]]
|
||||
|
||||
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:release `T* release();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Return `this->get()` and store `NULL` as the pointer associated with the current thread without invoking the cleanup
|
||||
function.]]
|
||||
|
||||
[[Postcondition:] [`this->get()==0`]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
23
example/Jamfile.v2
Normal file
23
example/Jamfile.v2
Normal file
@@ -0,0 +1,23 @@
|
||||
# Copyright (C) 2001-2003
|
||||
# William E. Kempf
|
||||
#
|
||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
project boost/thread/example
|
||||
: requirements <library>../build//boost_thread <threading>multi
|
||||
;
|
||||
|
||||
|
||||
exe monitor : monitor.cpp ;
|
||||
exe starvephil : starvephil.cpp ;
|
||||
exe tennis : tennis.cpp ;
|
||||
exe condition : condition.cpp ;
|
||||
exe mutex : mutex.cpp ;
|
||||
exe once : once.cpp ;
|
||||
exe recursive_mutex : recursive_mutex.cpp ;
|
||||
exe thread : thread.cpp ;
|
||||
exe thread_group : thread_group.cpp ;
|
||||
exe tss : tss.cpp ;
|
||||
exe xtime : xtime.cpp ;
|
||||
|
||||
89
example/condition.cpp
Normal file
89
example/condition.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
class bounded_buffer : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
typedef boost::mutex::scoped_lock lock;
|
||||
|
||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
|
||||
void send (int m) {
|
||||
lock lk(monitor);
|
||||
while (buffered == circular_buf.size())
|
||||
buffer_not_full.wait(lk);
|
||||
circular_buf[end] = m;
|
||||
end = (end+1) % circular_buf.size();
|
||||
++buffered;
|
||||
buffer_not_empty.notify_one();
|
||||
}
|
||||
int receive() {
|
||||
lock lk(monitor);
|
||||
while (buffered == 0)
|
||||
buffer_not_empty.wait(lk);
|
||||
int i = circular_buf[begin];
|
||||
begin = (begin+1) % circular_buf.size();
|
||||
--buffered;
|
||||
buffer_not_full.notify_one();
|
||||
return i;
|
||||
}
|
||||
|
||||
private:
|
||||
int begin, end, buffered;
|
||||
std::vector<int> circular_buf;
|
||||
boost::condition buffer_not_full, buffer_not_empty;
|
||||
boost::mutex monitor;
|
||||
};
|
||||
|
||||
bounded_buffer buf(2);
|
||||
|
||||
boost::mutex io_mutex;
|
||||
|
||||
void sender() {
|
||||
int n = 0;
|
||||
while (n < 1000000) {
|
||||
buf.send(n);
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "sent: " << n << std::endl;
|
||||
}
|
||||
++n;
|
||||
}
|
||||
buf.send(-1);
|
||||
}
|
||||
|
||||
void receiver() {
|
||||
int n;
|
||||
do {
|
||||
n = buf.receive();
|
||||
if(!(n%10000))
|
||||
{
|
||||
boost::mutex::scoped_lock io_lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
} while (n != -1); // -1 indicates end of buffer
|
||||
buf.send(-1);
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
boost::thread thrd1(&sender);
|
||||
boost::thread thrd2(&receiver);
|
||||
boost::thread thrd3(&receiver);
|
||||
boost::thread thrd4(&receiver);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
thrd3.join();
|
||||
thrd4.join();
|
||||
return 0;
|
||||
}
|
||||
113
example/monitor.cpp
Normal file
113
example/monitor.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace {
|
||||
const int ITERS = 100;
|
||||
boost::mutex io_mutex;
|
||||
} // namespace
|
||||
|
||||
template <typename M>
|
||||
class buffer_t
|
||||
{
|
||||
public:
|
||||
typedef typename M::scoped_lock scoped_lock;
|
||||
|
||||
buffer_t(int n)
|
||||
: p(0), c(0), full(0), buf(n)
|
||||
{
|
||||
}
|
||||
|
||||
void send(int m)
|
||||
{
|
||||
scoped_lock lk(mutex);
|
||||
while (full == buf.size())
|
||||
cond.wait(lk);
|
||||
buf[p] = m;
|
||||
p = (p+1) % buf.size();
|
||||
++full;
|
||||
cond.notify_one();
|
||||
}
|
||||
int receive()
|
||||
{
|
||||
scoped_lock lk(mutex);
|
||||
while (full == 0)
|
||||
cond.wait(lk);
|
||||
int i = buf[c];
|
||||
c = (c+1) % buf.size();
|
||||
--full;
|
||||
cond.notify_one();
|
||||
return i;
|
||||
}
|
||||
|
||||
static buffer_t& get_buffer()
|
||||
{
|
||||
static buffer_t buf(2);
|
||||
return buf;
|
||||
}
|
||||
|
||||
static void do_sender_thread()
|
||||
{
|
||||
for (int n = 0; n < ITERS; ++n)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(io_mutex);
|
||||
std::cout << "sending: " << n << std::endl;
|
||||
}
|
||||
get_buffer().send(n);
|
||||
}
|
||||
}
|
||||
|
||||
static void do_receiver_thread()
|
||||
{
|
||||
for (int x=0; x < (ITERS/2); ++x)
|
||||
{
|
||||
int n = get_buffer().receive();
|
||||
{
|
||||
boost::mutex::scoped_lock lock(io_mutex);
|
||||
std::cout << "received: " << n << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
M mutex;
|
||||
boost::condition cond;
|
||||
unsigned int p, c, full;
|
||||
std::vector<int> buf;
|
||||
};
|
||||
|
||||
template <typename M>
|
||||
void do_test(M* dummy=0)
|
||||
{
|
||||
(void)dummy;
|
||||
typedef buffer_t<M> buffer_type;
|
||||
buffer_type::get_buffer();
|
||||
boost::thread thrd1(&buffer_type::do_receiver_thread);
|
||||
boost::thread thrd2(&buffer_type::do_receiver_thread);
|
||||
boost::thread thrd3(&buffer_type::do_sender_thread);
|
||||
thrd1.join();
|
||||
thrd2.join();
|
||||
thrd3.join();
|
||||
}
|
||||
|
||||
void test_buffer()
|
||||
{
|
||||
do_test<boost::mutex>();
|
||||
do_test<boost::recursive_mutex>();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_buffer();
|
||||
return 0;
|
||||
}
|
||||
47
example/mutex.cpp
Normal file
47
example/mutex.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
|
||||
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
counter() : count(0) { }
|
||||
|
||||
int increment() {
|
||||
boost::mutex::scoped_lock scoped_lock(mutex);
|
||||
return ++count;
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex mutex;
|
||||
int count;
|
||||
};
|
||||
|
||||
counter c;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
int i = c.increment();
|
||||
boost::mutex::scoped_lock scoped_lock(io_mutex);
|
||||
std::cout << "count == " << i << std::endl;
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
const int num_threads = 4;
|
||||
boost::thread_group thrds;
|
||||
for (int i=0; i < num_threads; ++i)
|
||||
thrds.create_thread(&change_count);
|
||||
|
||||
thrds.join_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
38
example/once.cpp
Normal file
38
example/once.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <cassert>
|
||||
|
||||
int value=0;
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
boost::once_flag once;
|
||||
#else
|
||||
boost::once_flag once = BOOST_ONCE_INIT;
|
||||
boost::once_flag once2 = once;
|
||||
#endif
|
||||
|
||||
void init()
|
||||
{
|
||||
++value;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
boost::call_once(&init, once);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
assert(value == 1);
|
||||
}
|
||||
49
example/recursive_mutex.cpp
Normal file
49
example/recursive_mutex.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
class counter
|
||||
{
|
||||
public:
|
||||
counter() : count(0) { }
|
||||
|
||||
int add(int val) {
|
||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||
count += val;
|
||||
return count;
|
||||
}
|
||||
int increment() {
|
||||
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
|
||||
return add(1);
|
||||
}
|
||||
|
||||
private:
|
||||
boost::recursive_mutex mutex;
|
||||
int count;
|
||||
};
|
||||
|
||||
counter c;
|
||||
|
||||
void change_count()
|
||||
{
|
||||
std::cout << "count == " << c.increment() << std::endl;
|
||||
}
|
||||
|
||||
int main(int, char*[])
|
||||
{
|
||||
const int num_threads=4;
|
||||
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i < num_threads; ++i)
|
||||
threads.create_thread(&change_count);
|
||||
|
||||
threads.join_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
143
example/shared_monitor.cpp
Normal file
143
example/shared_monitor.cpp
Normal file
@@ -0,0 +1,143 @@
|
||||
// Copyright (C) 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 <iostream>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#if defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
#endif
|
||||
#include <cassert>
|
||||
#include <vector>
|
||||
|
||||
#define EXCLUSIVE 1
|
||||
#define SHARED 2
|
||||
|
||||
#define MODE SHARED
|
||||
|
||||
class A
|
||||
{
|
||||
#if MODE == EXCLUSIVE
|
||||
typedef boost::mutex mutex_type;
|
||||
#elif MODE == SHARED
|
||||
typedef boost::shared_mutex mutex_type;
|
||||
#else
|
||||
#error MODE not set
|
||||
#endif
|
||||
typedef std::vector<double> C;
|
||||
mutable mutex_type mut_;
|
||||
C data_;
|
||||
public:
|
||||
A() : data_(10000000) {}
|
||||
A(const A& a);
|
||||
A& operator=(const A& a);
|
||||
|
||||
void compute(const A& x, const A& y);
|
||||
};
|
||||
|
||||
A::A(const A& a)
|
||||
{
|
||||
#if MODE == EXCLUSIVE
|
||||
boost::unique_lock<mutex_type> lk(a.mut_);
|
||||
#elif MODE == SHARED
|
||||
boost::shared_lock<mutex_type> lk(a.mut_);
|
||||
#else
|
||||
#error MODE not set
|
||||
#endif
|
||||
data_ = a.data_;
|
||||
}
|
||||
|
||||
A&
|
||||
A::operator=(const A& a)
|
||||
{
|
||||
if (this != &a)
|
||||
{
|
||||
boost::unique_lock<mutex_type> lk1(mut_, boost::defer_lock);
|
||||
#if MODE == EXCLUSIVE
|
||||
boost::unique_lock<mutex_type> lk2(a.mut_, boost::defer_lock);
|
||||
#elif MODE == SHARED
|
||||
boost::shared_lock<mutex_type> lk2(a.mut_, boost::defer_lock);
|
||||
#else
|
||||
#error MODE not set
|
||||
#endif
|
||||
boost::lock(lk1, lk2);
|
||||
data_ = a.data_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
A::compute(const A& x, const A& y)
|
||||
{
|
||||
boost::unique_lock<mutex_type> lk1(mut_, boost::defer_lock);
|
||||
#if MODE == EXCLUSIVE
|
||||
boost::unique_lock<mutex_type> lk2(x.mut_, boost::defer_lock);
|
||||
boost::unique_lock<mutex_type> lk3(y.mut_, boost::defer_lock);
|
||||
#elif MODE == SHARED
|
||||
boost::shared_lock<mutex_type> lk2(x.mut_, boost::defer_lock);
|
||||
boost::shared_lock<mutex_type> lk3(y.mut_, boost::defer_lock);
|
||||
#else
|
||||
#error MODE not set
|
||||
#endif
|
||||
boost::lock(lk1, lk2, lk3);
|
||||
assert(data_.size() == x.data_.size());
|
||||
assert(data_.size() == y.data_.size());
|
||||
for (unsigned i = 0; i < data_.size(); ++i)
|
||||
data_[i] = (x.data_[i] + y.data_[i]) / 2;
|
||||
}
|
||||
|
||||
A a1;
|
||||
A a2;
|
||||
|
||||
void test_s()
|
||||
{
|
||||
A la3 = a1;
|
||||
for (int i = 0; i < 150; ++i)
|
||||
{
|
||||
la3.compute(a1, a2);
|
||||
}
|
||||
}
|
||||
|
||||
void test_w()
|
||||
{
|
||||
A la3 = a1;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
{
|
||||
la3.compute(a1, a2);
|
||||
a1 = la3;
|
||||
a2 = la3;
|
||||
#if defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
typedef boost::chrono::duration<double> sec;
|
||||
Clock::time_point t0 = Clock::now();
|
||||
#endif
|
||||
std::vector<boost::thread*> v;
|
||||
boost::thread thw(test_w);
|
||||
v.push_back(&thw);
|
||||
boost::thread thr0(test_w);
|
||||
v.push_back(&thr0);
|
||||
boost::thread thr1(test_w);
|
||||
v.push_back(&thr1);
|
||||
boost::thread thr2(test_w);
|
||||
v.push_back(&thr2);
|
||||
boost::thread thr3(test_w);
|
||||
v.push_back(&thr3);
|
||||
for (std::size_t i = 0; i < v.size(); ++i)
|
||||
v[i]->join();
|
||||
#if defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
Clock::time_point t1 = Clock::now();
|
||||
std::cout << sec(t1-t0) << '\n';
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
745
example/shared_mutex.cpp
Normal file
745
example/shared_mutex.cpp
Normal file
@@ -0,0 +1,745 @@
|
||||
// Copyright (C) 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)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <vector>
|
||||
|
||||
#if defined BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
|
||||
enum {reading, writing};
|
||||
int state = reading;
|
||||
|
||||
#if 1
|
||||
|
||||
boost::mutex&
|
||||
cout_mut()
|
||||
{
|
||||
static boost::mutex m;
|
||||
return m;
|
||||
}
|
||||
|
||||
void
|
||||
print(const char* tag, unsigned count, char ch)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> _(cout_mut());
|
||||
std::cout << tag << count << ch;
|
||||
}
|
||||
|
||||
#elif 0
|
||||
|
||||
boost::recursive_mutex&
|
||||
cout_mut()
|
||||
{
|
||||
static boost::recursive_mutex m;
|
||||
return m;
|
||||
}
|
||||
|
||||
void print() {}
|
||||
|
||||
template <class A0, class ...Args>
|
||||
void
|
||||
print(const A0& a0, const Args& ...args)
|
||||
{
|
||||
boost::lock_guard<boost::recursive_mutex> _(cout_mut());
|
||||
std::cout << a0;
|
||||
print(args...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class A0, class A1, class A2>
|
||||
void
|
||||
print(const A0&, const A1& a1, const A2&)
|
||||
{
|
||||
assert(a1 > 10000);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
namespace S
|
||||
{
|
||||
|
||||
boost::shared_mutex mut;
|
||||
|
||||
void reader()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock_shared();
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_shared();
|
||||
}
|
||||
print("reader = ", count, '\n');
|
||||
}
|
||||
|
||||
void writer()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock();
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
++count;
|
||||
mut.unlock();
|
||||
}
|
||||
print("writer = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_reader()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_shared())
|
||||
{
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_shared();
|
||||
}
|
||||
}
|
||||
print("try_reader = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_writer()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock())
|
||||
{
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
++count;
|
||||
mut.unlock();
|
||||
}
|
||||
}
|
||||
print("try_writer = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_reader()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_shared();
|
||||
}
|
||||
}
|
||||
print("try_for_reader = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_writer()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
++count;
|
||||
mut.unlock();
|
||||
}
|
||||
}
|
||||
print("try_for_writer = ", count, '\n');
|
||||
}
|
||||
|
||||
void
|
||||
test_shared_mutex()
|
||||
{
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(reader);
|
||||
boost::thread t2(writer);
|
||||
boost::thread t3(reader);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(try_reader);
|
||||
boost::thread t2(try_writer);
|
||||
boost::thread t3(try_reader);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(try_for_reader);
|
||||
boost::thread t2(try_for_writer);
|
||||
boost::thread t3(try_for_reader);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace U
|
||||
{
|
||||
|
||||
boost::upgrade_mutex mut;
|
||||
|
||||
void reader()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock_shared();
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_shared();
|
||||
}
|
||||
print("reader = ", count, '\n');
|
||||
}
|
||||
|
||||
void writer()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock();
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
++count;
|
||||
mut.unlock();
|
||||
}
|
||||
print("writer = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_reader()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_shared())
|
||||
{
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_shared();
|
||||
}
|
||||
}
|
||||
print("try_reader = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_writer()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock())
|
||||
{
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
++count;
|
||||
mut.unlock();
|
||||
}
|
||||
}
|
||||
print("try_writer = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_reader()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_shared();
|
||||
}
|
||||
}
|
||||
print("try_for_reader = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_writer()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
++count;
|
||||
mut.unlock();
|
||||
}
|
||||
}
|
||||
print("try_for_writer = ", count, '\n');
|
||||
}
|
||||
|
||||
void upgradable()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock_upgrade();
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_upgrade();
|
||||
}
|
||||
print("upgradable = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_upgradable()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_upgrade())
|
||||
{
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_upgrade();
|
||||
}
|
||||
}
|
||||
print("try_upgradable = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_upgradable()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
++count;
|
||||
mut.unlock_upgrade();
|
||||
}
|
||||
}
|
||||
print("try_for_upgradable = ", count, '\n');
|
||||
}
|
||||
|
||||
void clockwise()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock_shared();
|
||||
assert(state == reading);
|
||||
if (mut.try_unlock_shared_and_lock())
|
||||
{
|
||||
state = writing;
|
||||
}
|
||||
else if (mut.try_unlock_shared_and_lock_upgrade())
|
||||
{
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock();
|
||||
state = writing;
|
||||
}
|
||||
else
|
||||
{
|
||||
mut.unlock_shared();
|
||||
continue;
|
||||
}
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
mut.unlock_and_lock_upgrade();
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock_shared();
|
||||
assert(state == reading);
|
||||
mut.unlock_shared();
|
||||
++count;
|
||||
}
|
||||
print("clockwise = ", count, '\n');
|
||||
}
|
||||
|
||||
void counter_clockwise()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
mut.lock_upgrade();
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock();
|
||||
assert(state == reading);
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
mut.unlock_and_lock_shared();
|
||||
assert(state == reading);
|
||||
mut.unlock_shared();
|
||||
++count;
|
||||
}
|
||||
print("counter_clockwise = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_clockwise()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_shared())
|
||||
{
|
||||
assert(state == reading);
|
||||
if (mut.try_unlock_shared_and_lock())
|
||||
{
|
||||
state = writing;
|
||||
}
|
||||
else if (mut.try_unlock_shared_and_lock_upgrade())
|
||||
{
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock();
|
||||
state = writing;
|
||||
}
|
||||
else
|
||||
{
|
||||
mut.unlock_shared();
|
||||
continue;
|
||||
}
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
mut.unlock_and_lock_upgrade();
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock_shared();
|
||||
assert(state == reading);
|
||||
mut.unlock_shared();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
print("try_clockwise = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_clockwise()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
if (mut.try_unlock_shared_and_lock_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
state = writing;
|
||||
}
|
||||
else if (mut.try_unlock_shared_and_lock_upgrade_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock();
|
||||
state = writing;
|
||||
}
|
||||
else
|
||||
{
|
||||
mut.unlock_shared();
|
||||
continue;
|
||||
}
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
mut.unlock_and_lock_upgrade();
|
||||
assert(state == reading);
|
||||
mut.unlock_upgrade_and_lock_shared();
|
||||
assert(state == reading);
|
||||
mut.unlock_shared();
|
||||
++count;
|
||||
}
|
||||
}
|
||||
print("try_for_clockwise = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_counter_clockwise()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_upgrade())
|
||||
{
|
||||
assert(state == reading);
|
||||
if (mut.try_unlock_upgrade_and_lock())
|
||||
{
|
||||
assert(state == reading);
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
mut.unlock_and_lock_shared();
|
||||
assert(state == reading);
|
||||
mut.unlock_shared();
|
||||
++count;
|
||||
}
|
||||
else
|
||||
{
|
||||
mut.unlock_upgrade();
|
||||
}
|
||||
}
|
||||
}
|
||||
print("try_counter_clockwise = ", count, '\n');
|
||||
}
|
||||
|
||||
void try_for_counter_clockwise()
|
||||
{
|
||||
typedef boost::chrono::steady_clock Clock;
|
||||
unsigned count = 0;
|
||||
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
|
||||
while (Clock::now() < until)
|
||||
{
|
||||
if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
if (mut.try_unlock_upgrade_and_lock_for(boost::chrono::microseconds(5)))
|
||||
{
|
||||
assert(state == reading);
|
||||
state = writing;
|
||||
assert(state == writing);
|
||||
state = reading;
|
||||
mut.unlock_and_lock_shared();
|
||||
assert(state == reading);
|
||||
mut.unlock_shared();
|
||||
++count;
|
||||
}
|
||||
else
|
||||
{
|
||||
mut.unlock_upgrade();
|
||||
}
|
||||
}
|
||||
}
|
||||
print("try_for_counter_clockwise = ", count, '\n');
|
||||
}
|
||||
|
||||
void
|
||||
test_upgrade_mutex()
|
||||
{
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(reader);
|
||||
boost::thread t2(writer);
|
||||
boost::thread t3(reader);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(try_reader);
|
||||
boost::thread t2(try_writer);
|
||||
boost::thread t3(try_reader);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(try_for_reader);
|
||||
boost::thread t2(try_for_writer);
|
||||
boost::thread t3(try_for_reader);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(reader);
|
||||
boost::thread t2(writer);
|
||||
boost::thread t3(upgradable);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(reader);
|
||||
boost::thread t2(writer);
|
||||
boost::thread t3(try_upgradable);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
boost::thread t1(reader);
|
||||
boost::thread t2(writer);
|
||||
boost::thread t3(try_for_upgradable);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
state = reading;
|
||||
boost::thread t1(clockwise);
|
||||
boost::thread t2(counter_clockwise);
|
||||
boost::thread t3(clockwise);
|
||||
boost::thread t4(counter_clockwise);
|
||||
t1.join();
|
||||
t2.join();
|
||||
t3.join();
|
||||
t4.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
{
|
||||
state = reading;
|
||||
boost::thread t1(try_clockwise);
|
||||
boost::thread t2(try_counter_clockwise);
|
||||
t1.join();
|
||||
t2.join();
|
||||
}
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
// {
|
||||
// state = reading;
|
||||
// boost::thread t1(try_for_clockwise);
|
||||
// boost::thread t2(try_for_counter_clockwise);
|
||||
// t1.join();
|
||||
// t2.join();
|
||||
// }
|
||||
// std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Assignment
|
||||
{
|
||||
|
||||
class A
|
||||
{
|
||||
typedef boost::upgrade_mutex mutex_type;
|
||||
typedef boost::shared_lock<mutex_type> SharedLock;
|
||||
typedef boost::upgrade_lock<mutex_type> UpgradeLock;
|
||||
typedef boost::unique_lock<mutex_type> Lock;
|
||||
|
||||
mutable mutex_type mut_;
|
||||
std::vector<double> data_;
|
||||
|
||||
public:
|
||||
|
||||
A(const A& a)
|
||||
{
|
||||
SharedLock _(a.mut_);
|
||||
data_ = a.data_;
|
||||
}
|
||||
|
||||
A& operator=(const A& a)
|
||||
{
|
||||
if (this != &a)
|
||||
{
|
||||
Lock this_lock(mut_, boost::defer_lock);
|
||||
SharedLock that_lock(a.mut_, boost::defer_lock);
|
||||
boost::lock(this_lock, that_lock);
|
||||
data_ = a.data_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void swap(A& a)
|
||||
{
|
||||
Lock this_lock(mut_, boost::defer_lock);
|
||||
Lock that_lock(a.mut_, boost::defer_lock);
|
||||
boost::lock(this_lock, that_lock);
|
||||
data_.swap(a.data_);
|
||||
}
|
||||
|
||||
void average(A& a)
|
||||
{
|
||||
assert(data_.size() == a.data_.size());
|
||||
assert(this != &a);
|
||||
|
||||
Lock this_lock(mut_, boost::defer_lock);
|
||||
UpgradeLock share_that_lock(a.mut_, boost::defer_lock);
|
||||
boost::lock(this_lock, share_that_lock);
|
||||
|
||||
for (unsigned i = 0; i < data_.size(); ++i)
|
||||
data_[i] = (data_[i] + a.data_[i]) / 2;
|
||||
|
||||
SharedLock share_this_lock(boost::move(this_lock));
|
||||
Lock that_lock(boost::move(share_that_lock));
|
||||
a.data_ = data_;
|
||||
}
|
||||
};
|
||||
|
||||
} // Assignment
|
||||
|
||||
void temp()
|
||||
{
|
||||
using namespace boost;
|
||||
static upgrade_mutex mut;
|
||||
unique_lock<upgrade_mutex> ul(mut);
|
||||
shared_lock<upgrade_mutex> sl;
|
||||
sl = BOOST_THREAD_MAKE_RV_REF(shared_lock<upgrade_mutex>(boost::move(ul)));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
typedef boost::chrono::high_resolution_clock Clock;
|
||||
typedef boost::chrono::duration<double> sec;
|
||||
Clock::time_point t0 = Clock::now();
|
||||
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
S::test_shared_mutex();
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
U::test_upgrade_mutex();
|
||||
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
|
||||
Clock::time_point t1 = Clock::now();
|
||||
std::cout << sec(t1 - t0) << '\n';
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#error "This platform doesn't support Boost.Chrono"
|
||||
#endif
|
||||
185
example/starvephil.cpp
Normal file
185
example/starvephil.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
#include <time.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
boost::mutex iomx;
|
||||
} // namespace
|
||||
|
||||
class canteen
|
||||
{
|
||||
public:
|
||||
canteen() : m_chickens(0) { }
|
||||
|
||||
void get(int id)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
while (m_chickens == 0)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << id <<
|
||||
": wot, no chickens? I'll WAIT ..." << std::endl;
|
||||
}
|
||||
m_condition.wait(lock);
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << id <<
|
||||
": those chickens look good ... one please ..." << std::endl;
|
||||
}
|
||||
m_chickens--;
|
||||
}
|
||||
void put(int value)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock()
|
||||
<< ") Chef: ouch ... make room ... this dish is "
|
||||
<< "very hot ..." << std::endl;
|
||||
}
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
xt.sec += 3;
|
||||
boost::thread::sleep(xt);
|
||||
m_chickens += value;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() <<
|
||||
") Chef: more chickens ... " << m_chickens <<
|
||||
" now available ... NOTIFYING ..." << std::endl;
|
||||
}
|
||||
m_condition.notify_all();
|
||||
}
|
||||
|
||||
private:
|
||||
boost::mutex m_mutex;
|
||||
boost::condition m_condition;
|
||||
int m_chickens;
|
||||
};
|
||||
|
||||
canteen g_canteen;
|
||||
|
||||
void chef()
|
||||
{
|
||||
const int chickens = 4;
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
|
||||
}
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
xt.sec += 2;
|
||||
boost::thread::sleep(xt);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Chef: " << chickens
|
||||
<< " chickens, ready-to-go ..." << std::endl;
|
||||
}
|
||||
g_canteen.put(chickens);
|
||||
}
|
||||
}
|
||||
|
||||
struct phil
|
||||
{
|
||||
phil(int id) : m_id(id) { }
|
||||
void run() {
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": starting ..." << std::endl;
|
||||
}
|
||||
for (;;)
|
||||
{
|
||||
if (m_id > 0)
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
xt.sec += 3;
|
||||
boost::thread::sleep(xt);
|
||||
}
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": gotta eat ..." << std::endl;
|
||||
}
|
||||
g_canteen.get(m_id);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(iomx);
|
||||
std::cout << "(" << clock() << ") Phil" << m_id
|
||||
<< ": mmm ... that's good ..." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void do_thread(void* param) {
|
||||
static_cast<phil*>(param)->run();
|
||||
}
|
||||
|
||||
int m_id;
|
||||
};
|
||||
|
||||
struct thread_adapt
|
||||
{
|
||||
thread_adapt(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
int operator()() const
|
||||
{
|
||||
_func(_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread thrd_chef(&chef);
|
||||
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
|
||||
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
|
||||
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
|
||||
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
|
||||
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
|
||||
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
|
||||
|
||||
thrd_chef.join();
|
||||
thrd_phil0.join();
|
||||
thrd_phil1.join();
|
||||
thrd_phil2.join();
|
||||
thrd_phil3.join();
|
||||
thrd_phil4.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
135
example/tennis.cpp
Normal file
135
example/tennis.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
# include <windows.h>
|
||||
# include <process.h>
|
||||
#endif
|
||||
|
||||
enum game_state
|
||||
{
|
||||
START,
|
||||
PLAYER_A,
|
||||
PLAYER_B,
|
||||
GAME_OVER,
|
||||
ONE_PLAYER_GONE,
|
||||
BOTH_PLAYERS_GONE
|
||||
};
|
||||
|
||||
int state;
|
||||
boost::mutex mutex;
|
||||
boost::condition cond;
|
||||
|
||||
char* player_name(int state)
|
||||
{
|
||||
if (state == PLAYER_A)
|
||||
return "PLAYER-A";
|
||||
if (state == PLAYER_B)
|
||||
return "PLAYER-B";
|
||||
throw "bad player";
|
||||
return 0;
|
||||
}
|
||||
|
||||
void player(void* param)
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
|
||||
int active = (int)param;
|
||||
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
|
||||
|
||||
while (state < GAME_OVER)
|
||||
{
|
||||
std::cout << player_name(active) << ": Play." << std::endl;
|
||||
state = other;
|
||||
cond.notify_all();
|
||||
do
|
||||
{
|
||||
cond.wait(lock);
|
||||
if (state == other)
|
||||
{
|
||||
std::cout << "---" << player_name(active)
|
||||
<< ": Spurious wakeup!" << std::endl;
|
||||
}
|
||||
} while (state == other);
|
||||
}
|
||||
|
||||
++state;
|
||||
std::cout << player_name(active) << ": Gone." << std::endl;
|
||||
cond.notify_all();
|
||||
}
|
||||
|
||||
struct thread_adapt
|
||||
{
|
||||
thread_adapt(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
int operator()() const
|
||||
{
|
||||
_func(_param);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
class thread_adapter
|
||||
{
|
||||
public:
|
||||
thread_adapter(void (*func)(void*), void* param)
|
||||
: _func(func), _param(param)
|
||||
{
|
||||
}
|
||||
void operator()() const { _func(_param); }
|
||||
private:
|
||||
void (*_func)(void*);
|
||||
void* _param;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
state = START;
|
||||
|
||||
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
|
||||
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
|
||||
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt);
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "---Noise ON..." << std::endl;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 1000000000; ++i)
|
||||
cond.notify_all();
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "---Noise OFF..." << std::endl;
|
||||
state = GAME_OVER;
|
||||
cond.notify_all();
|
||||
do
|
||||
{
|
||||
cond.wait(lock);
|
||||
} while (state != BOTH_PLAYERS_GONE);
|
||||
}
|
||||
|
||||
std::cout << "GAME OVER" << std::endl;
|
||||
|
||||
thrda.join();
|
||||
thrdb.join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
35
example/thread.cpp
Normal file
35
example/thread.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <iostream>
|
||||
|
||||
struct thread_alarm
|
||||
{
|
||||
thread_alarm(int secs) : m_secs(secs) { }
|
||||
void operator()()
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
xt.sec += m_secs;
|
||||
|
||||
boost::thread::sleep(xt);
|
||||
|
||||
std::cout << "alarm sounded..." << std::endl;
|
||||
}
|
||||
|
||||
int m_secs;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
int secs = 5;
|
||||
std::cout << "setting alarm for 5 seconds..." << std::endl;
|
||||
thread_alarm alarm(secs);
|
||||
boost::thread thrd(alarm);
|
||||
thrd.join();
|
||||
}
|
||||
25
example/thread_group.cpp
Normal file
25
example/thread_group.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int count = 0;
|
||||
boost::mutex mutex;
|
||||
|
||||
void increment_count()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
std::cout << "count = " << ++count << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i = 0; i < 10; ++i)
|
||||
threads.create_thread(&increment_count);
|
||||
threads.join_all();
|
||||
}
|
||||
36
example/tss.cpp
Normal file
36
example/tss.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <cassert>
|
||||
|
||||
boost::thread_specific_ptr<int> value;
|
||||
|
||||
void increment()
|
||||
{
|
||||
int* p = value.get();
|
||||
++*p;
|
||||
}
|
||||
|
||||
void thread_proc()
|
||||
{
|
||||
value.reset(new int(0)); // initialize the thread's storage
|
||||
for (int i=0; i<10; ++i)
|
||||
{
|
||||
increment();
|
||||
int* p = value.get();
|
||||
assert(*p == i+1);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::thread_group threads;
|
||||
for (int i=0; i<5; ++i)
|
||||
threads.create_thread(&thread_proc);
|
||||
threads.join_all();
|
||||
}
|
||||
16
example/xtime.cpp
Normal file
16
example/xtime.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::xtime xt;
|
||||
boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
xt.sec += 1;
|
||||
boost::thread::sleep(xt); // Sleep for 1 second
|
||||
}
|
||||
26
include/boost/thread.hpp
Normal file
26
include/boost/thread.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// (C) Copyright 2008-9 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See www.boost.org/libs/thread for documentation.
|
||||
|
||||
#if !defined(BOOST_THREAD_WEK01082003_HPP)
|
||||
#define BOOST_THREAD_WEK01082003_HPP
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/recursive_mutex.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/barrier.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#endif
|
||||
64
include/boost/thread/barrier.hpp
Normal file
64
include/boost/thread/barrier.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_BARRIER_JDM030602_HPP
|
||||
#define BOOST_BARRIER_JDM030602_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class barrier
|
||||
{
|
||||
public:
|
||||
barrier(unsigned int count)
|
||||
: m_threshold(count), m_count(count), m_generation(0)
|
||||
{
|
||||
if (count == 0)
|
||||
boost::throw_exception(thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
|
||||
}
|
||||
|
||||
bool wait()
|
||||
{
|
||||
boost::mutex::scoped_lock lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = m_threshold;
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
condition_variable m_cond;
|
||||
unsigned int m_threshold;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
16
include/boost/thread/condition.hpp
Normal file
16
include/boost/thread/condition.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_HPP
|
||||
#define BOOST_THREAD_CONDITION_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef condition_variable_any condition;
|
||||
}
|
||||
|
||||
#endif
|
||||
21
include/boost/thread/condition_variable.hpp
Normal file
21
include/boost/thread/condition_variable.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_HPP
|
||||
|
||||
// condition_variable.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/condition_variable.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/condition_variable.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
26
include/boost/thread/cv_status.hpp
Normal file
26
include/boost/thread/cv_status.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
// cv_status.hpp
|
||||
//
|
||||
// Copyright (C) 2011 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_CV_STATUS_HPP
|
||||
#define BOOST_THREAD_CV_STATUS_HPP
|
||||
|
||||
#include <boost/detail/scoped_enum_emulation.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
// enum class cv_status;
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status)
|
||||
{
|
||||
no_timeout,
|
||||
timeout
|
||||
}
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(cv_status)
|
||||
}
|
||||
|
||||
#endif // header
|
||||
220
include/boost/thread/detail/config.hpp
Normal file
220
include/boost/thread/detail/config.hpp
Normal file
@@ -0,0 +1,220 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2011-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)
|
||||
|
||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
// This compiler doesn't support Boost.Chrono
|
||||
#if defined __IBMCPP__ && (__IBMCPP__ < 1100)
|
||||
#define BOOST_THREAD_DONT_USE_CHRONO
|
||||
#endif
|
||||
|
||||
// This compiler doesn't support Boost.Move
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
#define BOOST_THREAD_DONT_USE_MOVE
|
||||
#endif
|
||||
|
||||
// This compiler doesn't support Boost.Container Allocators files
|
||||
#if defined __SUNPRO_CC
|
||||
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
|
||||
#if defined _WIN32_WCE && _WIN32_WCE==0x501
|
||||
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID
|
||||
#define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#endif
|
||||
|
||||
// Default version is 2
|
||||
#if !defined BOOST_THREAD_VERSION
|
||||
#define BOOST_THREAD_VERSION 2
|
||||
#else
|
||||
#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3
|
||||
#error "BOOST_THREAD_VERSION must be 2 or 3"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Uses Boost.System by default if not stated the opposite defining BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#if ! defined BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#define BOOST_THREAD_USES_SYSTEM
|
||||
#endif
|
||||
|
||||
// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO or BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_DONT_USE_SYSTEM
|
||||
#define BOOST_THREAD_USES_CHRONO
|
||||
#endif
|
||||
|
||||
// Don't provided by default in version 1.
|
||||
#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit
|
||||
#else
|
||||
#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION
|
||||
#endif
|
||||
|
||||
|
||||
// Uses Boost.Move by default if not stated the opposite defining BOOST_THREAD_DONT_USE_MOVE
|
||||
#if ! defined BOOST_THREAD_DONT_USE_MOVE
|
||||
#if ! defined BOOST_THREAD_USES_MOVE
|
||||
//#define BOOST_THREAD_USES_MOVE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION==2
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY
|
||||
#define BOOST_THREAD_PROMISE_LAZY
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_THREAD_VERSION==3
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11
|
||||
#define BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION
|
||||
#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#endif
|
||||
#if ! defined BOOST_THREAD_DONT_USE_MOVE
|
||||
#if ! defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_USES_MOVE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
|
||||
#endif
|
||||
|
||||
// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52
|
||||
// BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
|
||||
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
# pragma warn -8008 // Condition always true/false
|
||||
# pragma warn -8080 // Identifier declared but never used
|
||||
# pragma warn -8057 // Parameter never used
|
||||
# pragma warn -8066 // Unreachable code
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
// provided for backwards compatibility, since this
|
||||
// macro was used for several releases by mistake.
|
||||
#if defined(BOOST_THREAD_DYN_DLL)
|
||||
# define BOOST_THREAD_DYN_LINK
|
||||
#endif
|
||||
|
||||
// compatibility with the rest of Boost's auto-linking code:
|
||||
#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
|
||||
# undef BOOST_THREAD_USE_LIB
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
|
||||
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
|
||||
#else //Use default
|
||||
# if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
|
||||
//For compilers supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads lib
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# else
|
||||
//For compilers not yet supporting auto-tss cleanup
|
||||
//with Boost.Threads lib, use Boost.Threads dll
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# endif
|
||||
# else
|
||||
# define BOOST_THREAD_USE_LIB
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_DECLSPEC)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT
|
||||
//# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT
|
||||
//# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define BOOST_THREAD_DECL
|
||||
# endif
|
||||
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_VISIBLE
|
||||
|
||||
#else
|
||||
# define BOOST_THREAD_DECL
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
|
||||
//
|
||||
// Automatically link to the correct build variant where possible.
|
||||
//
|
||||
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
|
||||
//
|
||||
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_USE_DLL)
|
||||
# define BOOST_DYN_LINK
|
||||
#endif
|
||||
//
|
||||
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_LIB_NAME)
|
||||
# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME
|
||||
#else
|
||||
# define BOOST_LIB_NAME boost_thread
|
||||
#endif
|
||||
//
|
||||
// If we're importing code from a dll, then tell auto_link.hpp about it:
|
||||
//
|
||||
// And include the header that does the work:
|
||||
//
|
||||
#include <boost/config/auto_link.hpp>
|
||||
#endif // auto-linking disabled
|
||||
|
||||
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP
|
||||
|
||||
// Change Log:
|
||||
// 22 Jan 05 Roland Schwarz (speedsnail)
|
||||
// Usage of BOOST_HAS_DECLSPEC macro.
|
||||
// Default again is static lib usage.
|
||||
// BOOST_DYN_LINK only defined when autolink included.
|
||||
45
include/boost/thread/detail/delete.hpp
Normal file
45
include/boost/thread/detail/delete.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (C) 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)
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_DELETE_HPP
|
||||
#define BOOST_THREAD_DETAIL_DELETE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
/**
|
||||
* BOOST_THREAD_DELETE_COPY_CTOR deletes the copy constructor when the compiler supports it or
|
||||
* makes it private.
|
||||
*
|
||||
* BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or
|
||||
* makes it private.
|
||||
*/
|
||||
#ifndef BOOST_NO_DELETED_FUNCTIONS
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
CLASS(CLASS const&) = delete; \
|
||||
|
||||
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
|
||||
CLASS& operator=(CLASS const&) = delete;
|
||||
|
||||
#else // BOOST_NO_DELETED_FUNCTIONS
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
private: \
|
||||
CLASS(CLASS&); \
|
||||
public:
|
||||
|
||||
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
|
||||
private: \
|
||||
CLASS& operator=(CLASS&); \
|
||||
public:
|
||||
#endif // BOOST_NO_DELETED_FUNCTIONS
|
||||
|
||||
/**
|
||||
* BOOST_THREAD_NO_COPYABLE deletes the copy constructor and assignment when the compiler supports it or
|
||||
* makes them private.
|
||||
*/
|
||||
#define BOOST_THREAD_NO_COPYABLE(CLASS) \
|
||||
BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS)
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_DELETE_HPP
|
||||
39
include/boost/thread/detail/force_cast.hpp
Normal file
39
include/boost/thread/detail/force_cast.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Mac Murrett
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
|
||||
#define BOOST_FORCE_CAST_MJM012402_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace thread {
|
||||
|
||||
// force_cast will convert anything to anything.
|
||||
|
||||
// general case
|
||||
template<class Return_Type, class Argument_Type>
|
||||
inline Return_Type &force_cast(Argument_Type &rSrc)
|
||||
{
|
||||
return(*reinterpret_cast<Return_Type *>(&rSrc));
|
||||
}
|
||||
|
||||
// specialization for const
|
||||
template<class Return_Type, class Argument_Type>
|
||||
inline const Return_Type &force_cast(const Argument_Type &rSrc)
|
||||
{
|
||||
return(*reinterpret_cast<const Return_Type *>(&rSrc));
|
||||
}
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_FORCE_CAST_MJM012402_HPP
|
||||
54
include/boost/thread/detail/memory.hpp
Normal file
54
include/boost/thread/detail/memory.hpp
Normal file
@@ -0,0 +1,54 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
// 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.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
#define BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
template <class _Alloc>
|
||||
class allocator_destructor
|
||||
{
|
||||
typedef container::allocator_traits<_Alloc> alloc_traits;
|
||||
public:
|
||||
typedef typename alloc_traits::pointer pointer;
|
||||
typedef typename alloc_traits::size_type size_type;
|
||||
private:
|
||||
_Alloc& alloc_;
|
||||
size_type s_;
|
||||
public:
|
||||
allocator_destructor(_Alloc& a, size_type s)BOOST_NOEXCEPT
|
||||
: alloc_(a), s_(s)
|
||||
{}
|
||||
void operator()(pointer p)BOOST_NOEXCEPT
|
||||
{
|
||||
alloc_traits::deallocate(alloc_, p, s_);
|
||||
}
|
||||
};
|
||||
} //namespace thread_detail
|
||||
|
||||
typedef container::allocator_arg_t allocator_arg_t;
|
||||
BOOST_CONSTEXPR_OR_CONST allocator_arg_t allocator_arg = {};
|
||||
|
||||
template <class T, class Alloc>
|
||||
struct uses_allocator: public container::uses_allocator<T, Alloc>
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
246
include/boost/thread/detail/move.hpp
Normal file
246
include/boost/thread/detail/move.hpp
Normal file
@@ -0,0 +1,246 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_MOVE_HPP
|
||||
#define BOOST_THREAD_MOVE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization;
|
||||
template<typename T>
|
||||
struct thread_move_t
|
||||
{
|
||||
T& t;
|
||||
explicit thread_move_t(T& t_):
|
||||
t(t_)
|
||||
{}
|
||||
|
||||
T& operator*() const
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
T* operator->() const
|
||||
{
|
||||
return &t;
|
||||
}
|
||||
private:
|
||||
void operator=(thread_move_t&);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename T>
|
||||
typename enable_if<boost::is_convertible<T&,boost::detail::thread_move_t<T> >, boost::detail::thread_move_t<T> >::type move(T& t)
|
||||
{
|
||||
return boost::detail::thread_move_t<T>(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
}
|
||||
|
||||
#if ! defined BOOST_NO_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
|
||||
#define BOOST_THREAD_RV(V) V
|
||||
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE
|
||||
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
|
||||
#define BOOST_THREAD_DCL_MOVABLE(TYPE)
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, true> \
|
||||
{}; \
|
||||
}
|
||||
|
||||
#elif ! defined BOOST_NO_RVALUE_REFERENCES && defined BOOST_MSVC
|
||||
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
|
||||
#define BOOST_THREAD_RV(V) V
|
||||
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE
|
||||
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
|
||||
#define BOOST_THREAD_DCL_MOVABLE(TYPE)
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, true> \
|
||||
{}; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
|
||||
#define BOOST_THREAD_RV(V) V
|
||||
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
|
||||
#define BOOST_THREAD_DCL_MOVABLE(TYPE)
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
namespace detail { \
|
||||
template <typename T> \
|
||||
struct has_move_emulation_enabled_aux_dummy_specialization<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: integral_constant<bool, true> \
|
||||
{}; \
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_RV_REF(TYPE) boost::detail::thread_move_t< TYPE >
|
||||
#define BOOST_THREAD_RV_REF_BEG boost::detail::thread_move_t<
|
||||
#define BOOST_THREAD_RV_REF_END >
|
||||
#define BOOST_THREAD_RV(V) (*V)
|
||||
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE(TYPE) \
|
||||
template <> \
|
||||
struct has_move_emulation_enabled_aux< TYPE > \
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \
|
||||
{};
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
|
||||
template <typename T> \
|
||||
struct has_move_emulation_enabled_aux<
|
||||
|
||||
#define BOOST_THREAD_DCL_MOVABLE_END > \
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \
|
||||
{};
|
||||
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <typename T>
|
||||
BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type)
|
||||
make_rv_ref(T v) BOOST_NOEXCEPT
|
||||
{
|
||||
return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v);
|
||||
}
|
||||
// template <typename T>
|
||||
// BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type)
|
||||
// make_rv_ref(T &v) BOOST_NOEXCEPT
|
||||
// {
|
||||
// return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v);
|
||||
// }
|
||||
// template <typename T>
|
||||
// const BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type)
|
||||
// make_rv_ref(T const&v) BOOST_NOEXCEPT
|
||||
// {
|
||||
// return (const BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v);
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE.move()
|
||||
//#define BOOST_THREAD_MAKE_RV_REF(RVALUE) boost::detail::make_rv_ref(RVALUE)
|
||||
#endif
|
||||
|
||||
|
||||
#if ! defined BOOST_NO_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE)
|
||||
|
||||
#else
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE) \
|
||||
::boost::rv<TYPE>& move() BOOST_NOEXCEPT \
|
||||
{ \
|
||||
return *static_cast< ::boost::rv<TYPE>* >(this); \
|
||||
} \
|
||||
const ::boost::rv<TYPE>& move() const BOOST_NOEXCEPT \
|
||||
{ \
|
||||
return *static_cast<const ::boost::rv<TYPE>* >(this); \
|
||||
} \
|
||||
operator ::boost::rv<TYPE>&() \
|
||||
{ \
|
||||
return *static_cast< ::boost::rv<TYPE>* >(this); \
|
||||
} \
|
||||
operator const ::boost::rv<TYPE>&() const \
|
||||
{ \
|
||||
return *static_cast<const ::boost::rv<TYPE>* >(this); \
|
||||
}\
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE) \
|
||||
operator ::boost::detail::thread_move_t<TYPE>() BOOST_NOEXCEPT \
|
||||
{ \
|
||||
return move(); \
|
||||
} \
|
||||
::boost::detail::thread_move_t<TYPE> move() BOOST_NOEXCEPT \
|
||||
{ \
|
||||
::boost::detail::thread_move_t<TYPE> x(*this); \
|
||||
return x; \
|
||||
} \
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_MOVABLE_ONLY(TYPE) \
|
||||
BOOST_THREAD_NO_COPYABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
|
||||
#define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
|
||||
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
namespace boost
|
||||
{ namespace thread_detail
|
||||
{
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
decay_copy(T&& t)
|
||||
{
|
||||
return boost::forward<T>(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
73
include/boost/thread/detail/platform.hpp
Normal file
73
include/boost/thread/detail/platform.hpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright 2006 Roland Schwarz.
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// This work is a reimplementation along the design and ideas
|
||||
// of William E. Kempf.
|
||||
|
||||
#ifndef BOOST_THREAD_RS06040501_HPP
|
||||
#define BOOST_THREAD_RS06040501_HPP
|
||||
|
||||
// fetch compiler and platform configuration
|
||||
#include <boost/config.hpp>
|
||||
|
||||
// insist on threading support being available:
|
||||
#include <boost/config/requires_threads.hpp>
|
||||
|
||||
// choose platform
|
||||
#if defined(linux) || defined(__linux) || defined(__linux__)
|
||||
# define BOOST_THREAD_LINUX
|
||||
//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000)
|
||||
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
|
||||
# define BOOST_THREAD_BSD
|
||||
#elif defined(sun) || defined(__sun)
|
||||
# define BOOST_THREAD_SOLARIS
|
||||
#elif defined(__sgi)
|
||||
# define BOOST_THREAD_IRIX
|
||||
#elif defined(__hpux)
|
||||
# define BOOST_THREAD_HPUX
|
||||
#elif defined(__CYGWIN__)
|
||||
# define BOOST_THREAD_CYGWIN
|
||||
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
|
||||
# define BOOST_THREAD_WIN32
|
||||
#elif defined(__BEOS__)
|
||||
# define BOOST_THREAD_BEOS
|
||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||
# define BOOST_THREAD_MACOS
|
||||
//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000)
|
||||
#elif defined(__IBMCPP__) || defined(_AIX)
|
||||
# define BOOST_THREAD_AIX
|
||||
#elif defined(__amigaos__)
|
||||
# define BOOST_THREAD_AMIGAOS
|
||||
#elif defined(__QNXNTO__)
|
||||
# define BOOST_THREAD_QNXNTO
|
||||
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
|
||||
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_POSIX
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// For every supported platform add a new entry into the dispatch table below.
|
||||
// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native
|
||||
// threading is available, the user may choose, by defining BOOST_THREAD_POSIX
|
||||
// in her source. If a platform is known to support pthreads and no native
|
||||
// port of boost_thread is available just specify "pthread" in the
|
||||
// dispatcher table. If there is no entry for a platform but pthreads is
|
||||
// available on the platform, pthread is choosen as default. If nothing is
|
||||
// available the preprocessor will fail with a diagnostic message.
|
||||
|
||||
#if defined(BOOST_THREAD_POSIX)
|
||||
# define BOOST_THREAD_PLATFORM_PTHREAD
|
||||
#else
|
||||
# if defined(BOOST_THREAD_WIN32)
|
||||
# define BOOST_THREAD_PLATFORM_WIN32
|
||||
# elif defined(BOOST_HAS_PTHREADS)
|
||||
# define BOOST_THREAD_PLATFORM_PTHREAD
|
||||
# else
|
||||
# error "Sorry, no boost threads are available for this platform."
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#endif // BOOST_THREAD_RS06040501_HPP
|
||||
59
include/boost/thread/detail/singleton.hpp
Normal file
59
include/boost/thread/detail/singleton.hpp
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// Mac Murrett
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org for most recent version including documentation.
|
||||
|
||||
#ifndef BOOST_SINGLETON_MJM012402_HPP
|
||||
#define BOOST_SINGLETON_MJM012402_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
namespace boost {
|
||||
namespace detail {
|
||||
namespace thread {
|
||||
|
||||
// class singleton has the same goal as all singletons: create one instance of
|
||||
// a class on demand, then dish it out as requested.
|
||||
|
||||
template <class T>
|
||||
class singleton : private T
|
||||
{
|
||||
private:
|
||||
singleton();
|
||||
~singleton();
|
||||
|
||||
public:
|
||||
static T &instance();
|
||||
};
|
||||
|
||||
|
||||
template <class T>
|
||||
inline singleton<T>::singleton()
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline singleton<T>::~singleton()
|
||||
{
|
||||
/* no-op */
|
||||
}
|
||||
|
||||
template <class T>
|
||||
/*static*/ T &singleton<T>::instance()
|
||||
{
|
||||
// function-local static to force this to work correctly at static
|
||||
// initialization time.
|
||||
static singleton<T> s_oT;
|
||||
return(s_oT);
|
||||
}
|
||||
|
||||
} // namespace thread
|
||||
} // namespace detail
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_SINGLETON_MJM012402_HPP
|
||||
642
include/boost/thread/detail/thread.hpp
Normal file
642
include/boost/thread/detail/thread.hpp
Normal file
@@ -0,0 +1,642 @@
|
||||
#ifndef BOOST_THREAD_THREAD_COMMON_HPP
|
||||
#define BOOST_THREAD_THREAD_COMMON_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-10 Anthony Williams
|
||||
// (C) Copyright 20011-12 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
#include <ostream>
|
||||
#endif
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4251)
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename F>
|
||||
class thread_data:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
thread_data(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(boost::forward<F>(f_))
|
||||
{}
|
||||
// This overloading must be removed if we want the packaged_task's tests to pass.
|
||||
// thread_data(F& f_):
|
||||
// f(f_)
|
||||
// {}
|
||||
#else
|
||||
|
||||
thread_data(BOOST_THREAD_RV_REF(F) f_):
|
||||
f(f_)
|
||||
{}
|
||||
thread_data(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
#endif
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
private:
|
||||
F f;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
class thread_data<boost::reference_wrapper<F> >:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
private:
|
||||
F& f;
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
thread_data(boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
class thread_data<const boost::reference_wrapper<F> >:
|
||||
public detail::thread_data_base
|
||||
{
|
||||
private:
|
||||
F& f;
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
thread_data(const boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
class BOOST_THREAD_DECL thread
|
||||
{
|
||||
public:
|
||||
typedef thread_attributes attributes;
|
||||
|
||||
BOOST_THREAD_MOVABLE_ONLY(thread)
|
||||
private:
|
||||
|
||||
void release_handle();
|
||||
|
||||
detail::thread_data_ptr thread_info;
|
||||
|
||||
void start_thread();
|
||||
void start_thread(const attributes& attr);
|
||||
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
|
||||
boost::forward<F>(f)));
|
||||
}
|
||||
static inline detail::thread_data_ptr make_thread_info(void (*f)())
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
|
||||
boost::forward<void(*)()>(f)));
|
||||
}
|
||||
#else
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(F f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
|
||||
}
|
||||
template<typename F>
|
||||
static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
|
||||
{
|
||||
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
|
||||
}
|
||||
|
||||
#endif
|
||||
struct dummy;
|
||||
public:
|
||||
#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
thread(const volatile thread&);
|
||||
#endif
|
||||
#endif
|
||||
thread() BOOST_NOEXCEPT;
|
||||
~thread()
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
|
||||
if (joinable()) {
|
||||
std::terminate();
|
||||
}
|
||||
#else
|
||||
detach();
|
||||
#endif
|
||||
}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template <
|
||||
class F
|
||||
>
|
||||
explicit thread(BOOST_THREAD_RV_REF(F) f
|
||||
, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
|
||||
):
|
||||
thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <
|
||||
class F
|
||||
>
|
||||
thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f):
|
||||
thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{
|
||||
start_thread(attrs);
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef BOOST_NO_SFINAE
|
||||
template <class F>
|
||||
explicit thread(F f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(attributes& attrs, F f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread(attrs);
|
||||
}
|
||||
#else
|
||||
template <class F>
|
||||
explicit thread(F f
|
||||
// todo Disable also if Or is_same<typename decay<F>::type, thread>
|
||||
, typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F>
|
||||
thread(attributes& attrs, F f
|
||||
, typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread(attrs);
|
||||
}
|
||||
#endif
|
||||
template <class F>
|
||||
explicit thread(BOOST_THREAD_RV_REF(F) f
|
||||
, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
|
||||
):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
start_thread(attrs);
|
||||
}
|
||||
#endif
|
||||
thread(BOOST_THREAD_RV_REF(thread) x)
|
||||
{
|
||||
thread_info=BOOST_THREAD_RV(x).thread_info;
|
||||
BOOST_THREAD_RV(x).thread_info.reset();
|
||||
}
|
||||
#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF.
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
thread& operator=(thread x)
|
||||
{
|
||||
swap(x);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
thread& operator=(BOOST_THREAD_RV_REF(thread) other) BOOST_NOEXCEPT
|
||||
{
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
|
||||
if (joinable()) std::terminate();
|
||||
#endif
|
||||
thread_info=BOOST_THREAD_RV(other).thread_info;
|
||||
BOOST_THREAD_RV(other).thread_info.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <class F,class A1>
|
||||
thread(F f,A1 a1,typename disable_if<boost::is_convertible<F&,thread_attributes >, dummy* >::type=0):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
template <class F,class A1,class A2>
|
||||
thread(F f,A1 a1,A2 a2):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
|
||||
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
|
||||
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
|
||||
{
|
||||
start_thread();
|
||||
}
|
||||
|
||||
void swap(thread& x) BOOST_NOEXCEPT
|
||||
{
|
||||
thread_info.swap(x.thread_info);
|
||||
}
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE id;
|
||||
id get_id() const BOOST_NOEXCEPT;
|
||||
|
||||
|
||||
bool joinable() const BOOST_NOEXCEPT;
|
||||
void join();
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
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);
|
||||
}
|
||||
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();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_join_until(s_now + ceil<nanoseconds>(t - c_now));
|
||||
}
|
||||
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)
|
||||
bool timed_join(const system_time& abs_time);
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp);
|
||||
#endif
|
||||
public:
|
||||
|
||||
#else
|
||||
bool timed_join(const system_time& abs_time)
|
||||
{
|
||||
struct timespec const ts=detail::get_timespec(abs_time);
|
||||
return do_try_join_until(ts);
|
||||
}
|
||||
#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;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
return do_try_join_until(ts);
|
||||
}
|
||||
#endif
|
||||
private:
|
||||
bool do_try_join_until(struct timespec const &timeout);
|
||||
public:
|
||||
|
||||
#endif
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline bool timed_join(TimeDuration const& rel_time)
|
||||
{
|
||||
return timed_join(get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
void detach() BOOST_NOEXCEPT;
|
||||
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
|
||||
|
||||
#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
|
||||
typedef detail::thread_data_base::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
// Use thread::id when comparisions are needed
|
||||
// backwards compatibility
|
||||
bool operator==(const thread& other) const;
|
||||
bool operator!=(const thread& other) const;
|
||||
#endif
|
||||
static inline void yield() BOOST_NOEXCEPT
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
|
||||
static inline void sleep(const system_time& xt)
|
||||
{
|
||||
this_thread::sleep(xt);
|
||||
}
|
||||
|
||||
// extensions
|
||||
void interrupt();
|
||||
bool interruption_requested() const BOOST_NOEXCEPT;
|
||||
};
|
||||
|
||||
inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT
|
||||
{
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
inline thread&& move(thread& t) BOOST_NOEXCEPT
|
||||
{
|
||||
return static_cast<thread&&>(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_THREAD_DCL_MOVABLE(thread)
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT;
|
||||
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT;
|
||||
bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT;
|
||||
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
|
||||
{
|
||||
sleep(system_time(abs_time));
|
||||
}
|
||||
}
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread::id
|
||||
{
|
||||
private:
|
||||
friend 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
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
typedef unsigned int data;
|
||||
#else
|
||||
typedef thread::native_handle_type data;
|
||||
#endif
|
||||
#else
|
||||
typedef detail::thread_data_ptr data;
|
||||
#endif
|
||||
data thread_data;
|
||||
|
||||
id(data thread_data_):
|
||||
thread_data(thread_data_)
|
||||
{}
|
||||
friend class thread;
|
||||
friend id BOOST_THREAD_DECL this_thread::get_id() BOOST_NOEXCEPT;
|
||||
public:
|
||||
id() BOOST_NOEXCEPT:
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
thread_data(0)
|
||||
#else
|
||||
thread_data(0)
|
||||
#endif
|
||||
#else
|
||||
thread_data()
|
||||
#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;
|
||||
}
|
||||
|
||||
bool operator!=(const id& y) const BOOST_NOEXCEPT
|
||||
{
|
||||
return thread_data!=y.thread_data;
|
||||
}
|
||||
|
||||
bool operator<(const id& y) const BOOST_NOEXCEPT
|
||||
{
|
||||
return thread_data<y.thread_data;
|
||||
}
|
||||
|
||||
bool operator>(const id& y) const BOOST_NOEXCEPT
|
||||
{
|
||||
return y.thread_data<thread_data;
|
||||
}
|
||||
|
||||
bool operator<=(const id& y) const BOOST_NOEXCEPT
|
||||
{
|
||||
return !(y.thread_data<thread_data);
|
||||
}
|
||||
|
||||
bool operator>=(const id& y) const BOOST_NOEXCEPT
|
||||
{
|
||||
return !(thread_data<y.thread_data);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
template<class charT, class traits>
|
||||
friend BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
|
||||
{
|
||||
if(x.thread_data)
|
||||
{
|
||||
io::ios_flags_saver ifs( os );
|
||||
return os<< std::hex << x.thread_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return os<<"{Not-any-thread}";
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<class charT, class traits>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
print(std::basic_ostream<charT, traits>& os) const
|
||||
{
|
||||
if(thread_data)
|
||||
{
|
||||
io::ios_flags_saver ifs( os );
|
||||
return os<< std::hex << thread_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return os<<"{Not-any-thread}";
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template<class charT, class traits>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
|
||||
{
|
||||
return x.print(os);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
|
||||
inline bool thread::operator==(const thread& other) const
|
||||
{
|
||||
return get_id()==other.get_id();
|
||||
}
|
||||
|
||||
inline bool thread::operator!=(const thread& other) const
|
||||
{
|
||||
return get_id()!=other.get_id();
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_function_base
|
||||
{
|
||||
virtual ~thread_exit_function_base()
|
||||
{}
|
||||
virtual void operator()()=0;
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
struct thread_exit_function:
|
||||
thread_exit_function_base
|
||||
{
|
||||
F f;
|
||||
|
||||
thread_exit_function(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
void operator()()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template<typename F>
|
||||
void at_thread_exit(F f)
|
||||
{
|
||||
detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
|
||||
detail::add_thread_exit_function(thread_exit_func);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
108
include/boost/thread/detail/thread_group.hpp
Normal file
108
include/boost/thread/detail/thread_group.hpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
|
||||
#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-9 Anthony Williams
|
||||
|
||||
#include <list>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4251)
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread_group
|
||||
{
|
||||
private:
|
||||
thread_group(thread_group const&);
|
||||
thread_group& operator=(thread_group const&);
|
||||
public:
|
||||
thread_group() {}
|
||||
~thread_group()
|
||||
{
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
thread* create_thread(F threadfunc)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
std::auto_ptr<thread> new_thread(new thread(threadfunc));
|
||||
threads.push_back(new_thread.get());
|
||||
return new_thread.release();
|
||||
}
|
||||
|
||||
void add_thread(thread* thrd)
|
||||
{
|
||||
if(thrd)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
threads.push_back(thrd);
|
||||
}
|
||||
}
|
||||
|
||||
void remove_thread(thread* thrd)
|
||||
{
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
|
||||
if(it!=threads.end())
|
||||
{
|
||||
threads.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void join_all()
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->join();
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt_all()
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
|
||||
it!=end;
|
||||
++it)
|
||||
{
|
||||
(*it)->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
size_t size() const
|
||||
{
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
return threads.size();
|
||||
}
|
||||
|
||||
private:
|
||||
std::list<thread*> threads;
|
||||
mutable shared_mutex m;
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
23
include/boost/thread/detail/thread_heap_alloc.hpp
Normal file
23
include/boost/thread/detail/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
|
||||
#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
|
||||
|
||||
// thread_heap_alloc.hpp
|
||||
//
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread_heap_alloc.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread_heap_alloc.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
36
include/boost/thread/detail/thread_interruption.hpp
Normal file
36
include/boost/thread/detail/thread_interruption.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
|
||||
#define BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-9 Anthony Williams
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace this_thread
|
||||
{
|
||||
class BOOST_THREAD_DECL disable_interruption
|
||||
{
|
||||
bool interruption_was_enabled;
|
||||
friend class restore_interruption;
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(disable_interruption)
|
||||
disable_interruption() BOOST_NOEXCEPT;
|
||||
~disable_interruption() BOOST_NOEXCEPT;
|
||||
};
|
||||
|
||||
class BOOST_THREAD_DECL restore_interruption
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(restore_interruption)
|
||||
explicit restore_interruption(disable_interruption& d) BOOST_NOEXCEPT;
|
||||
~restore_interruption() BOOST_NOEXCEPT;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
65
include/boost/thread/detail/tss_hooks.hpp
Normal file
65
include/boost/thread/detail/tss_hooks.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_TLS_HOOKS_HPP)
|
||||
#define BOOST_TLS_HOOKS_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
BOOST_THREAD_DECL void __cdecl on_process_enter(void);
|
||||
//Function to be called when the exe or dll
|
||||
//that uses Boost.Threads first starts
|
||||
//or is first loaded.
|
||||
//Should be called only before the first call to
|
||||
//on_thread_enter().
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_process_exit(void);
|
||||
//Function to be called when the exe or dll
|
||||
//that uses Boost.Threads first starts
|
||||
//or is first loaded.
|
||||
//Should be called only after the last call to
|
||||
//on_exit_thread().
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_thread_enter(void);
|
||||
//Function to be called just after a thread starts
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
//that is starting.
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//May be omitted; may be called multiple times.
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
|
||||
//Function to be called just be fore a thread ends
|
||||
//in an exe or dll that uses Boost.Threads.
|
||||
//Must be called in the context of the thread
|
||||
//that is ending.
|
||||
//Called automatically by Boost.Threads when
|
||||
//a method for doing so has been discovered.
|
||||
//Must not be omitted; may be called multiple times.
|
||||
|
||||
void tss_cleanup_implemented();
|
||||
//Dummy function used both to detect whether tss cleanup
|
||||
//cleanup has been implemented and to force
|
||||
//it to be linked into the Boost.Threads library.
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS)
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif //!defined(BOOST_TLS_HOOKS_HPP)
|
||||
223
include/boost/thread/exceptions.hpp
Normal file
223
include/boost/thread/exceptions.hpp
Normal file
@@ -0,0 +1,223 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-9 Anthony Williams
|
||||
// (C) Copyright 2011-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)
|
||||
|
||||
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
// pdm: Sorry, but this class is used all over the place & I end up
|
||||
// with recursive headers if I don't separate it
|
||||
// wek: Not sure why recursive headers would cause compilation problems
|
||||
// given the include guards, but regardless it makes sense to
|
||||
// seperate this out any way.
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_interrupted
|
||||
{};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_exception:
|
||||
public system::system_error
|
||||
//public std::exception
|
||||
{
|
||||
typedef system::system_error base_type;
|
||||
public:
|
||||
thread_exception()
|
||||
: base_type(0,system::system_category())
|
||||
{}
|
||||
|
||||
thread_exception(int sys_error_code)
|
||||
: base_type(sys_error_code, system::system_category())
|
||||
{}
|
||||
|
||||
thread_exception( int ev, const char * what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
{
|
||||
}
|
||||
thread_exception( int ev, const std::string & what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
~thread_exception() throw()
|
||||
{}
|
||||
|
||||
|
||||
int native_error() const
|
||||
{
|
||||
return code().value();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE condition_error:
|
||||
public system::system_error
|
||||
//public std::exception
|
||||
{
|
||||
typedef system::system_error base_type;
|
||||
public:
|
||||
condition_error()
|
||||
: base_type(system::error_code(0, system::system_category()), "Condition error")
|
||||
{}
|
||||
condition_error( int ev )
|
||||
: base_type(system::error_code(ev, system::system_category()), "Condition error")
|
||||
{
|
||||
}
|
||||
condition_error( int ev, const char * what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
{
|
||||
}
|
||||
condition_error( int ev, const std::string & what_arg )
|
||||
: base_type(system::error_code(ev, system::system_category()), what_arg)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE lock_error:
|
||||
public thread_exception
|
||||
{
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
lock_error()
|
||||
: base_type(0, "boost::lock_error")
|
||||
{}
|
||||
|
||||
lock_error( int ev )
|
||||
: base_type(ev, "boost::lock_error")
|
||||
{
|
||||
}
|
||||
lock_error( int ev, const char * what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
lock_error( int ev, const std::string & what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
~lock_error() throw()
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_resource_error:
|
||||
public thread_exception
|
||||
{
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
thread_resource_error()
|
||||
: base_type(system::errc::resource_unavailable_try_again, "boost::thread_resource_error")
|
||||
{}
|
||||
|
||||
thread_resource_error( int ev )
|
||||
: base_type(ev, "boost::thread_resource_error")
|
||||
{
|
||||
}
|
||||
thread_resource_error( int ev, const char * what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
thread_resource_error( int ev, const std::string & what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
~thread_resource_error() throw()
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE unsupported_thread_option:
|
||||
public thread_exception
|
||||
{
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
unsupported_thread_option()
|
||||
: base_type(system::errc::invalid_argument, "boost::unsupported_thread_option")
|
||||
{}
|
||||
|
||||
unsupported_thread_option( int ev )
|
||||
: base_type(ev, "boost::unsupported_thread_option")
|
||||
{
|
||||
}
|
||||
unsupported_thread_option( int ev, const char * what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
unsupported_thread_option( int ev, const std::string & what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE invalid_thread_argument:
|
||||
public thread_exception
|
||||
{
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
invalid_thread_argument()
|
||||
: base_type(system::errc::invalid_argument, "boost::invalid_thread_argument")
|
||||
{}
|
||||
|
||||
invalid_thread_argument( int ev )
|
||||
: base_type(ev, "boost::invalid_thread_argument")
|
||||
{
|
||||
}
|
||||
invalid_thread_argument( int ev, const char * what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
invalid_thread_argument( int ev, const std::string & what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class BOOST_SYMBOL_VISIBLE thread_permission_error:
|
||||
public thread_exception
|
||||
{
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
thread_permission_error()
|
||||
: base_type(system::errc::permission_denied, "boost::thread_permission_error")
|
||||
{}
|
||||
|
||||
thread_permission_error( int ev )
|
||||
: base_type(ev, "boost::thread_permission_error")
|
||||
{
|
||||
}
|
||||
thread_permission_error( int ev, const char * what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
thread_permission_error( int ev, const std::string & what_arg )
|
||||
: base_type(ev, what_arg)
|
||||
{
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
1703
include/boost/thread/future.hpp
Normal file
1703
include/boost/thread/future.hpp
Normal file
File diff suppressed because it is too large
Load Diff
1827
include/boost/thread/locks.hpp
Normal file
1827
include/boost/thread/locks.hpp
Normal file
File diff suppressed because it is too large
Load Diff
21
include/boost/thread/mutex.hpp
Normal file
21
include/boost/thread/mutex.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_MUTEX_HPP
|
||||
|
||||
// mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
35
include/boost/thread/once.hpp
Normal file
35
include/boost/thread/once.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#ifndef BOOST_THREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/once.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/once.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
// template<class Callable, class ...Args> void
|
||||
// call_once(once_flag& flag, Callable&& func, Args&&... args);
|
||||
inline void call_once(void (*func)(),once_flag& flag)
|
||||
{
|
||||
call_once(flag,func);
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
335
include/boost/thread/pthread/condition_variable.hpp
Normal file
335
include/boost/thread/pthread/condition_variable.hpp
Normal file
@@ -0,0 +1,335 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-10 Anthony Williams
|
||||
// (C) Copyright 2011 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
}
|
||||
|
||||
namespace thread_cv_detail
|
||||
{
|
||||
template<typename MutexType>
|
||||
struct lock_on_exit
|
||||
{
|
||||
MutexType* m;
|
||||
|
||||
lock_on_exit():
|
||||
m(0)
|
||||
{}
|
||||
|
||||
void activate(MutexType& m_)
|
||||
{
|
||||
m_.unlock();
|
||||
m=&m_;
|
||||
}
|
||||
~lock_on_exit()
|
||||
{
|
||||
if(m)
|
||||
{
|
||||
m->lock();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
inline void condition_variable::wait(unique_lock<mutex>& m)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
do {
|
||||
res = pthread_cond_wait(&cond,&internal_mutex);
|
||||
} while (res == EINTR);
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error(res, "boost:: condition_variable constructor failed in pthread_cond_wait"));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool condition_variable::do_timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
struct timespec const &timeout)
|
||||
{
|
||||
if (!m.owns_lock())
|
||||
boost::throw_exception(condition_error(EPERM, "condition_variable do_timed_wait: mutex not locked"));
|
||||
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
int cond_res;
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(cond_res)
|
||||
{
|
||||
boost::throw_exception(condition_error(cond_res, "condition_variable failed in pthread_cond_timedwait"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_one() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
inline void condition_variable::notify_all() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
|
||||
class condition_variable_any
|
||||
{
|
||||
pthread_mutex_t internal_mutex;
|
||||
pthread_cond_t cond;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(condition_variable_any)
|
||||
condition_variable_any()
|
||||
{
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_mutex_init"));
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
boost::throw_exception(thread_resource_error(res, "condition_variable_any failed in pthread_cond_init"));
|
||||
}
|
||||
}
|
||||
~condition_variable_any()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<lock_type> guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_wait"));
|
||||
}
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
return do_timed_wait(m, timeout);
|
||||
}
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class lock_type,class Duration>
|
||||
cv_status
|
||||
wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
||||
wait_until(lock,
|
||||
nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
||||
return system_clock::now() < t ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status
|
||||
wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
|
||||
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class lock_type, class Clock, class Duration, class Predicate>
|
||||
bool
|
||||
wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<Clock, Duration>& t,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_until(lock, t) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class lock_type, class Rep, class Period>
|
||||
cv_status
|
||||
wait_for(
|
||||
lock_type& lock,
|
||||
const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
wait_until(lock, s_now + ceil<nanoseconds>(d));
|
||||
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <class lock_type, class Rep, class Period, class Predicate>
|
||||
bool
|
||||
wait_for(
|
||||
lock_type& lock,
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_for(lock, d) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class lock_type>
|
||||
inline void wait_until(
|
||||
lock_type& lk,
|
||||
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
do_timed_wait(lk, ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
void notify_one() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
void notify_all() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
private: // used by boost::thread::try_join_until
|
||||
|
||||
template <class lock_type>
|
||||
inline bool do_timed_wait(
|
||||
lock_type& m,
|
||||
struct timespec const &timeout)
|
||||
{
|
||||
int res=0;
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<lock_type> guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_timedwait"));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
236
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
236
include/boost/thread/pthread/condition_variable_fwd.hpp
Normal file
@@ -0,0 +1,236 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
|
||||
#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/thread/cv_status.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class condition_variable
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t internal_mutex;
|
||||
pthread_cond_t cond;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(condition_variable)
|
||||
condition_variable()
|
||||
{
|
||||
int const res=pthread_mutex_init(&internal_mutex,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: condition_variable constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost:: condition_variable constructor failed in pthread_cond_init"));
|
||||
}
|
||||
}
|
||||
~condition_variable()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
int ret;
|
||||
do {
|
||||
ret = pthread_cond_destroy(&cond);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& m);
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
inline bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until)
|
||||
{
|
||||
#if defined BOOST_THREAD_WAIT_BUG
|
||||
struct timespec const timeout=detail::get_timespec(wait_until + BOOST_THREAD_WAIT_BUG);
|
||||
return do_timed_wait(m, timeout);
|
||||
#else
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
return do_timed_wait(m, timeout);
|
||||
#endif
|
||||
}
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
xtime const& wait_until)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
}
|
||||
|
||||
template<typename duration_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
duration_type const& wait_duration)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration);
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
xtime const& wait_until,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
}
|
||||
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,get_system_time()+wait_duration,pred);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
template <class Duration>
|
||||
cv_status
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
||||
wait_until(lock,
|
||||
nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
||||
return system_clock::now() < t ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
cv_status
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
wait_until(lock, s_now + ceil<nanoseconds>(t - c_now));
|
||||
return Clock::now() < t ? cv_status::no_timeout : cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration, class Predicate>
|
||||
bool
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& t,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_until(lock, t) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class Rep, class Period>
|
||||
cv_status
|
||||
wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
wait_until(lock, s_now + ceil<nanoseconds>(d));
|
||||
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <class Rep, class Period, class Predicate>
|
||||
bool
|
||||
wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_for(lock, d) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_DEFINES_CONDITION_VARIABLE_NATIVE_HANDLE
|
||||
typedef pthread_cond_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &cond;
|
||||
}
|
||||
|
||||
void notify_one() BOOST_NOEXCEPT;
|
||||
void notify_all() BOOST_NOEXCEPT;
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
inline void wait_until(
|
||||
unique_lock<mutex>& lk,
|
||||
chrono::time_point<chrono::system_clock, chrono::nanoseconds> tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
do_timed_wait(lk, ts);
|
||||
}
|
||||
#endif
|
||||
//private: // used by boost::thread::try_join_until
|
||||
|
||||
inline bool do_timed_wait(
|
||||
unique_lock<mutex>& lock,
|
||||
struct timespec const &timeout);
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
291
include/boost/thread/pthread/mutex.hpp
Normal file
291
include/boost/thread/pthread/mutex.hpp
Normal file
@@ -0,0 +1,291 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-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 <pthread.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <errno.h>
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class mutex
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(mutex)
|
||||
|
||||
mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: mutex constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_destroy(&m);
|
||||
} while (ret == EINTR);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_lock(&m);
|
||||
} while (res == EINTR);
|
||||
if (res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock"));
|
||||
}
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_unlock(&m);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_trylock(&m);
|
||||
} while (res == EINTR);
|
||||
if(res && (res!=EBUSY))
|
||||
{
|
||||
// The following throw_exception has been replaced by an assertion and just return false,
|
||||
// as this is an internal error and the user can do nothing with the exception.
|
||||
//boost::throw_exception(lock_error(res,"boost: mutex try_lock failed in pthread_mutex_trylock"));
|
||||
BOOST_ASSERT_MSG(false ,"boost: mutex try_lock failed in pthread_mutex_trylock");
|
||||
return false;
|
||||
}
|
||||
|
||||
return !res;
|
||||
}
|
||||
|
||||
#define BOOST_THREAD_DEFINES_MUTEX_NATIVE_HANDLE
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
#endif
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(timed_mutex)
|
||||
timed_mutex()
|
||||
{
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: timed_mutex constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost:: timed_mutex constructor failed in pthread_cond_init"));
|
||||
}
|
||||
is_locked=false;
|
||||
#endif
|
||||
}
|
||||
~timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
bool timed_lock(boost::xtime const & absolute_time)
|
||||
{
|
||||
return timed_lock(system_time(absolute_time));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
bool do_try_lock_until(struct timespec const &timeout)
|
||||
{
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
return !res;
|
||||
}
|
||||
public:
|
||||
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
is_locked=false;
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool do_try_lock_until(struct timespec const &timeout)
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
#endif
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const ts=detail::get_timespec(abs_time);
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
||||
return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
||||
}
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_DEFINES_TIMED_MUTEX_NATIVE_HANDLE
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
113
include/boost/thread/pthread/once.hpp
Normal file
113
include/boost/thread/pthread/once.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
#define BOOST_THREAD_PTHREAD_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-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 <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
BOOST_THREAD_NO_COPYABLE(once_flag)
|
||||
BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
|
||||
: epoch(BOOST_ONCE_INITIAL_FLAG_VALUE)
|
||||
{}
|
||||
private:
|
||||
boost::uintmax_t epoch;
|
||||
template<typename Function>
|
||||
friend
|
||||
void call_once(once_flag& flag,Function f);
|
||||
};
|
||||
|
||||
#else // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
boost::uintmax_t epoch;
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
|
||||
#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
|
||||
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
|
||||
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
|
||||
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
|
||||
}
|
||||
|
||||
// Based on Mike Burrows fast_pthread_once algorithm as described in
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
|
||||
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
|
||||
boost::uintmax_t const epoch=flag.epoch;
|
||||
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
|
||||
|
||||
if(epoch<this_thread_epoch)
|
||||
{
|
||||
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
|
||||
|
||||
while(flag.epoch<=being_initialized)
|
||||
{
|
||||
if(flag.epoch==uninitialized_flag)
|
||||
{
|
||||
flag.epoch=being_initialized;
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
#endif
|
||||
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
|
||||
f();
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
}
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
flag.epoch=uninitialized_flag;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
flag.epoch=--detail::once_global_epoch;
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
|
||||
}
|
||||
else
|
||||
{
|
||||
while(flag.epoch==being_initialized)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
|
||||
}
|
||||
}
|
||||
}
|
||||
this_thread_epoch=detail::once_global_epoch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
64
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
64
include/boost/thread/pthread/pthread_mutex_scoped_lock.hpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace pthread
|
||||
{
|
||||
class pthread_mutex_scoped_lock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
bool locked;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
|
||||
m(m_),locked(true)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
locked=false;
|
||||
}
|
||||
|
||||
~pthread_mutex_scoped_lock()
|
||||
{
|
||||
if(locked)
|
||||
{
|
||||
unlock();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class pthread_mutex_scoped_unlock
|
||||
{
|
||||
pthread_mutex_t* m;
|
||||
public:
|
||||
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
|
||||
m(m_)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
~pthread_mutex_scoped_unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
392
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
392
include/boost/thread/pthread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,392 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-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 <pthread.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <errno.h>
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK)
|
||||
#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
unsigned count;
|
||||
#endif
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(recursive_mutex)
|
||||
recursive_mutex()
|
||||
{
|
||||
#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_init"));
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_mutex constructor failed in pthread_mutexattr_settype"));
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
#else
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: recursive_mutex constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost:: recursive_mutex constructor failed in pthread_cond_init"));
|
||||
}
|
||||
is_locked=false;
|
||||
count=0;
|
||||
#endif
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
#define BOOST_THREAD_DEFINES_RECURSIVE_MUTEX_NATIVE_HANDLE
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(!--count)
|
||||
{
|
||||
is_locked=false;
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && !pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex
|
||||
{
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
unsigned count;
|
||||
#endif
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex)
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(init_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_init"));
|
||||
}
|
||||
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
|
||||
if(set_attr_res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(set_attr_res, "boost:: recursive_timed_mutex constructor failed in pthread_mutexattr_settype"));
|
||||
}
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
#else
|
||||
int const res=pthread_mutex_init(&m,NULL);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(res, "boost:: recursive_timed_mutex constructor failed in pthread_mutex_init"));
|
||||
}
|
||||
int const res2=pthread_cond_init(&cond,NULL);
|
||||
if(res2)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
boost::throw_exception(thread_resource_error(res2, "boost:: recursive_timed_mutex constructor failed in pthread_cond_init"));
|
||||
}
|
||||
is_locked=false;
|
||||
count=0;
|
||||
#endif
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
BOOST_ASSERT(!res || res==EBUSY);
|
||||
return !res;
|
||||
}
|
||||
private:
|
||||
bool do_try_lock_until(struct timespec const &timeout)
|
||||
{
|
||||
int const res=pthread_mutex_timedlock(&m,&timeout);
|
||||
BOOST_ASSERT(!res || res==ETIMEDOUT);
|
||||
return !res;
|
||||
}
|
||||
|
||||
public:
|
||||
|
||||
#else
|
||||
void lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(!--count)
|
||||
{
|
||||
is_locked=false;
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && !pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool do_try_lock_until(struct timespec const &timeout)
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
if(is_locked && pthread_equal(owner,pthread_self()))
|
||||
{
|
||||
++count;
|
||||
return true;
|
||||
}
|
||||
while(is_locked)
|
||||
{
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
}
|
||||
is_locked=true;
|
||||
++count;
|
||||
owner=pthread_self();
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
|
||||
#endif
|
||||
|
||||
bool timed_lock(system_time const & abs_time)
|
||||
{
|
||||
struct timespec const ts=detail::get_timespec(abs_time);
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_lock_until(s_now + ceil<nanoseconds>(t - c_now));
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
|
||||
return try_lock_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
|
||||
}
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds d = tp.time_since_epoch();
|
||||
timespec ts;
|
||||
seconds s = duration_cast<seconds>(d);
|
||||
ts.tv_sec = static_cast<long>(s.count());
|
||||
ts.tv_nsec = static_cast<long>((d - s).count());
|
||||
return do_try_lock_until(ts);
|
||||
}
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_DEFINES_RECURSIVE_TIMED_MUTEX_NATIVE_HANDLE
|
||||
typedef pthread_mutex_t* native_handle_type;
|
||||
native_handle_type native_handle()
|
||||
{
|
||||
return &m;
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
551
include/boost/thread/pthread/shared_mutex.hpp
Normal file
551
include/boost/thread/pthread/shared_mutex.hpp
Normal file
@@ -0,0 +1,551 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-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/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count;
|
||||
bool exclusive;
|
||||
bool upgrade;
|
||||
bool exclusive_waiting_blocked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
state_data state;
|
||||
boost::mutex state_change;
|
||||
boost::condition_variable shared_cond;
|
||||
boost::condition_variable exclusive_cond;
|
||||
boost::condition_variable upgrade_cond;
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
exclusive_cond.notify_one();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(shared_mutex)
|
||||
|
||||
shared_mutex()
|
||||
{
|
||||
state_data state_={0,0,0,0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool timed_lock_shared(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(cv_status::timeout==shared_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
void unlock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(state.upgrade)
|
||||
{
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
upgrade_cond.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
release_waiters();
|
||||
}
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
exclusive_cond.wait(lk);
|
||||
}
|
||||
state.exclusive=true;
|
||||
}
|
||||
|
||||
bool timed_lock(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
if(!exclusive_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
while(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=true;
|
||||
if(cv_status::timeout == exclusive_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
shared_cond.wait(lk);
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
}
|
||||
|
||||
bool timed_lock_upgrade(system_time const& timeout)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(!shared_cond.timed_wait(lk,timeout))
|
||||
{
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_upgrade(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_upgrade(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_upgrade_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
if(cv_status::timeout == shared_cond.wait_until(lk,abs_time))
|
||||
{
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++state.shared_count;
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
} else {
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
// Upgrade <-> Exclusive
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
--state.shared_count;
|
||||
while(state.shared_count)
|
||||
{
|
||||
upgrade_cond.wait(lk);
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
state.upgrade=true;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& state.upgrade
|
||||
&& state.shared_count==1)
|
||||
{
|
||||
state.shared_count=0;
|
||||
state.exclusive=true;
|
||||
state.upgrade=false;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
try_unlock_upgrade_and_lock_for(
|
||||
const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_unlock_upgrade_and_lock_until(
|
||||
chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
try_unlock_upgrade_and_lock_until(
|
||||
const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if (state.shared_count != 1)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cv_status status = shared_cond.wait_until(lk,abs_time);
|
||||
if (state.shared_count == 1)
|
||||
break;
|
||||
if(status == cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
state.shared_count=0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Shared <-> Exclusive
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.exclusive=false;
|
||||
++state.shared_count;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& !state.upgrade
|
||||
&& state.shared_count==1)
|
||||
{
|
||||
state.shared_count=0;
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
try_unlock_shared_and_lock_for(
|
||||
const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_until(
|
||||
chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
try_unlock_shared_and_lock_until(
|
||||
const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if (state.shared_count != 1)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cv_status status = shared_cond.wait_until(lk,abs_time);
|
||||
if (state.shared_count == 1)
|
||||
break;
|
||||
if(status == cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.upgrade=false;
|
||||
state.exclusive=true;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
state.shared_count=0;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Shared <-> Upgrade
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
state.upgrade=false;
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( !state.exclusive
|
||||
&& !state.exclusive_waiting_blocked
|
||||
&& !state.upgrade
|
||||
)
|
||||
{
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool
|
||||
try_unlock_shared_and_lock_upgrade_for(
|
||||
const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_unlock_shared_and_lock_upgrade_until(
|
||||
chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool
|
||||
try_unlock_shared_and_lock_upgrade_until(
|
||||
const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::this_thread::disable_interruption do_not_disturb;
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
if( state.exclusive
|
||||
|| state.exclusive_waiting_blocked
|
||||
|| state.upgrade
|
||||
)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
cv_status status = exclusive_cond.wait_until(lk,abs_time);
|
||||
if( ! state.exclusive
|
||||
&& ! state.exclusive_waiting_blocked
|
||||
&& ! state.upgrade
|
||||
)
|
||||
break;
|
||||
if(status == cv_status::timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
state.upgrade=true;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef shared_mutex upgrade_mutex;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
208
include/boost/thread/pthread/thread_data.hpp
Normal file
208
include/boost/thread/pthread/thread_data.hpp
Normal file
@@ -0,0 +1,208 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
#include <map>
|
||||
#include <unistd.h>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread_attributes {
|
||||
public:
|
||||
thread_attributes() BOOST_NOEXCEPT {
|
||||
int res = pthread_attr_init(&val_);
|
||||
BOOST_VERIFY(!res && "pthread_attr_init failed");
|
||||
}
|
||||
~thread_attributes() {
|
||||
int res = pthread_attr_destroy(&val_);
|
||||
BOOST_VERIFY(!res && "pthread_attr_destroy failed");
|
||||
}
|
||||
// stack
|
||||
void set_stack_size(std::size_t size) BOOST_NOEXCEPT {
|
||||
if (size==0) return;
|
||||
std::size_t page_size = getpagesize();
|
||||
#ifdef PTHREAD_STACK_MIN
|
||||
if (size<PTHREAD_STACK_MIN) size=PTHREAD_STACK_MIN;
|
||||
#endif
|
||||
size = ((size+page_size-1)/page_size)*page_size;
|
||||
int res = pthread_attr_setstacksize(&val_, size);
|
||||
BOOST_VERIFY(!res && "pthread_attr_setstacksize failed");
|
||||
}
|
||||
|
||||
std::size_t get_stack_size() const BOOST_NOEXCEPT {
|
||||
std::size_t size;
|
||||
int res = pthread_attr_getstacksize(&val_, &size);
|
||||
BOOST_VERIFY(!res && "pthread_attr_getstacksize failed");
|
||||
return size;
|
||||
}
|
||||
#define BOOST_THREAD_DEFINES_THREAD_ATTRIBUTES_NATIVE_HANDLE
|
||||
|
||||
typedef pthread_attr_t native_handle_type;
|
||||
native_handle_type* native_handle() BOOST_NOEXCEPT {
|
||||
return &val_;
|
||||
}
|
||||
const native_handle_type* native_handle() const BOOST_NOEXCEPT {
|
||||
return &val_;
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_attr_t val_;
|
||||
};
|
||||
|
||||
class thread;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function;
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node
|
||||
{
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
|
||||
tss_data_node(boost::shared_ptr<boost::detail::tss_cleanup_function> func_,
|
||||
void* value_):
|
||||
func(func_),value(value_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct thread_data_base;
|
||||
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
|
||||
|
||||
struct BOOST_THREAD_DECL thread_data_base:
|
||||
enable_shared_from_this<thread_data_base>
|
||||
{
|
||||
thread_data_ptr self;
|
||||
pthread_t thread_handle;
|
||||
boost::mutex data_mutex;
|
||||
boost::condition_variable done_condition;
|
||||
boost::mutex sleep_mutex;
|
||||
boost::condition_variable sleep_condition;
|
||||
bool done;
|
||||
bool join_started;
|
||||
bool joined;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
std::map<void const*,boost::detail::tss_data_node> tss_data;
|
||||
bool interrupt_enabled;
|
||||
bool interrupt_requested;
|
||||
pthread_mutex_t* cond_mutex;
|
||||
pthread_cond_t* current_cond;
|
||||
|
||||
thread_data_base():
|
||||
done(false),join_started(false),joined(false),
|
||||
thread_exit_callbacks(0),
|
||||
interrupt_enabled(true),
|
||||
interrupt_requested(false),
|
||||
current_cond(0)
|
||||
{}
|
||||
virtual ~thread_data_base();
|
||||
|
||||
typedef pthread_t native_handle_type;
|
||||
|
||||
virtual void run()=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
|
||||
|
||||
class interruption_checker
|
||||
{
|
||||
thread_data_base* const thread_info;
|
||||
pthread_mutex_t* m;
|
||||
bool set;
|
||||
|
||||
void check_for_interruption()
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted(); // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator=(interruption_checker&);
|
||||
public:
|
||||
explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
|
||||
thread_info(detail::get_current_thread_data()),m(cond_mutex),
|
||||
set(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
if(set)
|
||||
{
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
check_for_interruption();
|
||||
thread_info->cond_mutex=cond_mutex;
|
||||
thread_info->current_cond=cond;
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(m));
|
||||
}
|
||||
}
|
||||
~interruption_checker()
|
||||
{
|
||||
if(set)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
lock_guard<mutex> guard(thread_info->data_mutex);
|
||||
thread_info->cond_mutex=NULL;
|
||||
thread_info->current_cond=NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(m));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns);
|
||||
#endif
|
||||
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
|
||||
|
||||
#ifdef __DECXXX
|
||||
/// Workaround of DECCXX issue of incorrect template substitution
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
template<>
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
#else
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
242
include/boost/thread/pthread/thread_heap_alloc.hpp
Normal file
242
include/boost/thread/pthread/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,242 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP
|
||||
#define THREAD_HEAP_ALLOC_PTHREAD_HPP
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
inline T* heap_new()
|
||||
{
|
||||
return new T();
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1));
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1&& a1,A2&& a2)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3));
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
|
||||
{
|
||||
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
|
||||
}
|
||||
#else
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new_impl(A1 a1)
|
||||
{
|
||||
return new T(a1);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2)
|
||||
{
|
||||
return new T(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
|
||||
{
|
||||
return new T(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
|
||||
{
|
||||
return new T(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1 const& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&>(a1);
|
||||
}
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1&>(a1);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&>(a1,a2);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
inline void heap_delete(T* data)
|
||||
{
|
||||
delete data;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct do_heap_delete
|
||||
{
|
||||
void operator()(T* data) const
|
||||
{
|
||||
detail::heap_delete(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
36
include/boost/thread/pthread/timespec.hpp
Normal file
36
include/boost/thread/pthread/timespec.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <pthread.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline struct timespec get_timespec(boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec timeout={0,0};
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
timeout.tv_sec=time_since_epoch.total_seconds();
|
||||
timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
|
||||
return timeout;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
21
include/boost/thread/recursive_mutex.hpp
Normal file
21
include/boost/thread/recursive_mutex.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/recursive_mutex.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/recursive_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
58
include/boost/thread/reverse_lock.hpp
Normal file
58
include/boost/thread/reverse_lock.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_REVERSE_LOCK_HPP
|
||||
#define BOOST_THREAD_REVERSE_LOCK_HPP
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<typename Lock>
|
||||
class reverse_lock
|
||||
{
|
||||
|
||||
public:
|
||||
typedef typename Lock::mutex_type mutex_type;
|
||||
BOOST_THREAD_NO_COPYABLE(reverse_lock)
|
||||
|
||||
explicit reverse_lock(Lock& m_)
|
||||
: m(m_), mtx(0)
|
||||
{
|
||||
if (m.owns_lock())
|
||||
{
|
||||
m.unlock();
|
||||
}
|
||||
mtx=m.release();
|
||||
}
|
||||
~reverse_lock()
|
||||
{
|
||||
if (mtx) {
|
||||
mtx->lock();
|
||||
m = BOOST_THREAD_MAKE_RV_REF(Lock(*mtx, adopt_lock));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Lock& m;
|
||||
mutex_type* mtx;
|
||||
};
|
||||
|
||||
|
||||
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
template<typename T>
|
||||
struct is_mutex_type<reverse_lock<T> >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // header
|
||||
52
include/boost/thread/shared_lock_guard.hpp
Normal file
52
include/boost/thread/shared_lock_guard.hpp
Normal file
@@ -0,0 +1,52 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_SHARED_LOCK_GUARD_HPP
|
||||
#define BOOST_THREAD_SHARED_LOCK_GUARD_HPP
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template<typename SharedMutex>
|
||||
class shared_lock_guard
|
||||
{
|
||||
private:
|
||||
SharedMutex& m;
|
||||
|
||||
public:
|
||||
typedef SharedMutex mutex_type;
|
||||
BOOST_THREAD_NO_COPYABLE(shared_lock_guard)
|
||||
explicit shared_lock_guard(SharedMutex& m_):
|
||||
m(m_)
|
||||
{
|
||||
m.lock_shared();
|
||||
}
|
||||
shared_lock_guard(SharedMutex& m_,adopt_lock_t):
|
||||
m(m_)
|
||||
{}
|
||||
~shared_lock_guard()
|
||||
{
|
||||
m.unlock_shared();
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
|
||||
template<typename T>
|
||||
struct is_mutex_type<shared_lock_guard<T> >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif // header
|
||||
26
include/boost/thread/shared_mutex.hpp
Normal file
26
include/boost/thread/shared_mutex.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_SHARED_MUTEX_HPP
|
||||
|
||||
// shared_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2011-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>
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#if defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
|
||||
#include <boost/thread/pthread/shared_mutex.hpp>
|
||||
#else
|
||||
#include <boost/thread/win32/shared_mutex.hpp>
|
||||
#endif
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/shared_mutex.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
28
include/boost/thread/thread.hpp
Normal file
28
include/boost/thread/thread.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#ifndef BOOST_THREAD_THREAD_HPP
|
||||
#define BOOST_THREAD_THREAD_HPP
|
||||
|
||||
// thread.hpp
|
||||
//
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/platform.hpp>
|
||||
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
#include <boost/thread/win32/thread_data.hpp>
|
||||
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#else
|
||||
#error "Boost threads unavailable on this platform"
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/thread.hpp>
|
||||
#include <boost/thread/detail/thread_interruption.hpp>
|
||||
#include <boost/thread/detail/thread_group.hpp>
|
||||
#include <boost/thread/v2/thread.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
55
include/boost/thread/thread_time.hpp
Normal file
55
include/boost/thread/thread_time.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
#ifndef BOOST_THREAD_TIME_HPP
|
||||
#define BOOST_THREAD_TIME_HPP
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/date_time/time_clock.hpp>
|
||||
#include <boost/date_time/microsec_time_clock.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
typedef boost::posix_time::ptime system_time;
|
||||
|
||||
inline system_time get_system_time()
|
||||
{
|
||||
#if defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
|
||||
return boost::date_time::microsec_clock<system_time>::universal_time();
|
||||
#else // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
|
||||
return boost::date_time::second_clock<system_time>::universal_time();
|
||||
#endif // defined(BOOST_DATE_TIME_HAS_HIGH_PRECISION_CLOCK)
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
inline system_time get_system_time_sentinel()
|
||||
{
|
||||
return system_time(boost::posix_time::pos_infin);
|
||||
}
|
||||
|
||||
inline unsigned long get_milliseconds_until(system_time const& target_time)
|
||||
{
|
||||
if(target_time.is_pos_infinity())
|
||||
{
|
||||
return ~(unsigned long)0;
|
||||
}
|
||||
system_time const now=get_system_time();
|
||||
if(target_time<=now)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return static_cast<unsigned long>((target_time-now).total_milliseconds()+1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
113
include/boost/thread/tss.hpp
Normal file
113
include/boost/thread/tss.hpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#ifndef BOOST_THREAD_TSS_HPP
|
||||
#define BOOST_THREAD_TSS_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/thread/detail/thread_heap_alloc.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function
|
||||
{
|
||||
virtual ~tss_cleanup_function()
|
||||
{}
|
||||
|
||||
virtual void operator()(void* data)=0;
|
||||
};
|
||||
|
||||
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
|
||||
BOOST_THREAD_DECL void* get_tss_data(void const* key);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class thread_specific_ptr
|
||||
{
|
||||
private:
|
||||
thread_specific_ptr(thread_specific_ptr&);
|
||||
thread_specific_ptr& operator=(thread_specific_ptr&);
|
||||
|
||||
struct delete_data:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void operator()(void* data)
|
||||
{
|
||||
delete static_cast<T*>(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct run_custom_cleanup_function:
|
||||
detail::tss_cleanup_function
|
||||
{
|
||||
void (*cleanup_function)(T*);
|
||||
|
||||
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
|
||||
cleanup_function(cleanup_function_)
|
||||
{}
|
||||
|
||||
void operator()(void* data)
|
||||
{
|
||||
cleanup_function(static_cast<T*>(data));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
|
||||
|
||||
public:
|
||||
typedef T element_type;
|
||||
|
||||
thread_specific_ptr():
|
||||
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
|
||||
{}
|
||||
explicit thread_specific_ptr(void (*func_)(T*))
|
||||
{
|
||||
if(func_)
|
||||
{
|
||||
cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
|
||||
}
|
||||
}
|
||||
~thread_specific_ptr()
|
||||
{
|
||||
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,true);
|
||||
}
|
||||
|
||||
T* get() const
|
||||
{
|
||||
return static_cast<T*>(detail::get_tss_data(this));
|
||||
}
|
||||
T* operator->() const
|
||||
{
|
||||
return get();
|
||||
}
|
||||
T& operator*() const
|
||||
{
|
||||
return *get();
|
||||
}
|
||||
T* release()
|
||||
{
|
||||
T* const temp=get();
|
||||
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
|
||||
return temp;
|
||||
}
|
||||
void reset(T* new_value=0)
|
||||
{
|
||||
T* const current_value=get();
|
||||
if(current_value!=new_value)
|
||||
{
|
||||
detail::set_tss_data(this,cleanup,new_value,true);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
56
include/boost/thread/v2/thread.hpp
Normal file
56
include/boost/thread/v2/thread.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2011 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_V2_THREAD_HPP
|
||||
#define BOOST_THREAD_V2_THREAD_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#endif
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace this_thread
|
||||
{
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
nanoseconds ns = duration_cast<nanoseconds> (d);
|
||||
if (ns < d) ++ns;
|
||||
sleep_for(ns);
|
||||
}
|
||||
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
mutex mut;
|
||||
condition_variable cv;
|
||||
unique_lock<mutex> lk(mut);
|
||||
while (Clock::now() < t)
|
||||
cv.wait_until(lk, t);
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
inline BOOST_SYMBOL_VISIBLE
|
||||
void sleep_until(const chrono::time_point<chrono::steady_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
sleep_for(t - steady_clock::now());
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
160
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
160
include/boost/thread/win32/basic_recursive_mutex.hpp
Normal file
@@ -0,0 +1,160 @@
|
||||
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// (C) Copyright 2011-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/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/basic_timed_mutex.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template<typename underlying_mutex_type>
|
||||
struct basic_recursive_mutex_impl
|
||||
{
|
||||
long recursion_count;
|
||||
long locking_thread_id;
|
||||
underlying_mutex_type mutex;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
recursion_count=0;
|
||||
locking_thread_id=0;
|
||||
mutex.initialize();
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
mutex.destroy();
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
if(!try_recursive_lock(current_thread_id))
|
||||
{
|
||||
mutex.lock();
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
}
|
||||
}
|
||||
bool timed_lock(::boost::system_time const& target)
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
|
||||
}
|
||||
template<typename Duration>
|
||||
bool timed_lock(Duration const& timeout)
|
||||
{
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_timed_lock_for(current_thread_id,rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
long const current_thread_id=win32::GetCurrentThreadId();
|
||||
return try_recursive_lock(current_thread_id) || try_timed_lock_until(current_thread_id,t);
|
||||
}
|
||||
#endif
|
||||
void unlock()
|
||||
{
|
||||
if(!--recursion_count)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
|
||||
mutex.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool try_recursive_lock(long current_thread_id)
|
||||
{
|
||||
if(::boost::detail::interlocked_read_acquire(&locking_thread_id)==current_thread_id)
|
||||
{
|
||||
++recursion_count;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_basic_lock(long current_thread_id)
|
||||
{
|
||||
if(mutex.try_lock())
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
|
||||
{
|
||||
if(mutex.timed_lock(target))
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename TP>
|
||||
bool try_timed_lock_until(long current_thread_id,TP const& target)
|
||||
{
|
||||
if(mutex.try_lock_until(target))
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
template <typename D>
|
||||
bool try_timed_lock_for(long current_thread_id,D const& target)
|
||||
{
|
||||
if(mutex.try_lock_for(target))
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
|
||||
recursion_count=1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex;
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
267
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
267
include/boost/thread/win32/basic_timed_mutex.hpp
Normal file
@@ -0,0 +1,267 @@
|
||||
#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
|
||||
|
||||
// basic_timed_mutex_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// (C) Copyright 2011-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/assert.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
struct basic_timed_mutex
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31);
|
||||
BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30);
|
||||
BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit);
|
||||
BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit);
|
||||
long active_count;
|
||||
void* event;
|
||||
|
||||
void initialize()
|
||||
{
|
||||
active_count=0;
|
||||
event=0;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4312)
|
||||
#endif
|
||||
void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if(old_event)
|
||||
{
|
||||
win32::CloseHandle(old_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
if(try_lock())
|
||||
{
|
||||
return;
|
||||
}
|
||||
long old_count=active_count;
|
||||
mark_waiting_and_try_lock(old_count);
|
||||
|
||||
if(old_count&lock_flag_value)
|
||||
{
|
||||
bool lock_acquired=false;
|
||||
void* const sem=get_event();
|
||||
|
||||
do
|
||||
{
|
||||
BOOST_VERIFY(win32::WaitForSingleObject(
|
||||
sem,::boost::detail::win32::infinite)==0);
|
||||
clear_waiting_and_try_lock(old_count);
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
}
|
||||
}
|
||||
void mark_waiting_and_try_lock(long& old_count)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
|
||||
if(current==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current;
|
||||
}
|
||||
}
|
||||
|
||||
void clear_waiting_and_try_lock(long& old_count)
|
||||
{
|
||||
old_count&=~lock_flag_value;
|
||||
old_count|=event_set_flag_value;
|
||||
for(;;)
|
||||
{
|
||||
long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
|
||||
if(current==old_count)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_count=current;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool timed_lock(::boost::system_time const& wait_until)
|
||||
{
|
||||
if(try_lock())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
long old_count=active_count;
|
||||
mark_waiting_and_try_lock(old_count);
|
||||
|
||||
if(old_count&lock_flag_value)
|
||||
{
|
||||
bool lock_acquired=false;
|
||||
void* const sem=get_event();
|
||||
|
||||
do
|
||||
{
|
||||
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
clear_waiting_and_try_lock(old_count);
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_lock(Duration const& timeout)
|
||||
{
|
||||
return timed_lock(get_system_time()+timeout);
|
||||
}
|
||||
|
||||
bool timed_lock(boost::xtime const& timeout)
|
||||
{
|
||||
return timed_lock(system_time(timeout));
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
|
||||
return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
|
||||
}
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
|
||||
{
|
||||
if(try_lock())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
long old_count=active_count;
|
||||
mark_waiting_and_try_lock(old_count);
|
||||
|
||||
if(old_count&lock_flag_value)
|
||||
{
|
||||
bool lock_acquired=false;
|
||||
void* const sem=get_event();
|
||||
|
||||
do
|
||||
{
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
|
||||
if(win32::WaitForSingleObject(sem,static_cast<unsigned long>(rel_time.count()))!=0)
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&active_count);
|
||||
return false;
|
||||
}
|
||||
clear_waiting_and_try_lock(old_count);
|
||||
lock_acquired=!(old_count&lock_flag_value);
|
||||
}
|
||||
while(!lock_acquired);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void unlock()
|
||||
{
|
||||
long const offset=lock_flag_value;
|
||||
long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
|
||||
if(!(old_count&event_set_flag_value) && (old_count>offset))
|
||||
{
|
||||
if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
|
||||
{
|
||||
win32::SetEvent(get_event());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void* get_event()
|
||||
{
|
||||
void* current_event=::boost::detail::interlocked_read_acquire(&event);
|
||||
|
||||
if(!current_event)
|
||||
{
|
||||
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4311)
|
||||
#pragma warning(disable:4312)
|
||||
#endif
|
||||
void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
if(old_event!=0)
|
||||
{
|
||||
win32::CloseHandle(new_event);
|
||||
return old_event;
|
||||
}
|
||||
else
|
||||
{
|
||||
return new_event;
|
||||
}
|
||||
}
|
||||
return current_event;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
517
include/boost/thread/win32/condition_variable.hpp
Normal file
517
include/boost/thread/win32/condition_variable.hpp
Normal file
@@ -0,0 +1,517 @@
|
||||
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <limits.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include <algorithm>
|
||||
#include <boost/thread/cv_status.hpp>
|
||||
#include <boost/thread/win32/thread_data.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <vector>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class basic_cv_list_entry;
|
||||
void intrusive_ptr_add_ref(basic_cv_list_entry * p);
|
||||
void intrusive_ptr_release(basic_cv_list_entry * p);
|
||||
|
||||
class basic_cv_list_entry
|
||||
{
|
||||
private:
|
||||
detail::win32::handle_manager semaphore;
|
||||
detail::win32::handle_manager wake_sem;
|
||||
long waiters;
|
||||
bool notified;
|
||||
long references;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(basic_cv_list_entry)
|
||||
explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
|
||||
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
|
||||
wake_sem(wake_sem_.duplicate()),
|
||||
waiters(1),notified(false),references(0)
|
||||
{}
|
||||
|
||||
static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
|
||||
{
|
||||
return !detail::interlocked_read_acquire(&entry->waiters);
|
||||
}
|
||||
|
||||
void add_waiter()
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&waiters);
|
||||
}
|
||||
|
||||
void remove_waiter()
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&waiters);
|
||||
}
|
||||
|
||||
void release(unsigned count_to_release)
|
||||
{
|
||||
notified=true;
|
||||
detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
|
||||
}
|
||||
|
||||
void release_waiters()
|
||||
{
|
||||
release(detail::interlocked_read_acquire(&waiters));
|
||||
}
|
||||
|
||||
bool is_notified() const
|
||||
{
|
||||
return notified;
|
||||
}
|
||||
|
||||
bool wait(timeout abs_time)
|
||||
{
|
||||
return this_thread::interruptible_wait(semaphore,abs_time);
|
||||
}
|
||||
|
||||
bool woken()
|
||||
{
|
||||
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0);
|
||||
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
|
||||
return woken_result==0;
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
|
||||
friend void intrusive_ptr_release(basic_cv_list_entry * p);
|
||||
};
|
||||
|
||||
inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->references);
|
||||
}
|
||||
|
||||
inline void intrusive_ptr_release(basic_cv_list_entry * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
|
||||
{
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
class basic_condition_variable
|
||||
{
|
||||
boost::mutex internal_mutex;
|
||||
long total_count;
|
||||
unsigned active_generation_count;
|
||||
|
||||
typedef basic_cv_list_entry list_entry;
|
||||
|
||||
typedef boost::intrusive_ptr<list_entry> entry_ptr;
|
||||
typedef std::vector<entry_ptr> generation_list;
|
||||
|
||||
generation_list generations;
|
||||
detail::win32::handle_manager wake_sem;
|
||||
|
||||
void wake_waiters(long count_to_wake)
|
||||
{
|
||||
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
|
||||
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
struct relocker
|
||||
{
|
||||
BOOST_THREAD_NO_COPYABLE(relocker)
|
||||
lock_type& lock;
|
||||
bool unlocked;
|
||||
|
||||
relocker(lock_type& lock_):
|
||||
lock(lock_),unlocked(false)
|
||||
{}
|
||||
void unlock()
|
||||
{
|
||||
lock.unlock();
|
||||
unlocked=true;
|
||||
}
|
||||
~relocker()
|
||||
{
|
||||
if(unlocked)
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
entry_ptr get_wait_entry()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
|
||||
if(!wake_sem)
|
||||
{
|
||||
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
BOOST_ASSERT(wake_sem);
|
||||
}
|
||||
|
||||
detail::interlocked_write_release(&total_count,total_count+1);
|
||||
if(generations.empty() || generations.back()->is_notified())
|
||||
{
|
||||
entry_ptr new_entry(new list_entry(wake_sem));
|
||||
generations.push_back(new_entry);
|
||||
return new_entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
generations.back()->add_waiter();
|
||||
return generations.back();
|
||||
}
|
||||
}
|
||||
|
||||
struct entry_manager
|
||||
{
|
||||
entry_ptr const entry;
|
||||
|
||||
BOOST_THREAD_NO_COPYABLE(entry_manager)
|
||||
entry_manager(entry_ptr const& entry_):
|
||||
entry(entry_)
|
||||
{}
|
||||
|
||||
~entry_manager()
|
||||
{
|
||||
entry->remove_waiter();
|
||||
}
|
||||
|
||||
list_entry* operator->()
|
||||
{
|
||||
return entry.get();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
protected:
|
||||
template<typename lock_type>
|
||||
bool do_wait(lock_type& lock,timeout abs_time)
|
||||
{
|
||||
relocker<lock_type> locker(lock);
|
||||
|
||||
entry_manager entry(get_wait_entry());
|
||||
|
||||
locker.unlock();
|
||||
|
||||
bool woken=false;
|
||||
while(!woken)
|
||||
{
|
||||
if(!entry->wait(abs_time))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
woken=entry->woken();
|
||||
}
|
||||
return woken;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool do_wait(lock_type& m,timeout const& abs_time,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!do_wait(m, abs_time))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
basic_condition_variable(const basic_condition_variable& other);
|
||||
basic_condition_variable& operator=(const basic_condition_variable& other);
|
||||
|
||||
public:
|
||||
basic_condition_variable():
|
||||
total_count(0),active_generation_count(0),wake_sem(0)
|
||||
{}
|
||||
|
||||
~basic_condition_variable()
|
||||
{}
|
||||
|
||||
void notify_one() BOOST_NOEXCEPT
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
if(!total_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
wake_waiters(1);
|
||||
|
||||
for(generation_list::iterator it=generations.begin(),
|
||||
end=generations.end();
|
||||
it!=end;++it)
|
||||
{
|
||||
(*it)->release(1);
|
||||
}
|
||||
generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
|
||||
}
|
||||
}
|
||||
|
||||
void notify_all() BOOST_NOEXCEPT
|
||||
{
|
||||
if(detail::interlocked_read_acquire(&total_count))
|
||||
{
|
||||
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
|
||||
if(!total_count)
|
||||
{
|
||||
return;
|
||||
}
|
||||
wake_waiters(total_count);
|
||||
for(generation_list::iterator it=generations.begin(),
|
||||
end=generations.end();
|
||||
it!=end;++it)
|
||||
{
|
||||
(*it)->release_waiters();
|
||||
}
|
||||
generations.clear();
|
||||
wake_sem=detail::win32::handle(0);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
class condition_variable:
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(condition_variable)
|
||||
condition_variable()
|
||||
{}
|
||||
|
||||
using detail::basic_condition_variable::notify_one;
|
||||
using detail::basic_condition_variable::notify_all;
|
||||
|
||||
void wait(unique_lock<mutex>& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
void wait(unique_lock<mutex>& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time)
|
||||
{
|
||||
return do_wait(m,abs_time);
|
||||
}
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time)
|
||||
{
|
||||
return do_wait(m,system_time(abs_time));
|
||||
}
|
||||
template<typename duration_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& abs_time,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,abs_time,pred);
|
||||
}
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& abs_time,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,system_time(abs_time),pred);
|
||||
}
|
||||
template<typename duration_type,typename predicate_type>
|
||||
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
template <class Clock, class Duration>
|
||||
cv_status
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
do_wait(lock, ceil<milliseconds>(t-Clock::now()).count());
|
||||
return Clock::now() < t ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class Rep, class Period>
|
||||
cv_status
|
||||
wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
do_wait(lock, ceil<milliseconds>(d).count());
|
||||
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class Clock, class Duration, class Predicate>
|
||||
bool
|
||||
wait_until(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::time_point<Clock, Duration>& t,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_until(lock, t) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <class Rep, class Period, class Predicate>
|
||||
bool
|
||||
wait_for(
|
||||
unique_lock<mutex>& lock,
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred)
|
||||
{
|
||||
return wait_until(lock, chrono::steady_clock::now() + d, pred);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
class condition_variable_any:
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(condition_variable_any)
|
||||
condition_variable_any()
|
||||
{}
|
||||
|
||||
using detail::basic_condition_variable::notify_one;
|
||||
using detail::basic_condition_variable::notify_all;
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
do_wait(m,detail::timeout::sentinel());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
void wait(lock_type& m,predicate_type pred)
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& abs_time)
|
||||
{
|
||||
return do_wait(m,abs_time);
|
||||
}
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::xtime const& abs_time)
|
||||
{
|
||||
return do_wait(m,system_time(abs_time));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds());
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& abs_time,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,abs_time,pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::xtime const& abs_time,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,system_time(abs_time),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
|
||||
{
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status
|
||||
wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
do_wait(lock, ceil<milliseconds>(t-Clock::now()).count());
|
||||
return Clock::now() < t ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class lock_type, class Rep, class Period>
|
||||
cv_status
|
||||
wait_for(
|
||||
lock_type& lock,
|
||||
const chrono::duration<Rep, Period>& d)
|
||||
{
|
||||
using namespace chrono;
|
||||
steady_clock::time_point c_now = steady_clock::now();
|
||||
do_wait(lock, ceil<milliseconds>(d).count());
|
||||
return steady_clock::now() - c_now < d ? cv_status::no_timeout :
|
||||
cv_status::timeout;
|
||||
}
|
||||
|
||||
template <class lock_type, class Clock, class Duration, class Predicate>
|
||||
bool
|
||||
wait_until(
|
||||
lock_type& lock,
|
||||
const chrono::time_point<Clock, Duration>& t,
|
||||
Predicate pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if (wait_until(lock, t) == cv_status::timeout)
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class lock_type, class Rep, class Period, class Predicate>
|
||||
bool
|
||||
wait_for(
|
||||
lock_type& lock,
|
||||
const chrono::duration<Rep, Period>& d,
|
||||
Predicate pred)
|
||||
{
|
||||
return wait_until(lock, chrono::steady_clock::now() + d, pred);
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
80
include/boost/thread/win32/interlocked_read.hpp
Normal file
80
include/boost/thread/win32/interlocked_read.hpp
Normal file
@@ -0,0 +1,80 @@
|
||||
#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
|
||||
|
||||
// interlocked_read_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2005-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
|
||||
extern "C" void _ReadWriteBarrier(void);
|
||||
#pragma intrinsic(_ReadWriteBarrier)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
long const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
void* const res=*x;
|
||||
_ReadWriteBarrier();
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
_ReadWriteBarrier();
|
||||
*x=value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline long interlocked_read_acquire(long volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
|
||||
}
|
||||
inline void* interlocked_read_acquire(void* volatile* x)
|
||||
{
|
||||
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
|
||||
}
|
||||
inline void interlocked_write_release(long volatile* x,long value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(x,value);
|
||||
}
|
||||
inline void interlocked_write_release(void* volatile* x,void* value)
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
65
include/boost/thread/win32/mutex.hpp
Normal file
65
include/boost/thread/win32/mutex.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#ifndef BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_MUTEX_HPP
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2011-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/win32/basic_timed_mutex.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
typedef ::boost::detail::basic_timed_mutex underlying_mutex;
|
||||
}
|
||||
|
||||
class mutex:
|
||||
public ::boost::detail::underlying_mutex
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(mutex)
|
||||
mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef mutex try_mutex;
|
||||
|
||||
class timed_mutex:
|
||||
public ::boost::detail::basic_timed_mutex
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(timed_mutex)
|
||||
timed_mutex()
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
~timed_mutex()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
230
include/boost/thread/win32/once.hpp
Normal file
230
include/boost/thread/win32/once.hpp
Normal file
@@ -0,0 +1,230 @@
|
||||
#ifndef BOOST_THREAD_WIN32_ONCE_HPP
|
||||
#define BOOST_THREAD_WIN32_ONCE_HPP
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2005 John Maddock
|
||||
// (C) Copyright 2011-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 <cstring>
|
||||
#include <cstddef>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifdef BOOST_NO_STDC_NAMESPACE
|
||||
namespace std
|
||||
{
|
||||
using ::memcpy;
|
||||
using ::ptrdiff_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
BOOST_THREAD_NO_COPYABLE(once_flag)
|
||||
BOOST_CONSTEXPR once_flag() BOOST_NOEXCEPT
|
||||
: status(0), count(0)
|
||||
{}
|
||||
private:
|
||||
long status;
|
||||
long count;
|
||||
template<typename Function>
|
||||
friend
|
||||
void call_once(once_flag& flag,Function f);
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT once_flag()
|
||||
#else // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
struct once_flag
|
||||
{
|
||||
long status;
|
||||
long count;
|
||||
};
|
||||
|
||||
#define BOOST_ONCE_INIT {0,0}
|
||||
#endif // BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
typedef wchar_t once_char_type;
|
||||
#else
|
||||
typedef char once_char_type;
|
||||
#endif
|
||||
unsigned const once_mutex_name_fixed_length=54;
|
||||
unsigned const once_mutex_name_length=once_mutex_name_fixed_length+
|
||||
sizeof(void*)*2+sizeof(unsigned long)*2+1;
|
||||
|
||||
template <class I>
|
||||
void int_to_string(I p, once_char_type* buf)
|
||||
{
|
||||
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
|
||||
{
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
once_char_type const a=L'A';
|
||||
#else
|
||||
once_char_type const a='A';
|
||||
#endif
|
||||
*buf = a + static_cast<once_char_type>((p >> (i*4)) & 0x0f);
|
||||
}
|
||||
*buf = 0;
|
||||
}
|
||||
|
||||
inline void name_once_mutex(once_char_type* mutex_name,void* flag_address)
|
||||
{
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
static const once_char_type fixed_mutex_name[]=L"Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#else
|
||||
static const once_char_type fixed_mutex_name[]="Local\\{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) ==
|
||||
(sizeof(once_char_type)*(once_mutex_name_fixed_length+1)));
|
||||
|
||||
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
|
||||
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address),
|
||||
mutex_name + once_mutex_name_fixed_length);
|
||||
detail::int_to_string(win32::GetCurrentProcessId(),
|
||||
mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
|
||||
}
|
||||
|
||||
inline void* open_once_event(once_char_type* mutex_name,void* flag_address)
|
||||
{
|
||||
if(!*mutex_name)
|
||||
{
|
||||
name_once_mutex(mutex_name,flag_address);
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
return ::boost::detail::win32::OpenEventW(
|
||||
#else
|
||||
return ::boost::detail::win32::OpenEventA(
|
||||
#endif
|
||||
::boost::detail::win32::synchronize |
|
||||
::boost::detail::win32::event_modify_state,
|
||||
false,
|
||||
mutex_name);
|
||||
}
|
||||
|
||||
inline void* create_once_event(once_char_type* mutex_name,void* flag_address)
|
||||
{
|
||||
if(!*mutex_name)
|
||||
{
|
||||
name_once_mutex(mutex_name,flag_address);
|
||||
}
|
||||
#ifdef BOOST_NO_ANSI_APIS
|
||||
return ::boost::detail::win32::CreateEventW(
|
||||
#else
|
||||
return ::boost::detail::win32::CreateEventA(
|
||||
#endif
|
||||
0,::boost::detail::win32::manual_reset_event,
|
||||
::boost::detail::win32::event_initially_reset,
|
||||
mutex_name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename Function>
|
||||
void call_once(once_flag& flag,Function f)
|
||||
{
|
||||
// Try for a quick win: if the procedure has already been called
|
||||
// just skip through:
|
||||
long const function_complete_flag_value=0xc15730e2;
|
||||
long const running_value=0x7f0725e3;
|
||||
long status;
|
||||
bool counted=false;
|
||||
detail::win32::handle_manager event_handle;
|
||||
detail::once_char_type mutex_name[detail::once_mutex_name_length];
|
||||
mutex_name[0]=0;
|
||||
|
||||
while((status=::boost::detail::interlocked_read_acquire(&flag.status))
|
||||
!=function_complete_flag_value)
|
||||
{
|
||||
status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0);
|
||||
if(!status)
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
if(!event_handle)
|
||||
{
|
||||
event_handle=detail::open_once_event(mutex_name,&flag);
|
||||
}
|
||||
if(event_handle)
|
||||
{
|
||||
::boost::detail::win32::ResetEvent(event_handle);
|
||||
}
|
||||
f();
|
||||
if(!counted)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&flag.count);
|
||||
counted=true;
|
||||
}
|
||||
BOOST_INTERLOCKED_EXCHANGE(&flag.status,function_complete_flag_value);
|
||||
if(!event_handle &&
|
||||
(::boost::detail::interlocked_read_acquire(&flag.count)>1))
|
||||
{
|
||||
event_handle=detail::create_once_event(mutex_name,&flag);
|
||||
}
|
||||
if(event_handle)
|
||||
{
|
||||
::boost::detail::win32::SetEvent(event_handle);
|
||||
}
|
||||
break;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
BOOST_INTERLOCKED_EXCHANGE(&flag.status,0);
|
||||
if(!event_handle)
|
||||
{
|
||||
event_handle=detail::open_once_event(mutex_name,&flag);
|
||||
}
|
||||
if(event_handle)
|
||||
{
|
||||
::boost::detail::win32::SetEvent(event_handle);
|
||||
}
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if(!counted)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&flag.count);
|
||||
counted=true;
|
||||
status=::boost::detail::interlocked_read_acquire(&flag.status);
|
||||
if(status==function_complete_flag_value)
|
||||
{
|
||||
break;
|
||||
}
|
||||
if(!event_handle)
|
||||
{
|
||||
event_handle=detail::create_once_event(mutex_name,&flag);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
|
||||
event_handle,::boost::detail::win32::infinite));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
63
include/boost/thread/win32/recursive_mutex.hpp
Normal file
63
include/boost/thread/win32/recursive_mutex.hpp
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
#define BOOST_RECURSIVE_MUTEX_WIN32_HPP
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/thread/win32/basic_recursive_mutex.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class recursive_mutex:
|
||||
public ::boost::detail::basic_recursive_mutex
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(recursive_mutex)
|
||||
recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::initialize();
|
||||
}
|
||||
~recursive_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_mutex> scoped_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
|
||||
};
|
||||
|
||||
typedef recursive_mutex recursive_try_mutex;
|
||||
|
||||
class recursive_timed_mutex:
|
||||
public ::boost::detail::basic_recursive_timed_mutex
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(recursive_timed_mutex)
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::initialize();
|
||||
}
|
||||
~recursive_timed_mutex()
|
||||
{
|
||||
::boost::detail::basic_recursive_timed_mutex::destroy();
|
||||
}
|
||||
|
||||
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
|
||||
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
|
||||
typedef scoped_timed_lock scoped_lock;
|
||||
};
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
865
include/boost/thread/win32/shared_mutex.hpp
Normal file
865
include/boost/thread/win32/shared_mutex.hpp
Normal file
@@ -0,0 +1,865 @@
|
||||
#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
|
||||
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// (C) Copyright 2011-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/assert.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <limits.h>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/ceil.hpp>
|
||||
#endif
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class shared_mutex
|
||||
{
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
unsigned shared_count:11,
|
||||
shared_waiting:11,
|
||||
exclusive:1,
|
||||
upgrade:1,
|
||||
exclusive_waiting:7,
|
||||
exclusive_waiting_blocked:1;
|
||||
|
||||
friend bool operator==(state_data const& lhs,state_data const& rhs)
|
||||
{
|
||||
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
T interlocked_compare_exchange(T* target,T new_value,T comparand)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
|
||||
long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
|
||||
*reinterpret_cast<long*>(&new_value),
|
||||
*reinterpret_cast<long*>(&comparand));
|
||||
return *reinterpret_cast<T const*>(&res);
|
||||
}
|
||||
|
||||
enum
|
||||
{
|
||||
unlock_sem = 0,
|
||||
exclusive_sem = 1
|
||||
};
|
||||
|
||||
state_data state;
|
||||
detail::win32::handle semaphores[2];
|
||||
detail::win32::handle upgrade_sem;
|
||||
|
||||
void release_waiters(state_data old_state)
|
||||
{
|
||||
if(old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
|
||||
}
|
||||
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(shared_mutex)
|
||||
shared_mutex()
|
||||
{
|
||||
semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
|
||||
if (!semaphores[exclusive_sem])
|
||||
{
|
||||
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
|
||||
if (!upgrade_sem)
|
||||
{
|
||||
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
|
||||
detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
|
||||
~shared_mutex()
|
||||
{
|
||||
detail::win32::CloseHandle(upgrade_sem);
|
||||
detail::win32::CloseHandle(semaphores[unlock_sem]);
|
||||
detail::win32::CloseHandle(semaphores[exclusive_sem]);
|
||||
}
|
||||
|
||||
bool try_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
|
||||
}
|
||||
|
||||
void lock_shared()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock_shared(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock_shared(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool timed_lock_shared(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
if(!new_state.shared_waiting)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(new_state.shared_waiting)
|
||||
{
|
||||
--new_state.shared_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_shared_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_lock_shared_until(s_now + ceil<system_clock::duration>(t - c_now));
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
|
||||
return try_lock_shared_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
|
||||
}
|
||||
bool try_lock_shared_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
if(!new_state.shared_waiting)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
chrono::system_clock::time_point n = chrono::system_clock::now();
|
||||
unsigned long res;
|
||||
if (tp>n) {
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
|
||||
res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],
|
||||
static_cast<unsigned long>(rel_time.count()));
|
||||
} else {
|
||||
res=detail::win32::timeout;
|
||||
}
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
|
||||
{
|
||||
if(new_state.shared_waiting)
|
||||
{
|
||||
--new_state.shared_waiting;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void unlock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.upgrade)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
if(old_state.upgrade)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
|
||||
}
|
||||
else
|
||||
{
|
||||
release_waiters(old_state);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
}
|
||||
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
bool timed_lock(TimeDuration const & relative_time)
|
||||
{
|
||||
return timed_lock(get_system_time()+relative_time);
|
||||
}
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool timed_lock(boost::system_time const& wait_until)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
++new_state.exclusive_waiting;
|
||||
if(!new_state.exclusive_waiting)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
|
||||
new_state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#ifndef UNDER_CE
|
||||
const bool wait_all = true;
|
||||
#else
|
||||
const bool wait_all = false;
|
||||
#endif
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
if(!--new_state.exclusive_waiting)
|
||||
{
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(wait_res<2);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
template <class Rep, class Period>
|
||||
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_lock_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
template <class Clock, class Duration>
|
||||
bool try_lock_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
system_clock::time_point s_now = system_clock::now();
|
||||
typename Clock::time_point c_now = Clock::now();
|
||||
return try_lock_until(s_now + ceil<system_clock::duration>(t - c_now));
|
||||
}
|
||||
template <class Duration>
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, Duration>& t)
|
||||
{
|
||||
using namespace chrono;
|
||||
typedef time_point<chrono::system_clock, chrono::system_clock::duration> sys_tmpt;
|
||||
return try_lock_until(sys_tmpt(chrono::ceil<chrono::system_clock::duration>(t.time_since_epoch())));
|
||||
}
|
||||
bool try_lock_until(const chrono::time_point<chrono::system_clock, chrono::system_clock::duration>& tp)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
++new_state.exclusive_waiting;
|
||||
if(!new_state.exclusive_waiting)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
|
||||
new_state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#ifndef UNDER_CE
|
||||
const bool wait_all = true;
|
||||
#else
|
||||
const bool wait_all = false;
|
||||
#endif
|
||||
|
||||
chrono::system_clock::time_point n = chrono::system_clock::now();
|
||||
unsigned long wait_res;
|
||||
if (tp>n) {
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,
|
||||
static_cast<unsigned long>(rel_time.count()));
|
||||
} else {
|
||||
wait_res=detail::win32::timeout;
|
||||
}
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.shared_count || new_state.exclusive)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
if(!--new_state.exclusive_waiting)
|
||||
{
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
if(!old_state.shared_count && !old_state.exclusive)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(wait_res<2);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void unlock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
void lock_upgrade()
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
++new_state.shared_waiting;
|
||||
if(!new_state.shared_waiting)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
|
||||
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
|
||||
}
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
++new_state.shared_count;
|
||||
if(!new_state.shared_count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(last_reader)
|
||||
{
|
||||
release_waiters(old_state);
|
||||
} else {
|
||||
release_waiters(old_state);
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
new_state.upgrade=false;
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
if(!last_reader)
|
||||
{
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
|
||||
}
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
new_state.upgrade=true;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
// bool try_unlock_upgrade_and_lock()
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//#ifdef BOOST_THREAD_USES_CHRONO
|
||||
// template <class Rep, class Period>
|
||||
// bool
|
||||
// try_unlock_upgrade_and_lock_for(
|
||||
// const chrono::duration<Rep, Period>& rel_time)
|
||||
// {
|
||||
// return try_unlock_upgrade_and_lock_until(
|
||||
// chrono::steady_clock::now() + rel_time);
|
||||
// }
|
||||
// template <class Clock, class Duration>
|
||||
// bool
|
||||
// try_unlock_upgrade_and_lock_until(
|
||||
// const chrono::time_point<Clock, Duration>& abs_time)
|
||||
// {
|
||||
// return false;
|
||||
// }
|
||||
//#endif
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.exclusive=false;
|
||||
++new_state.shared_count;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
for(;;)
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
new_state.upgrade=false;
|
||||
if(new_state.exclusive_waiting)
|
||||
{
|
||||
--new_state.exclusive_waiting;
|
||||
new_state.exclusive_waiting_blocked=false;
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old_state=current_state;
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
};
|
||||
typedef shared_mutex upgrade_mutex;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
230
include/boost/thread/win32/thread_data.hpp
Normal file
230
include/boost/thread/win32/thread_data.hpp
Normal file
@@ -0,0 +1,230 @@
|
||||
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2008 Anthony Williams
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/thread_heap_alloc.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
class thread_attributes {
|
||||
public:
|
||||
thread_attributes() BOOST_NOEXCEPT {
|
||||
val_.stack_size = 0;
|
||||
//val_.lpThreadAttributes=0;
|
||||
}
|
||||
~thread_attributes() {
|
||||
}
|
||||
// stack size
|
||||
void set_stack_size(std::size_t size) BOOST_NOEXCEPT {
|
||||
val_.stack_size = size;
|
||||
}
|
||||
|
||||
std::size_t get_stack_size() const BOOST_NOEXCEPT {
|
||||
return val_.stack_size;
|
||||
}
|
||||
|
||||
//void set_security(LPSECURITY_ATTRIBUTES lpThreadAttributes)
|
||||
//{
|
||||
// val_.lpThreadAttributes=lpThreadAttributes;
|
||||
//}
|
||||
//LPSECURITY_ATTRIBUTES get_security()
|
||||
//{
|
||||
// return val_.lpThreadAttributes;
|
||||
//}
|
||||
|
||||
struct win_attrs {
|
||||
std::size_t stack_size;
|
||||
//LPSECURITY_ATTRIBUTES lpThreadAttributes;
|
||||
};
|
||||
typedef win_attrs native_handle_type;
|
||||
native_handle_type* native_handle() {return &val_;}
|
||||
const native_handle_type* native_handle() const {return &val_;}
|
||||
|
||||
private:
|
||||
win_attrs val_;
|
||||
};
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node;
|
||||
|
||||
struct thread_data_base;
|
||||
void intrusive_ptr_add_ref(thread_data_base * p);
|
||||
void intrusive_ptr_release(thread_data_base * p);
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE thread_data_base
|
||||
{
|
||||
long count;
|
||||
detail::win32::handle_manager thread_handle;
|
||||
detail::win32::handle_manager interruption_handle;
|
||||
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
|
||||
boost::detail::tss_data_node* tss_data;
|
||||
bool interruption_enabled;
|
||||
unsigned id;
|
||||
|
||||
thread_data_base():
|
||||
count(0),thread_handle(detail::win32::invalid_handle_value),
|
||||
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
|
||||
thread_exit_callbacks(0),tss_data(0),
|
||||
interruption_enabled(true),
|
||||
id(0)
|
||||
{}
|
||||
virtual ~thread_data_base()
|
||||
{}
|
||||
|
||||
friend void intrusive_ptr_add_ref(thread_data_base * p)
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->count);
|
||||
}
|
||||
|
||||
friend void intrusive_ptr_release(thread_data_base * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
|
||||
{
|
||||
detail::heap_delete(p);
|
||||
}
|
||||
}
|
||||
|
||||
void interrupt()
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
|
||||
}
|
||||
|
||||
typedef detail::win32::handle native_handle_type;
|
||||
|
||||
virtual void run()=0;
|
||||
};
|
||||
|
||||
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE timeout
|
||||
{
|
||||
unsigned long start;
|
||||
uintmax_t milliseconds;
|
||||
bool relative;
|
||||
boost::system_time abs_time;
|
||||
|
||||
static unsigned long const max_non_infinite_wait=0xfffffffe;
|
||||
|
||||
timeout(uintmax_t milliseconds_):
|
||||
start(win32::GetTickCount()),
|
||||
milliseconds(milliseconds_),
|
||||
relative(true),
|
||||
abs_time(boost::get_system_time())
|
||||
{}
|
||||
|
||||
timeout(boost::system_time const& abs_time_):
|
||||
start(win32::GetTickCount()),
|
||||
milliseconds(0),
|
||||
relative(false),
|
||||
abs_time(abs_time_)
|
||||
{}
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE remaining_time
|
||||
{
|
||||
bool more;
|
||||
unsigned long milliseconds;
|
||||
|
||||
remaining_time(uintmax_t remaining):
|
||||
more(remaining>max_non_infinite_wait),
|
||||
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
|
||||
{}
|
||||
};
|
||||
|
||||
remaining_time remaining_milliseconds() const
|
||||
{
|
||||
if(is_sentinel())
|
||||
{
|
||||
return remaining_time(win32::infinite);
|
||||
}
|
||||
else if(relative)
|
||||
{
|
||||
unsigned long const now=win32::GetTickCount();
|
||||
unsigned long const elapsed=now-start;
|
||||
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
|
||||
}
|
||||
else
|
||||
{
|
||||
system_time const now=get_system_time();
|
||||
if(abs_time<=now)
|
||||
{
|
||||
return remaining_time(0);
|
||||
}
|
||||
return remaining_time((abs_time-now).total_milliseconds()+1);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_sentinel() const
|
||||
{
|
||||
return milliseconds==~uintmax_t(0);
|
||||
}
|
||||
|
||||
|
||||
static timeout sentinel()
|
||||
{
|
||||
return timeout(sentinel_type());
|
||||
}
|
||||
private:
|
||||
struct sentinel_type
|
||||
{};
|
||||
|
||||
explicit timeout(sentinel_type):
|
||||
start(0),milliseconds(~uintmax_t(0)),relative(true)
|
||||
{}
|
||||
};
|
||||
|
||||
inline uintmax_t pin_to_zero(intmax_t value)
|
||||
{
|
||||
return (value<0)?0u:(uintmax_t)value;
|
||||
}
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
|
||||
|
||||
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
|
||||
inline void interruptible_wait(uintmax_t milliseconds)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
|
||||
}
|
||||
inline BOOST_SYMBOL_VISIBLE void interruptible_wait(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
|
||||
}
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
|
||||
}
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(abs_time);
|
||||
}
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
|
||||
{
|
||||
interruptible_wait(chrono::duration_cast<chrono::milliseconds>(ns).count());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
434
include/boost/thread/win32/thread_heap_alloc.hpp
Normal file
434
include/boost/thread/win32/thread_heap_alloc.hpp
Normal file
@@ -0,0 +1,434 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
#ifndef THREAD_HEAP_ALLOC_HPP
|
||||
#define THREAD_HEAP_ALLOC_HPP
|
||||
#include <new>
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <stdexcept>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
using ::GetProcessHeap;
|
||||
using ::HeapAlloc;
|
||||
using ::HeapFree;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
# ifdef HeapAlloc
|
||||
# undef HeapAlloc
|
||||
# endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
__declspec(dllimport) handle __stdcall GetProcessHeap();
|
||||
__declspec(dllimport) void* __stdcall HeapAlloc(handle,unsigned long,ulong_ptr);
|
||||
__declspec(dllimport) int __stdcall HeapFree(handle,unsigned long,void*);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline void* allocate_raw_heap_memory(unsigned size)
|
||||
{
|
||||
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
|
||||
if(!heap_memory)
|
||||
{
|
||||
boost::throw_exception(std::bad_alloc());
|
||||
}
|
||||
return heap_memory;
|
||||
}
|
||||
|
||||
inline void free_raw_heap_memory(void* heap_memory)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T* heap_new()
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T();
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1&& a1)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1));
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1&& a1,A2&& a2)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3));
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
|
||||
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new_impl(A1 a1)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1);
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2);
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2,a3);
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
|
||||
{
|
||||
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
T* const data=new (heap_memory) T(a1,a2,a3,a4);
|
||||
return data;
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
free_raw_heap_memory(heap_memory);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1 const& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&>(a1);
|
||||
}
|
||||
template<typename T,typename A1>
|
||||
inline T* heap_new(A1& a1)
|
||||
{
|
||||
return heap_new_impl<T,A1&>(a1);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2 const& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
|
||||
}
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1& a1,A2& a2)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&>(a1,a2);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
template<typename T,typename A1,typename A2,typename A3,typename A4>
|
||||
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
inline void heap_delete(T* data)
|
||||
{
|
||||
data->~T();
|
||||
free_raw_heap_memory(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct do_heap_delete
|
||||
{
|
||||
void operator()(T* data) const
|
||||
{
|
||||
detail::heap_delete(data);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
#endif
|
||||
436
include/boost/thread/win32/thread_primitives.hpp
Normal file
436
include/boost/thread/win32/thread_primitives.hpp
Normal file
@@ -0,0 +1,436 @@
|
||||
#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
|
||||
|
||||
// win32_thread_primitives.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined( BOOST_USE_WINDOWS_H )
|
||||
# include <windows.h>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
typedef ULONG_PTR ulong_ptr;
|
||||
typedef HANDLE handle;
|
||||
unsigned const infinite=INFINITE;
|
||||
unsigned const timeout=WAIT_TIMEOUT;
|
||||
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
|
||||
unsigned const event_modify_state=EVENT_MODIFY_STATE;
|
||||
unsigned const synchronize=SYNCHRONIZE;
|
||||
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
using ::CreateMutexW;
|
||||
using ::CreateEventW;
|
||||
using ::OpenEventW;
|
||||
using ::CreateSemaphoreW;
|
||||
# else
|
||||
using ::CreateMutexA;
|
||||
using ::CreateEventA;
|
||||
using ::OpenEventA;
|
||||
using ::CreateSemaphoreA;
|
||||
# endif
|
||||
using ::CloseHandle;
|
||||
using ::ReleaseMutex;
|
||||
using ::ReleaseSemaphore;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
using ::WaitForMultipleObjects;
|
||||
using ::WaitForSingleObject;
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::DuplicateHandle;
|
||||
using ::SleepEx;
|
||||
using ::Sleep;
|
||||
using ::QueueUserAPC;
|
||||
using ::GetTickCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
|
||||
|
||||
# ifdef UNDER_CE
|
||||
# ifndef WINAPI
|
||||
# ifndef _WIN32_WCE_EMULATION
|
||||
# define WINAPI __cdecl // Note this doesn't match the desktop definition
|
||||
# else
|
||||
# define WINAPI __stdcall
|
||||
# endif
|
||||
# endif
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
# endif
|
||||
typedef int BOOL;
|
||||
typedef unsigned long DWORD;
|
||||
typedef void* HANDLE;
|
||||
|
||||
# include <kfuncs.h>
|
||||
# ifdef __cplusplus
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
typedef unsigned long ulong_ptr;
|
||||
# endif
|
||||
typedef void* handle;
|
||||
unsigned const infinite=~0U;
|
||||
unsigned const timeout=258U;
|
||||
handle const invalid_handle_value=(handle)(-1);
|
||||
unsigned const event_modify_state=2;
|
||||
unsigned const synchronize=0x100000u;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
struct _SECURITY_ATTRIBUTES;
|
||||
# ifdef BOOST_NO_ANSI_APIS
|
||||
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
|
||||
__declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
|
||||
# else
|
||||
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
|
||||
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
|
||||
__declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*);
|
||||
# endif
|
||||
__declspec(dllimport) int __stdcall CloseHandle(void*);
|
||||
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
|
||||
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
|
||||
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
|
||||
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
|
||||
__declspec(dllimport) void __stdcall Sleep(unsigned long);
|
||||
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
|
||||
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
|
||||
|
||||
__declspec(dllimport) unsigned long __stdcall GetTickCount();
|
||||
|
||||
# ifndef UNDER_CE
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
|
||||
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentThread();
|
||||
__declspec(dllimport) void* __stdcall GetCurrentProcess();
|
||||
__declspec(dllimport) int __stdcall SetEvent(void*);
|
||||
__declspec(dllimport) int __stdcall ResetEvent(void*);
|
||||
# else
|
||||
using ::GetCurrentProcessId;
|
||||
using ::GetCurrentThreadId;
|
||||
using ::GetCurrentThread;
|
||||
using ::GetCurrentProcess;
|
||||
using ::SetEvent;
|
||||
using ::ResetEvent;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
# error "Win32 functions not available"
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
enum event_type
|
||||
{
|
||||
auto_reset_event=false,
|
||||
manual_reset_event=true
|
||||
};
|
||||
|
||||
enum initial_event_state
|
||||
{
|
||||
event_initially_reset=false,
|
||||
event_initially_set=true
|
||||
};
|
||||
|
||||
inline handle create_anonymous_event(event_type type,initial_event_state state)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=win32::CreateEventA(0,type,state,0);
|
||||
#else
|
||||
handle const res=win32::CreateEventW(0,type,state,0);
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
|
||||
#else
|
||||
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
|
||||
#else
|
||||
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle duplicate_handle(handle source)
|
||||
{
|
||||
handle const current_process=GetCurrentProcess();
|
||||
long const same_access_flag=2;
|
||||
handle new_handle=0;
|
||||
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
|
||||
if(!success)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
return new_handle;
|
||||
}
|
||||
|
||||
inline void release_semaphore(handle semaphore,long count)
|
||||
{
|
||||
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
|
||||
}
|
||||
|
||||
class handle_manager
|
||||
{
|
||||
private:
|
||||
handle handle_to_manage;
|
||||
handle_manager(handle_manager&);
|
||||
handle_manager& operator=(handle_manager&);
|
||||
|
||||
void cleanup()
|
||||
{
|
||||
if(handle_to_manage && handle_to_manage!=invalid_handle_value)
|
||||
{
|
||||
BOOST_VERIFY(CloseHandle(handle_to_manage));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
explicit handle_manager(handle handle_to_manage_):
|
||||
handle_to_manage(handle_to_manage_)
|
||||
{}
|
||||
handle_manager():
|
||||
handle_to_manage(0)
|
||||
{}
|
||||
|
||||
handle_manager& operator=(handle new_handle)
|
||||
{
|
||||
cleanup();
|
||||
handle_to_manage=new_handle;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator handle() const
|
||||
{
|
||||
return handle_to_manage;
|
||||
}
|
||||
|
||||
handle duplicate() const
|
||||
{
|
||||
return duplicate_handle(handle_to_manage);
|
||||
}
|
||||
|
||||
void swap(handle_manager& other)
|
||||
{
|
||||
std::swap(handle_to_manage,other.handle_to_manage);
|
||||
}
|
||||
|
||||
handle release()
|
||||
{
|
||||
handle const res=handle_to_manage;
|
||||
handle_to_manage=0;
|
||||
return res;
|
||||
}
|
||||
|
||||
bool operator!() const
|
||||
{
|
||||
return !handle_to_manage;
|
||||
}
|
||||
|
||||
~handle_manager()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
#if _MSC_VER==1400
|
||||
extern "C" unsigned char _interlockedbittestandset(long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
|
||||
#else
|
||||
extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
|
||||
extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
|
||||
#endif
|
||||
|
||||
#pragma intrinsic(_interlockedbittestandset)
|
||||
#pragma intrinsic(_interlockedbittestandreset)
|
||||
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
return _interlockedbittestandset(x,bit)!=0;
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
{
|
||||
return _interlockedbittestandreset(x,bit)!=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#define BOOST_THREAD_BTS_DEFINED
|
||||
#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
#if 0
|
||||
__asm {
|
||||
mov eax,bit;
|
||||
mov edx,x;
|
||||
lock bts [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
#else
|
||||
bool ret;
|
||||
__asm {
|
||||
mov eax,bit; mov edx,x; lock bts [edx],eax; setc al; mov ret, al
|
||||
};
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
{
|
||||
#if 0
|
||||
__asm {
|
||||
mov eax,bit;
|
||||
mov edx,x;
|
||||
lock btr [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
#else
|
||||
|
||||
|
||||
bool ret;
|
||||
__asm {
|
||||
mov eax,bit; mov edx,x; lock btr [edx],eax; setc al; mov ret, al
|
||||
};
|
||||
return ret;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
#define BOOST_THREAD_BTS_DEFINED
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_THREAD_BTS_DEFINED
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
inline bool interlocked_bit_test_and_set(long* x,long bit)
|
||||
{
|
||||
long const value=1<<bit;
|
||||
long old=*x;
|
||||
do
|
||||
{
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old);
|
||||
if(current==old)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old=current;
|
||||
}
|
||||
while(true);
|
||||
return (old&value)!=0;
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
{
|
||||
long const value=1<<bit;
|
||||
long old=*x;
|
||||
do
|
||||
{
|
||||
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old);
|
||||
if(current==old)
|
||||
{
|
||||
break;
|
||||
}
|
||||
old=current;
|
||||
}
|
||||
while(true);
|
||||
return (old&value)!=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
92
include/boost/thread/xtime.hpp
Normal file
92
include/boost/thread/xtime.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_XTIME_WEK070601_HPP
|
||||
#define BOOST_XTIME_WEK070601_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
enum xtime_clock_types
|
||||
{
|
||||
TIME_UTC_=1
|
||||
// TIME_TAI,
|
||||
// TIME_MONOTONIC,
|
||||
// TIME_PROCESS,
|
||||
// TIME_THREAD,
|
||||
// TIME_LOCAL,
|
||||
// TIME_SYNC,
|
||||
// TIME_RESOLUTION
|
||||
};
|
||||
|
||||
struct xtime
|
||||
{
|
||||
#if defined(BOOST_NO_INT64_T)
|
||||
typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX
|
||||
#else
|
||||
typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX
|
||||
#endif
|
||||
|
||||
typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND
|
||||
|
||||
xtime_sec_t sec;
|
||||
xtime_nsec_t nsec;
|
||||
|
||||
operator system_time() const
|
||||
{
|
||||
return boost::posix_time::from_time_t(0)+
|
||||
boost::posix_time::seconds(static_cast<long>(sec))+
|
||||
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
|
||||
boost::posix_time::nanoseconds(nsec);
|
||||
#else
|
||||
boost::posix_time::microseconds((nsec+500)/1000);
|
||||
#endif
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
inline xtime get_xtime(boost::system_time const& abs_time)
|
||||
{
|
||||
xtime res;
|
||||
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
|
||||
|
||||
res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds());
|
||||
res.nsec=static_cast<xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()));
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int xtime_get(struct xtime* xtp, int clock_type)
|
||||
{
|
||||
if (clock_type == TIME_UTC_)
|
||||
{
|
||||
*xtp=get_xtime(get_system_time());
|
||||
return clock_type;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
|
||||
{
|
||||
if (xt1.sec == xt2.sec)
|
||||
return (int)(xt1.nsec - xt2.nsec);
|
||||
else
|
||||
return (xt1.sec > xt2.sec) ? 1 : -1;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif //BOOST_XTIME_WEK070601_HPP
|
||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
||||
<!-- Copyright (c) 2002-2003 William E. Kempf.
|
||||
Subject to the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
-->
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=doc/index.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
|
||||
</body>
|
||||
</html>
|
||||
61
src/future.cpp
Executable file
61
src/future.cpp
Executable file
@@ -0,0 +1,61 @@
|
||||
// (C) Copyright 2012 Vicente J. Botet Escriba
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
class future_error_category :
|
||||
public boost::system::error_category
|
||||
{
|
||||
public:
|
||||
virtual const char* name() const; //BOOST_NOEXCEPT;
|
||||
virtual std::string message(int ev) const;
|
||||
};
|
||||
|
||||
const char*
|
||||
future_error_category::name() const //BOOST_NOEXCEPT
|
||||
{
|
||||
return "future";
|
||||
}
|
||||
|
||||
std::string
|
||||
future_error_category::message(int ev) const
|
||||
{
|
||||
switch (BOOST_SCOPED_ENUM_NATIVE(future_errc)(ev))
|
||||
{
|
||||
case future_errc::broken_promise:
|
||||
return std::string("The associated promise has been destructed prior "
|
||||
"to the associated state becoming ready.");
|
||||
case future_errc::future_already_retrieved:
|
||||
return std::string("The future has already been retrieved from "
|
||||
"the promise or packaged_task.");
|
||||
case future_errc::promise_already_satisfied:
|
||||
return std::string("The state of the promise has already been set.");
|
||||
case future_errc::no_state:
|
||||
return std::string("Operation not permitted on an object without "
|
||||
"an associated state.");
|
||||
}
|
||||
return std::string("unspecified future_errc value\n");
|
||||
}
|
||||
}
|
||||
|
||||
const system::error_category&
|
||||
future_category()
|
||||
{
|
||||
static thread_detail::future_error_category f;
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
72
src/pthread/once.cpp
Normal file
72
src/pthread/once.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright (C) 2007 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define __STDC_CONSTANT_MACROS
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
|
||||
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
|
||||
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
namespace
|
||||
{
|
||||
pthread_key_t epoch_tss_key;
|
||||
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static void delete_epoch_tss_data(void* data)
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void create_epoch_tss_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PATCH
|
||||
const pthread_once_t pthread_once_init_value=PTHREAD_ONCE_INIT;
|
||||
struct BOOST_THREAD_DECL delete_epoch_tss_key_on_dlclose_t
|
||||
{
|
||||
delete_epoch_tss_key_on_dlclose_t()
|
||||
{
|
||||
}
|
||||
~delete_epoch_tss_key_on_dlclose_t()
|
||||
{
|
||||
if(memcmp(&epoch_tss_key_flag, &pthread_once_init_value, sizeof(pthread_once_t)))
|
||||
{
|
||||
pthread_key_delete(epoch_tss_key);
|
||||
}
|
||||
}
|
||||
};
|
||||
delete_epoch_tss_key_on_dlclose_t delete_epoch_tss_key_on_dlclose;
|
||||
#endif
|
||||
}
|
||||
|
||||
boost::uintmax_t& get_once_per_thread_epoch()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
|
||||
void* data=pthread_getspecific(epoch_tss_key);
|
||||
if(!data)
|
||||
{
|
||||
data=malloc(sizeof(boost::uintmax_t));
|
||||
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
|
||||
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
|
||||
}
|
||||
return *static_cast<boost::uintmax_t*>(data);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
709
src/pthread/thread.cpp
Normal file
709
src/pthread/thread.cpp
Normal file
@@ -0,0 +1,709 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
// (C) Copyright 2011 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.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#ifdef __GLIBC__
|
||||
#include <sys/sysinfo.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#elif defined BOOST_HAS_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <libs/thread/src/pthread/timeconv.inl>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
thread_data_base::~thread_data_base()
|
||||
{}
|
||||
|
||||
struct thread_exit_callback_node
|
||||
{
|
||||
boost::detail::thread_exit_function_base* func;
|
||||
thread_exit_callback_node* next;
|
||||
|
||||
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
|
||||
thread_exit_callback_node* next_):
|
||||
func(func_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
boost::once_flag current_thread_tls_init_flag;
|
||||
#else
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
#endif
|
||||
pthread_key_t current_thread_tls_key;
|
||||
|
||||
extern "C"
|
||||
{
|
||||
static void tls_destructor(void* data)
|
||||
{
|
||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||
if(thread_info)
|
||||
{
|
||||
while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks)
|
||||
{
|
||||
while(thread_info->thread_exit_callbacks)
|
||||
{
|
||||
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
|
||||
thread_info->thread_exit_callbacks=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)();
|
||||
delete current_node->func;
|
||||
}
|
||||
delete current_node;
|
||||
}
|
||||
for(std::map<void const*,tss_data_node>::iterator next=thread_info->tss_data.begin(),
|
||||
current,
|
||||
end=thread_info->tss_data.end();
|
||||
next!=end;)
|
||||
{
|
||||
current=next;
|
||||
++next;
|
||||
if(current->second.func && (current->second.value!=0))
|
||||
{
|
||||
(*current->second.func)(current->second.value);
|
||||
}
|
||||
thread_info->tss_data.erase(current);
|
||||
}
|
||||
}
|
||||
thread_info->self.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PATCH
|
||||
|
||||
struct delete_current_thread_tls_key_on_dlclose_t
|
||||
{
|
||||
delete_current_thread_tls_key_on_dlclose_t()
|
||||
{
|
||||
}
|
||||
~delete_current_thread_tls_key_on_dlclose_t()
|
||||
{
|
||||
if (current_thread_tls_init_flag.epoch!=BOOST_ONCE_INITIAL_FLAG_VALUE)
|
||||
{
|
||||
pthread_key_delete(current_thread_tls_key);
|
||||
}
|
||||
}
|
||||
};
|
||||
delete_current_thread_tls_key_on_dlclose_t delete_current_thread_tls_key_on_dlclose;
|
||||
#endif
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(¤t_thread_tls_key,&tls_destructor));
|
||||
}
|
||||
}
|
||||
|
||||
boost::detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
static void* thread_proxy(void* param)
|
||||
{
|
||||
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
|
||||
thread_info->self.reset();
|
||||
detail::set_current_thread_data(thread_info.get());
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
thread_info->run();
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(thread_interrupted const&) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
}
|
||||
#endif
|
||||
// Removed as it stops the debugger identifying the cause of the exception
|
||||
// Unhandled exceptions still cause the application to terminate
|
||||
// catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
// {
|
||||
// std::terminate();
|
||||
// }
|
||||
|
||||
detail::tls_destructor(thread_info.get());
|
||||
detail::set_current_thread_data(0);
|
||||
boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
|
||||
thread_info->done=true;
|
||||
thread_info->done_condition.notify_all();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
externally_launched_thread()
|
||||
{
|
||||
interrupt_enabled=false;
|
||||
}
|
||||
|
||||
void run()
|
||||
{}
|
||||
|
||||
private:
|
||||
externally_launched_thread(externally_launched_thread&);
|
||||
void operator=(externally_launched_thread&);
|
||||
};
|
||||
|
||||
detail::thread_data_base* make_external_thread_data()
|
||||
{
|
||||
detail::thread_data_base* const me(new externally_launched_thread());
|
||||
me->self.reset(me);
|
||||
set_current_thread_data(me);
|
||||
return me;
|
||||
}
|
||||
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
current_thread_data=make_external_thread_data();
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
thread::thread() BOOST_NOEXCEPT
|
||||
{}
|
||||
|
||||
void thread::start_thread()
|
||||
{
|
||||
thread_info->self=thread_info;
|
||||
int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create"));
|
||||
}
|
||||
}
|
||||
|
||||
void thread::start_thread(const attributes& attr)
|
||||
{
|
||||
thread_info->self=thread_info;
|
||||
const attributes::native_handle_type* h = attr.native_handle();
|
||||
int res = pthread_create(&thread_info->thread_handle, h, &thread_proxy, thread_info.get());
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
int detached_state;
|
||||
res = pthread_attr_getdetachstate(h, &detached_state);
|
||||
if (res != 0)
|
||||
{
|
||||
thread_info->self.reset();
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
if (PTHREAD_CREATE_DETACHED==detached_state)
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
thread_info.swap(local_thread_info);
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
//lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
if(!local_thread_info->join_started)
|
||||
{
|
||||
//BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
|
||||
local_thread_info->join_started=true;
|
||||
local_thread_info->joined=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
{
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
}
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::do_try_join_until(struct timespec const &timeout)
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
}
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
{
|
||||
if(!local_thread_info->done_condition.do_timed_wait(lock,timeout))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
}
|
||||
else
|
||||
{
|
||||
while(!local_thread_info->joined)
|
||||
{
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(do_join)
|
||||
{
|
||||
void* result=0;
|
||||
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool thread::joinable() const BOOST_NOEXCEPT
|
||||
{
|
||||
return (get_thread_info)();
|
||||
}
|
||||
|
||||
|
||||
void thread::detach() BOOST_NOEXCEPT
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
thread_info.swap(local_thread_info);
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
if(!local_thread_info->join_started)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
|
||||
local_thread_info->join_started=true;
|
||||
local_thread_info->joined=true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
|
||||
#ifdef __DECXXX
|
||||
/// Workaround of DECCXX issue of incorrect template substitution
|
||||
template<>
|
||||
#endif
|
||||
void sleep(const system_time& st)
|
||||
{
|
||||
detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
|
||||
if(thread_info)
|
||||
{
|
||||
unique_lock<mutex> lk(thread_info->sleep_mutex);
|
||||
while(thread_info->sleep_condition.timed_wait(lk,st)) {}
|
||||
}
|
||||
else
|
||||
{
|
||||
xtime const xt=get_xtime(st);
|
||||
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
timespec ts;
|
||||
to_timespec_duration(xt, ts);
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
timespec ts;
|
||||
to_timespec_duration(xt, ts);
|
||||
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
mutex::scoped_lock lock(mx);
|
||||
condition cond;
|
||||
cond.timed_wait(lock, xt);
|
||||
# endif
|
||||
xtime cur;
|
||||
xtime_get(&cur, TIME_UTC_);
|
||||
if (xtime_cmp(xt, cur) <= 0)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
void
|
||||
sleep_for(const chrono::nanoseconds& ns)
|
||||
{
|
||||
using namespace chrono;
|
||||
if (ns >= nanoseconds::zero())
|
||||
{
|
||||
timespec ts;
|
||||
ts.tv_sec = static_cast<long>(duration_cast<seconds>(ns).count());
|
||||
ts.tv_nsec = static_cast<long>((ns - seconds(ts.tv_sec)).count());
|
||||
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
BOOST_VERIFY(!pthread_delay_np(&ts));
|
||||
# elif defined(BOOST_HAS_NANOSLEEP)
|
||||
// nanosleep takes a timespec that is an offset, not
|
||||
// an absolute time.
|
||||
nanosleep(&ts, 0);
|
||||
# else
|
||||
mutex mx;
|
||||
mutex::scoped_lock lock(mx);
|
||||
condition_variable cond;
|
||||
cond.wait_for(lock, ns);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void yield() BOOST_NOEXCEPT
|
||||
{
|
||||
# if defined(BOOST_HAS_SCHED_YIELD)
|
||||
BOOST_VERIFY(!sched_yield());
|
||||
# elif defined(BOOST_HAS_PTHREAD_YIELD)
|
||||
BOOST_VERIFY(!pthread_yield());
|
||||
# else
|
||||
xtime xt;
|
||||
xtime_get(&xt, TIME_UTC_);
|
||||
sleep(xt);
|
||||
# endif
|
||||
}
|
||||
}
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined(PTW32_VERSION) || defined(__hpux)
|
||||
return pthread_num_processors_np();
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
int count;
|
||||
size_t size=sizeof(count);
|
||||
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
|
||||
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
|
||||
int const count=sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (count>0)?count:0;
|
||||
#elif defined(__GLIBC__)
|
||||
return get_nprocs();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
//return local_thread_info->thread_handle;
|
||||
return const_cast<thread*>(this)->native_handle();
|
||||
#else
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
return id(local_thread_info);
|
||||
}
|
||||
else
|
||||
{
|
||||
return id();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void thread::interrupt()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
local_thread_info->interrupt_requested=true;
|
||||
if(local_thread_info->current_cond)
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(local_thread_info->cond_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::interruption_requested() const BOOST_NOEXCEPT
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->interrupt_requested;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr const local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lk(local_thread_info->data_mutex);
|
||||
return local_thread_info->thread_handle;
|
||||
}
|
||||
else
|
||||
{
|
||||
return pthread_t();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
thread::id get_id() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
return pthread_self();
|
||||
#else
|
||||
boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
|
||||
return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr());
|
||||
#endif
|
||||
}
|
||||
|
||||
void interruption_point()
|
||||
{
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(thread_info && thread_info->interrupt_enabled)
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
if(thread_info->interrupt_requested)
|
||||
{
|
||||
thread_info->interrupt_requested=false;
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool interruption_enabled() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
return thread_info && thread_info->interrupt_enabled;
|
||||
}
|
||||
|
||||
bool interruption_requested() BOOST_NOEXCEPT
|
||||
{
|
||||
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
|
||||
if(!thread_info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
lock_guard<mutex> lg(thread_info->data_mutex);
|
||||
return thread_info->interrupt_requested;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::disable_interruption() BOOST_NOEXCEPT:
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
if(interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::~disable_interruption() BOOST_NOEXCEPT
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
|
||||
{
|
||||
if(d.interruption_was_enabled)
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::~restore_interruption() BOOST_NOEXCEPT
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
{
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void add_thread_exit_function(thread_exit_function_base* func)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
tss_data_node* find_tss_data(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
std::map<void const*,tss_data_node>::iterator current_node=
|
||||
current_thread_data->tss_data.find(key);
|
||||
if(current_node!=current_thread_data->tss_data.end())
|
||||
{
|
||||
return ¤t_node->second;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* get_tss_data(void const* key)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
return current_node->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void add_new_tss_node(void const* key,
|
||||
boost::shared_ptr<tss_cleanup_function> func,
|
||||
void* tss_data)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.insert(std::make_pair(key,tss_data_node(func,tss_data)));
|
||||
}
|
||||
|
||||
void erase_tss_node(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.erase(key);
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,
|
||||
boost::shared_ptr<tss_cleanup_function> func,
|
||||
void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func && (current_node->value!=0))
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
if(func || (tss_data!=0))
|
||||
{
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
erase_tss_node(key);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
add_new_tss_node(key,func,tss_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
132
src/pthread/timeconv.inl
Normal file
132
src/pthread/timeconv.inl
Normal file
@@ -0,0 +1,132 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2009 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_sec = xt.sec - cur.sec;
|
||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||
|
||||
if( ts.tv_nsec < 0 )
|
||||
{
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(boost::xtime xt, int& microseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC_); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
||||
38
src/tss_null.cpp
Normal file
38
src/tss_null.cpp
Normal file
@@ -0,0 +1,38 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
|
||||
|
||||
namespace boost
|
||||
{
|
||||
/*
|
||||
This file is a "null" implementation of tss cleanup; it's
|
||||
purpose is to to eliminate link errors in cases
|
||||
where it is known that tss cleanup is not needed.
|
||||
*/
|
||||
|
||||
void tss_cleanup_implemented(void)
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
automatic tss cleanup is not implemented by Boost.Threads as a
|
||||
reminder that user code is responsible for calling the necessary
|
||||
functions at the appropriate times (and for implementing an a
|
||||
tss_cleanup_implemented() function to eliminate the linker's
|
||||
missing symbol error).
|
||||
|
||||
If Boost.Threads later implements automatic tss cleanup in cases
|
||||
where it currently doesn't (which is the plan), the duplicate
|
||||
symbol error will warn the user that their custom solution is no
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && !defined(_MSC_VER)
|
||||
699
src/win32/thread.cpp
Normal file
699
src/win32/thread.cpp
Normal file
@@ -0,0 +1,699 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x400
|
||||
#endif
|
||||
|
||||
#ifndef WINVER
|
||||
#define WINVER 0x400
|
||||
#endif
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <algorithm>
|
||||
#ifndef UNDER_CE
|
||||
#include <process.h>
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <windows.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace
|
||||
{
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
boost::once_flag current_thread_tls_init_flag;
|
||||
#else
|
||||
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
|
||||
#endif
|
||||
#if defined(UNDER_CE)
|
||||
// Windows CE does not define the TLS_OUT_OF_INDEXES constant.
|
||||
#define TLS_OUT_OF_INDEXES 0xFFFFFFFF
|
||||
#endif
|
||||
DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
|
||||
current_thread_tls_key=TlsAlloc();
|
||||
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
||||
}
|
||||
|
||||
void cleanup_tls_key()
|
||||
{
|
||||
if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
TlsFree(current_thread_tls_key);
|
||||
current_thread_tls_key=TLS_OUT_OF_INDEXES;
|
||||
}
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_current_thread_data()
|
||||
{
|
||||
if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
|
||||
}
|
||||
|
||||
void set_current_thread_data(detail::thread_data_base* new_data)
|
||||
{
|
||||
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
|
||||
if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
|
||||
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
|
||||
else
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
|
||||
#ifndef BOOST_HAS_THREADEX
|
||||
// Windows CE doesn't define _beginthreadex
|
||||
|
||||
struct ThreadProxyData
|
||||
{
|
||||
typedef unsigned (__stdcall* func)(void*);
|
||||
func start_address_;
|
||||
void* arglist_;
|
||||
ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
|
||||
};
|
||||
|
||||
DWORD WINAPI ThreadProxy(LPVOID args)
|
||||
{
|
||||
std::auto_ptr<ThreadProxyData> data(reinterpret_cast<ThreadProxyData*>(args));
|
||||
DWORD ret=data->start_address_(data->arglist_);
|
||||
return ret;
|
||||
}
|
||||
|
||||
typedef void* uintptr_t;
|
||||
|
||||
inline uintptr_t _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
|
||||
void* arglist, unsigned initflag, unsigned* thrdaddr)
|
||||
{
|
||||
DWORD threadID;
|
||||
ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
|
||||
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
|
||||
data,initflag,&threadID);
|
||||
if (hthread==0) {
|
||||
delete data;
|
||||
return 0;
|
||||
}
|
||||
*thrdaddr=threadID;
|
||||
return reinterpret_cast<uintptr_t const>(hthread);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct thread_exit_callback_node
|
||||
{
|
||||
boost::detail::thread_exit_function_base* func;
|
||||
thread_exit_callback_node* next;
|
||||
|
||||
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
|
||||
thread_exit_callback_node* next_):
|
||||
func(func_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
struct tss_data_node
|
||||
{
|
||||
void const* key;
|
||||
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
|
||||
void* value;
|
||||
tss_data_node* next;
|
||||
|
||||
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
|
||||
tss_data_node* next_):
|
||||
key(key_),func(func_),value(value_),next(next_)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void run_thread_exit_callbacks()
|
||||
{
|
||||
detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
|
||||
if(current_thread_data)
|
||||
{
|
||||
while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
|
||||
{
|
||||
while(current_thread_data->thread_exit_callbacks)
|
||||
{
|
||||
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
|
||||
current_thread_data->thread_exit_callbacks=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)();
|
||||
boost::detail::heap_delete(current_node->func);
|
||||
}
|
||||
boost::detail::heap_delete(current_node);
|
||||
}
|
||||
while(current_thread_data->tss_data)
|
||||
{
|
||||
detail::tss_data_node* const current_node=current_thread_data->tss_data;
|
||||
current_thread_data->tss_data=current_node->next;
|
||||
if(current_node->func)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
boost::detail::heap_delete(current_node);
|
||||
}
|
||||
}
|
||||
|
||||
set_current_thread_data(0);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned __stdcall thread_start_function(void* param)
|
||||
{
|
||||
detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
|
||||
set_current_thread_data(thread_info);
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
thread_info->run();
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(thread_interrupted const&) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
}
|
||||
#endif
|
||||
// Removed as it stops the debugger identifying the cause of the exception
|
||||
// Unhandled exceptions still cause the application to terminate
|
||||
// catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
// {
|
||||
// std::terminate();
|
||||
// }
|
||||
run_thread_exit_callbacks();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
thread::thread() BOOST_NOEXCEPT
|
||||
{}
|
||||
|
||||
void thread::start_thread()
|
||||
{
|
||||
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
if(!new_thread)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
intrusive_ptr_add_ref(thread_info.get());
|
||||
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
||||
ResumeThread(thread_info->thread_handle);
|
||||
}
|
||||
|
||||
void thread::start_thread(const attributes& attr)
|
||||
{
|
||||
//uintptr_t const new_thread=_beginthreadex(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
|
||||
if(!new_thread)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
intrusive_ptr_add_ref(thread_info.get());
|
||||
thread_info->thread_handle=(detail::win32::handle)(new_thread);
|
||||
ResumeThread(thread_info->thread_handle);
|
||||
}
|
||||
|
||||
thread::thread(detail::thread_data_ptr data):
|
||||
thread_info(data)
|
||||
{}
|
||||
|
||||
namespace
|
||||
{
|
||||
struct externally_launched_thread:
|
||||
detail::thread_data_base
|
||||
{
|
||||
externally_launched_thread()
|
||||
{
|
||||
++count;
|
||||
interruption_enabled=false;
|
||||
}
|
||||
|
||||
void run()
|
||||
{}
|
||||
private:
|
||||
externally_launched_thread(externally_launched_thread&);
|
||||
void operator=(externally_launched_thread&);
|
||||
};
|
||||
|
||||
void make_external_thread_data()
|
||||
{
|
||||
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
try // BOOST_NO_EXCEPTIONS protected
|
||||
#endif
|
||||
{
|
||||
set_current_thread_data(me);
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(...) // BOOST_NO_EXCEPTIONS protected
|
||||
{
|
||||
detail::heap_delete(me);
|
||||
throw; // BOOST_NO_EXCEPTIONS protected
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
detail::thread_data_base* get_or_make_current_thread_data()
|
||||
{
|
||||
detail::thread_data_base* current_thread_data(get_current_thread_data());
|
||||
if(!current_thread_data)
|
||||
{
|
||||
make_external_thread_data();
|
||||
current_thread_data=get_current_thread_data();
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
thread::id thread::get_id() const BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
return local_thread_info?local_thread_info->id:0;
|
||||
//return const_cast<thread*>(this)->native_handle();
|
||||
#else
|
||||
return thread::id((get_thread_info)());
|
||||
#endif
|
||||
}
|
||||
|
||||
bool thread::joinable() const BOOST_NOEXCEPT
|
||||
{
|
||||
return (get_thread_info)();
|
||||
}
|
||||
|
||||
void thread::join()
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
}
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
|
||||
release_handle();
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::timed_join(boost::system_time const& wait_until)
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
}
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
release_handle();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
|
||||
bool thread::try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
{
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
}
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
|
||||
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,rel_time.count()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
release_handle();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void thread::detach() BOOST_NOEXCEPT
|
||||
{
|
||||
release_handle();
|
||||
}
|
||||
|
||||
void thread::release_handle()
|
||||
{
|
||||
thread_info=0;
|
||||
}
|
||||
|
||||
void thread::interrupt()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
if(local_thread_info)
|
||||
{
|
||||
local_thread_info->interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
bool thread::interruption_requested() const BOOST_NOEXCEPT
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
SYSTEM_INFO info={{0}};
|
||||
GetSystemInfo(&info);
|
||||
return info.dwNumberOfProcessors;
|
||||
}
|
||||
|
||||
thread::native_handle_type thread::native_handle()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
|
||||
}
|
||||
|
||||
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
|
||||
{
|
||||
return thread_info;
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace
|
||||
{
|
||||
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
|
||||
{
|
||||
LARGE_INTEGER due_time={{0}};
|
||||
if(target_time.relative)
|
||||
{
|
||||
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
|
||||
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
|
||||
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
|
||||
|
||||
if(remaining_milliseconds>0)
|
||||
{
|
||||
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SYSTEMTIME target_system_time={0};
|
||||
target_system_time.wYear=target_time.abs_time.date().year();
|
||||
target_system_time.wMonth=target_time.abs_time.date().month();
|
||||
target_system_time.wDay=target_time.abs_time.date().day();
|
||||
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
|
||||
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
|
||||
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
|
||||
|
||||
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
|
||||
{
|
||||
due_time.QuadPart=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
long const hundred_nanoseconds_in_one_second=10000000;
|
||||
posix_time::time_duration::tick_type const ticks_per_second=
|
||||
target_time.abs_time.time_of_day().ticks_per_second();
|
||||
if(ticks_per_second>hundred_nanoseconds_in_one_second)
|
||||
{
|
||||
posix_time::time_duration::tick_type const
|
||||
ticks_per_hundred_nanoseconds=
|
||||
ticks_per_second/hundred_nanoseconds_in_one_second;
|
||||
due_time.QuadPart+=
|
||||
target_time.abs_time.time_of_day().fractional_seconds()/
|
||||
ticks_per_hundred_nanoseconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
due_time.QuadPart+=
|
||||
target_time.abs_time.time_of_day().fractional_seconds()*
|
||||
(hundred_nanoseconds_in_one_second/ticks_per_second);
|
||||
}
|
||||
}
|
||||
}
|
||||
return due_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
|
||||
{
|
||||
detail::win32::handle handles[3]={0};
|
||||
unsigned handle_count=0;
|
||||
unsigned wait_handle_index=~0U;
|
||||
unsigned interruption_index=~0U;
|
||||
unsigned timeout_index=~0U;
|
||||
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
|
||||
{
|
||||
wait_handle_index=handle_count;
|
||||
handles[handle_count++]=handle_to_wait_for;
|
||||
}
|
||||
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
|
||||
{
|
||||
interruption_index=handle_count;
|
||||
handles[handle_count++]=get_current_thread_data()->interruption_handle;
|
||||
}
|
||||
|
||||
detail::win32::handle_manager timer_handle;
|
||||
|
||||
#ifndef UNDER_CE
|
||||
unsigned const min_timer_wait_period=20;
|
||||
|
||||
if(!target_time.is_sentinel())
|
||||
{
|
||||
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
|
||||
if(time_left.milliseconds > min_timer_wait_period)
|
||||
{
|
||||
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
|
||||
timer_handle=CreateWaitableTimer(NULL,false,NULL);
|
||||
if(timer_handle!=0)
|
||||
{
|
||||
LARGE_INTEGER due_time=get_due_time(target_time);
|
||||
|
||||
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
|
||||
if(set_time_succeeded)
|
||||
{
|
||||
timeout_index=handle_count;
|
||||
handles[handle_count++]=timer_handle;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(!target_time.relative)
|
||||
{
|
||||
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
|
||||
target_time=detail::timeout(time_left.milliseconds);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
bool const using_timer=timeout_index!=~0u;
|
||||
detail::timeout::remaining_time time_left(0);
|
||||
|
||||
do
|
||||
{
|
||||
if(!using_timer)
|
||||
{
|
||||
time_left=target_time.remaining_milliseconds();
|
||||
}
|
||||
|
||||
if(handle_count)
|
||||
{
|
||||
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
|
||||
if(notified_index<handle_count)
|
||||
{
|
||||
if(notified_index==wait_handle_index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if(notified_index==interruption_index)
|
||||
{
|
||||
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
|
||||
throw thread_interrupted();
|
||||
}
|
||||
else if(notified_index==timeout_index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
detail::win32::Sleep(time_left.milliseconds);
|
||||
}
|
||||
if(target_time.relative)
|
||||
{
|
||||
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
|
||||
}
|
||||
}
|
||||
while(time_left.more);
|
||||
return false;
|
||||
}
|
||||
|
||||
thread::id get_id() BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
|
||||
//return detail::win32::GetCurrentThread();
|
||||
return detail::win32::GetCurrentThreadId();
|
||||
#else
|
||||
return thread::id(get_or_make_current_thread_data());
|
||||
#endif
|
||||
}
|
||||
|
||||
void interruption_point()
|
||||
{
|
||||
if(interruption_enabled() && interruption_requested())
|
||||
{
|
||||
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
bool interruption_enabled() BOOST_NOEXCEPT
|
||||
{
|
||||
return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
|
||||
}
|
||||
|
||||
bool interruption_requested() BOOST_NOEXCEPT
|
||||
{
|
||||
return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
|
||||
}
|
||||
|
||||
void yield() BOOST_NOEXCEPT
|
||||
{
|
||||
detail::win32::Sleep(0);
|
||||
}
|
||||
|
||||
disable_interruption::disable_interruption() BOOST_NOEXCEPT:
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
if(interruption_was_enabled)
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
disable_interruption::~disable_interruption() BOOST_NOEXCEPT
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=interruption_was_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::restore_interruption(disable_interruption& d) BOOST_NOEXCEPT
|
||||
{
|
||||
if(d.interruption_was_enabled)
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
restore_interruption::~restore_interruption() BOOST_NOEXCEPT
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
{
|
||||
get_current_thread_data()->interruption_enabled=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void add_thread_exit_function(thread_exit_function_base* func)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
thread_exit_callback_node* const new_node=
|
||||
heap_new<thread_exit_callback_node>(
|
||||
func,current_thread_data->thread_exit_callbacks);
|
||||
current_thread_data->thread_exit_callbacks=new_node;
|
||||
}
|
||||
|
||||
tss_data_node* find_tss_data(void const* key)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
detail::tss_data_node* current_node=current_thread_data->tss_data;
|
||||
while(current_node)
|
||||
{
|
||||
if(current_node->key==key)
|
||||
{
|
||||
return current_node;
|
||||
}
|
||||
current_node=current_node->next;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void* get_tss_data(void const* key)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
return current_node->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
|
||||
{
|
||||
if(tss_data_node* const current_node=find_tss_data(key))
|
||||
{
|
||||
if(cleanup_existing && current_node->func.get() && current_node->value)
|
||||
{
|
||||
(*current_node->func)(current_node->value);
|
||||
}
|
||||
current_node->func=func;
|
||||
current_node->value=tss_data;
|
||||
}
|
||||
else if(func && tss_data)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
tss_data_node* const new_node=
|
||||
heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
|
||||
current_thread_data->tss_data=new_node;
|
||||
}
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_DECL void __cdecl on_process_enter()
|
||||
{}
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_thread_enter()
|
||||
{}
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_process_exit()
|
||||
{
|
||||
boost::cleanup_tls_key();
|
||||
}
|
||||
|
||||
BOOST_THREAD_DECL void __cdecl on_thread_exit()
|
||||
{
|
||||
boost::run_thread_exit_callbacks();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
130
src/win32/timeconv.inl
Normal file
130
src/win32/timeconv.inl
Normal file
@@ -0,0 +1,130 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// boostinspect:nounnamed
|
||||
|
||||
namespace {
|
||||
const int MILLISECONDS_PER_SECOND = 1000;
|
||||
const int NANOSECONDS_PER_SECOND = 1000000000;
|
||||
const int NANOSECONDS_PER_MILLISECOND = 1000000;
|
||||
|
||||
const int MICROSECONDS_PER_SECOND = 1000000;
|
||||
const int NANOSECONDS_PER_MICROSECOND = 1000;
|
||||
|
||||
inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
|
||||
if (xt.nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
++xt.sec;
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
ts.tv_sec = static_cast<int>(xt.sec);
|
||||
ts.tv_nsec = static_cast<int>(xt.nsec);
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_time(int milliseconds, timespec& ts)
|
||||
{
|
||||
boost::xtime xt;
|
||||
to_time(milliseconds, xt);
|
||||
to_timespec(xt, ts);
|
||||
}
|
||||
|
||||
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
ts.tv_sec = 0;
|
||||
ts.tv_nsec = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ts.tv_sec = xt.sec - cur.sec;
|
||||
ts.tv_nsec = xt.nsec - cur.nsec;
|
||||
|
||||
if( ts.tv_nsec < 0 )
|
||||
{
|
||||
ts.tv_sec -= 1;
|
||||
ts.tv_nsec += NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
|
||||
{
|
||||
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
|
||||
NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
}
|
||||
|
||||
inline void to_microduration(boost::xtime xt, int& microseconds)
|
||||
{
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC_);
|
||||
assert(res == boost::TIME_UTC_);
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
else
|
||||
{
|
||||
if (cur.nsec > xt.nsec)
|
||||
{
|
||||
xt.nsec += NANOSECONDS_PER_SECOND;
|
||||
--xt.sec;
|
||||
}
|
||||
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
|
||||
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
|
||||
NANOSECONDS_PER_MICROSECOND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Change Log:
|
||||
// 1 Jun 01 Initial creation.
|
||||
76
src/win32/tss_dll.cpp
Normal file
76
src/win32/tss_dll.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// (C) Copyright Michael Glassford 2004.
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#if defined(__BORLANDC__)
|
||||
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
#elif defined(_WIN32_WCE)
|
||||
extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
#else
|
||||
extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
|
||||
#endif
|
||||
{
|
||||
switch(dwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
boost::on_process_enter();
|
||||
boost::on_thread_enter();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
{
|
||||
boost::on_thread_enter();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
}
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
{
|
||||
boost::on_thread_exit();
|
||||
boost::on_process_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
namespace boost
|
||||
{
|
||||
void tss_cleanup_implemented()
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
automatic tss cleanup is not implemented by Boost.Threads as a
|
||||
reminder that user code is responsible for calling the necessary
|
||||
functions at the appropriate times (and for implementing an a
|
||||
tss_cleanup_implemented() function to eliminate the linker's
|
||||
missing symbol error).
|
||||
|
||||
If Boost.Threads later implements automatic tss cleanup in cases
|
||||
where it currently doesn't (which is the plan), the duplicate
|
||||
symbol error will warn the user that their custom solution is no
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
|
||||
284
src/win32/tss_pe.cpp
Normal file
284
src/win32/tss_pe.cpp
Normal file
@@ -0,0 +1,284 @@
|
||||
// $Id$
|
||||
// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
|
||||
// (C) Copyright 2007 Roland Schwarz
|
||||
// (C) Copyright 2007 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
// Use, modification and distribution are subject to the
|
||||
// Boost Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
|
||||
#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
void tss_cleanup_implemented() {}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void NTAPI on_tls_callback(void* , DWORD dwReason, PVOID )
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
{
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32_MAJOR_VERSION >3) || \
|
||||
((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
|
||||
extern "C"
|
||||
{
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
|
||||
}
|
||||
#else
|
||||
extern "C" {
|
||||
|
||||
void (* after_ctors )() __attribute__((section(".ctors"))) = boost::on_process_enter;
|
||||
void (* before_dtors)() __attribute__((section(".dtors"))) = boost::on_thread_exit;
|
||||
void (* after_dtors )() __attribute__((section(".dtors.zzz"))) = boost::on_process_exit;
|
||||
|
||||
ULONG __tls_index__ = 0;
|
||||
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
|
||||
char __tls_start__ __attribute__((section(".tls"))) = 0;
|
||||
|
||||
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
|
||||
}
|
||||
extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
|
||||
{
|
||||
(DWORD) &__tls_start__,
|
||||
(DWORD) &__tls_end__,
|
||||
(DWORD) &__tls_index__,
|
||||
(DWORD) (&__crt_xl_start__+1),
|
||||
(DWORD) 0,
|
||||
(DWORD) 0
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#elif defined(_MSC_VER) && !defined(UNDER_CE)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
//Definitions required by implementation
|
||||
|
||||
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
|
||||
typedef void (__cdecl *_PVFV)();
|
||||
#define INIRETSUCCESS
|
||||
#define PVAPI void __cdecl
|
||||
#else
|
||||
typedef int (__cdecl *_PVFV)();
|
||||
#define INIRETSUCCESS 0
|
||||
#define PVAPI int __cdecl
|
||||
#endif
|
||||
|
||||
typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
|
||||
|
||||
//Symbols for connection to the runtime environment
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern DWORD _tls_used; //the tls directory (located in .rdata segment)
|
||||
extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
//Forward declarations
|
||||
|
||||
static PVAPI on_tls_prepare();
|
||||
static PVAPI on_process_init();
|
||||
static PVAPI on_process_term();
|
||||
static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
|
||||
|
||||
//The .CRT$Xxx information is taken from Codeguru:
|
||||
//http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
|
||||
|
||||
#if (_MSC_VER >= 1400)
|
||||
#pragma section(".CRT$XIU",long,read)
|
||||
#pragma section(".CRT$XCU",long,read)
|
||||
#pragma section(".CRT$XTU",long,read)
|
||||
#pragma section(".CRT$XLC",long,read)
|
||||
__declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
|
||||
__declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
|
||||
__declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
|
||||
__declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
|
||||
#else
|
||||
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
|
||||
# pragma data_seg(push, old_seg)
|
||||
#endif
|
||||
//Callback to run tls glue code first.
|
||||
//I don't think it is necessary to run it
|
||||
//at .CRT$XIB level, since we are only
|
||||
//interested in thread detachement. But
|
||||
//this could be changed easily if required.
|
||||
|
||||
#pragma data_seg(".CRT$XIU")
|
||||
static _PVFV p_tls_prepare = on_tls_prepare;
|
||||
#pragma data_seg()
|
||||
|
||||
//Callback after all global ctors.
|
||||
|
||||
#pragma data_seg(".CRT$XCU")
|
||||
static _PVFV p_process_init = on_process_init;
|
||||
#pragma data_seg()
|
||||
|
||||
//Callback for tls notifications.
|
||||
|
||||
#pragma data_seg(".CRT$XLB")
|
||||
_TLSCB p_thread_callback = on_tls_callback;
|
||||
#pragma data_seg()
|
||||
//Callback for termination.
|
||||
|
||||
#pragma data_seg(".CRT$XTU")
|
||||
static _PVFV p_process_term = on_process_term;
|
||||
#pragma data_seg()
|
||||
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
|
||||
# pragma data_seg(pop, old_seg)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4189)
|
||||
#endif
|
||||
|
||||
PVAPI on_tls_prepare()
|
||||
{
|
||||
//The following line has an important side effect:
|
||||
//if the TLS directory is not already there, it will
|
||||
//be created by the linker. In other words, it forces a tls
|
||||
//directory to be generated by the linker even when static tls
|
||||
//(i.e. __declspec(thread)) is not used.
|
||||
//The volatile should prevent the optimizer
|
||||
//from removing the reference.
|
||||
|
||||
DWORD volatile dw = _tls_used;
|
||||
|
||||
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
|
||||
_TLSCB* pfbegin = __xl_a;
|
||||
_TLSCB* pfend = __xl_z;
|
||||
_TLSCB* pfdst = pfbegin;
|
||||
//pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
|
||||
|
||||
//The following loop will merge the address pointers
|
||||
//into a contiguous area, since the tlssup code seems
|
||||
//to require this (at least on MSVC 6)
|
||||
|
||||
while (pfbegin < pfend)
|
||||
{
|
||||
if (*pfbegin != 0)
|
||||
{
|
||||
*pfdst = *pfbegin;
|
||||
++pfdst;
|
||||
}
|
||||
++pfbegin;
|
||||
}
|
||||
|
||||
*pfdst = 0;
|
||||
#endif
|
||||
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
#ifdef BOOST_MSVC
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
PVAPI on_process_init()
|
||||
{
|
||||
//Schedule on_thread_exit() to be called for the main
|
||||
//thread before destructors of global objects have been
|
||||
//called.
|
||||
|
||||
//It will not be run when 'quick' exiting the
|
||||
//library; however, this is the standard behaviour
|
||||
//for destructors of global objects, so that
|
||||
//shouldn't be a problem.
|
||||
|
||||
atexit(boost::on_thread_exit);
|
||||
|
||||
//Call Boost process entry callback here
|
||||
|
||||
boost::on_process_enter();
|
||||
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
PVAPI on_process_term()
|
||||
{
|
||||
boost::on_process_exit();
|
||||
return INIRETSUCCESS;
|
||||
}
|
||||
|
||||
void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
|
||||
{
|
||||
switch (dwReason)
|
||||
{
|
||||
case DLL_THREAD_DETACH:
|
||||
boost::on_thread_exit();
|
||||
break;
|
||||
case DLL_PROCESS_DETACH:
|
||||
boost::on_process_exit();
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} //namespace
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
|
||||
}
|
||||
namespace boost
|
||||
{
|
||||
void tss_cleanup_implemented()
|
||||
{
|
||||
/*
|
||||
This function's sole purpose is to cause a link error in cases where
|
||||
automatic tss cleanup is not implemented by Boost.Threads as a
|
||||
reminder that user code is responsible for calling the necessary
|
||||
functions at the appropriate times (and for implementing an a
|
||||
tss_cleanup_implemented() function to eliminate the linker's
|
||||
missing symbol error).
|
||||
|
||||
If Boost.Threads later implements automatic tss cleanup in cases
|
||||
where it currently doesn't (which is the plan), the duplicate
|
||||
symbol error will warn the user that their custom solution is no
|
||||
longer needed and can be removed.
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
|
||||
|
||||
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
18
test/Carbon.r
Normal file
18
test/Carbon.r
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Permit this Carbon application to launch on OS X
|
||||
*
|
||||
* © 1997-2000 Metrowerks Corp.
|
||||
*
|
||||
* Questions and comments to:
|
||||
* <mailto:support@metrowerks.com>
|
||||
* <http://www.metrowerks.com/>
|
||||
*/
|
||||
|
||||
|
||||
/*----------------------------carb ¥ Carbon on OS X launch information --------------------------*/
|
||||
type 'carb' {
|
||||
};
|
||||
|
||||
|
||||
resource 'carb'(0) {
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user