mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 21:52:07 +00:00
Compare commits
657 Commits
boost-1.54
...
boost-1.56
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0b2a61bca0 | ||
|
|
c6e70226ea | ||
|
|
5cdd807718 | ||
|
|
2a6948d74d | ||
|
|
590a3d99b0 | ||
|
|
14dfe49c50 | ||
|
|
08c4599fb6 | ||
|
|
ca14e6187d | ||
|
|
f263c6014e | ||
|
|
9e962e12e2 | ||
|
|
6e154d45a4 | ||
|
|
c54e519f72 | ||
|
|
5c61dced5e | ||
|
|
8a7f927be9 | ||
|
|
6074487b73 | ||
|
|
04c53415fd | ||
|
|
fe6daec2bc | ||
|
|
f75b2ca155 | ||
|
|
68be44ec06 | ||
|
|
817591b87c | ||
|
|
d7a3f124db | ||
|
|
c6817aeb1c | ||
|
|
c266790b8d | ||
|
|
00ad9dddb9 | ||
|
|
21617e1acb | ||
|
|
99ac322223 | ||
|
|
414fce4580 | ||
|
|
fe195e776b | ||
|
|
8a6d3d68ce | ||
|
|
3a5c926930 | ||
|
|
685ee1506a | ||
|
|
2062cebb54 | ||
|
|
126030eb8c | ||
|
|
ac1b9653f3 | ||
|
|
54ee07e745 | ||
|
|
ca298c2c86 | ||
|
|
4def87448e | ||
|
|
5719ea9e9f | ||
|
|
6583d87c92 | ||
|
|
fcf7a1811e | ||
|
|
d8f628ae65 | ||
|
|
0bd10b7244 | ||
|
|
24635c588f | ||
|
|
4f8106c00e | ||
|
|
3c4f1ea365 | ||
|
|
b5a50ab443 | ||
|
|
cb8a4a27bb | ||
|
|
8c0640e5be | ||
|
|
f807a678e0 | ||
|
|
49a1779d7f | ||
|
|
d3d2ad2390 | ||
|
|
abf844f50e | ||
|
|
4d52ef0740 | ||
|
|
40620e3d4b | ||
|
|
c3ab21a7ba | ||
|
|
c3002edc54 | ||
|
|
100bb706d6 | ||
|
|
de6a4df3a8 | ||
|
|
9669830a86 | ||
|
|
2937171413 | ||
|
|
dd0bfdd7ce | ||
|
|
89e340b177 | ||
|
|
c744899e45 | ||
|
|
0a4af0c5ed | ||
|
|
e6eb24d4a9 | ||
|
|
0d10e282fa | ||
|
|
e8181da6d4 | ||
|
|
68dc454a66 | ||
|
|
0e0ee99c61 | ||
|
|
f747d79c5b | ||
|
|
73fbc520e8 | ||
|
|
7d4f485ade | ||
|
|
143adde27d | ||
|
|
a7400061c6 | ||
|
|
d2a65d2427 | ||
|
|
82379f83a8 | ||
|
|
cc29295986 | ||
|
|
9d1c957625 | ||
|
|
1dbf7028fe | ||
|
|
0bba5e630e | ||
|
|
84c30313a2 | ||
|
|
54646e9959 | ||
|
|
3f5823f50a | ||
|
|
e1636bdbd5 | ||
|
|
750c849b0f | ||
|
|
0a05db8399 | ||
|
|
1d7da085ea | ||
|
|
75236fe3ae | ||
|
|
80634ee51e | ||
|
|
b1ac899f23 | ||
|
|
aa37de7aad | ||
|
|
9d527bebe0 | ||
|
|
f7c18c55bb | ||
|
|
1a2197c7f9 | ||
|
|
4a54ac0331 | ||
|
|
c6593d87b0 | ||
|
|
51e49c69b5 | ||
|
|
ab2a180de5 | ||
|
|
3772a8294b | ||
|
|
155ccfffbe | ||
|
|
bfa0ccee88 | ||
|
|
980772d514 | ||
|
|
94b27db991 | ||
|
|
0a58445b63 | ||
|
|
f02e25e4e7 | ||
|
|
acb117b5a9 | ||
|
|
8682f7cb48 | ||
|
|
4503c0e1da | ||
|
|
dc3397c452 | ||
|
|
af7fde5eae | ||
|
|
36bc3c0523 | ||
|
|
0218cb90b3 | ||
|
|
f4d4c16294 | ||
|
|
85d22a8d93 | ||
|
|
7eb67443dd | ||
|
|
4308e0ec24 | ||
|
|
ac9497dec9 | ||
|
|
8fec35f444 | ||
|
|
7b3fa08503 | ||
|
|
a2e1e80343 | ||
|
|
690feeb9ba | ||
|
|
5d76ab52e7 | ||
|
|
cb845f19e4 | ||
|
|
2886e985b4 | ||
|
|
f4d0ecbab5 | ||
|
|
d187732946 | ||
|
|
1fc78c7ceb | ||
|
|
5c18d92a5f | ||
|
|
06325961ef | ||
|
|
10b283e03a | ||
|
|
6ab71dc057 | ||
|
|
47be5228b1 | ||
|
|
6c5a6e4330 | ||
|
|
326842cc7f | ||
|
|
9f592860cd | ||
|
|
4148842426 | ||
|
|
7edae6614b | ||
|
|
2554065a91 | ||
|
|
74bb7d6b29 | ||
|
|
fbfda71555 | ||
|
|
f3a66f76e0 | ||
|
|
19346e1817 | ||
|
|
5753026ceb | ||
|
|
f6edd7cace | ||
|
|
126ed2428b | ||
|
|
fd631e2794 | ||
|
|
44f9a2f4ad | ||
|
|
8665c5d510 | ||
|
|
e1d6baddd6 | ||
|
|
9287a29c9d | ||
|
|
5c0cecaaf8 | ||
|
|
713f5a449c | ||
|
|
b336427571 | ||
|
|
2a16b649ad | ||
|
|
3723cedcab | ||
|
|
3ad582222c | ||
|
|
c9a33b8668 | ||
|
|
88880770d3 | ||
|
|
9138a2ae92 | ||
|
|
d558de7811 | ||
|
|
19290fddf9 | ||
|
|
2ac967d1dc | ||
|
|
6e81db4172 | ||
|
|
3a68a63478 | ||
|
|
7875edd234 | ||
|
|
2be0b4f8fd | ||
|
|
67528fc9af | ||
|
|
4da1e9dca1 | ||
|
|
d8c9be3449 | ||
|
|
f02390a804 | ||
|
|
955b207c05 | ||
|
|
c17f5d3fc7 | ||
|
|
8685c32d18 | ||
|
|
f51e8c812a | ||
|
|
51aff0fb00 | ||
|
|
bfe7af29bc | ||
|
|
4681104b33 | ||
|
|
d602f44af6 | ||
|
|
dc55945760 | ||
|
|
f7f0347780 | ||
|
|
d6c4be0cd0 | ||
|
|
e146febd70 | ||
|
|
67ca45ed83 | ||
|
|
cad6f2b9a6 | ||
|
|
7756df2ce0 | ||
|
|
ae831efe08 | ||
|
|
fc65611e82 | ||
|
|
8c6dcb9709 | ||
|
|
67afa35c49 | ||
|
|
63d9ae2b29 | ||
|
|
08aa0d2fb6 | ||
|
|
3c8334f8c4 | ||
|
|
0e2c8ed9e3 | ||
|
|
5bfa7cff41 | ||
|
|
e3a1498355 | ||
|
|
6fab117c17 | ||
|
|
4a63d4992c | ||
|
|
04e3d918fb | ||
|
|
0073516f0a | ||
|
|
89de3dcf4f | ||
|
|
47f40f991f | ||
|
|
8b351fe473 | ||
|
|
2da4e8c29e | ||
|
|
8dce737911 | ||
|
|
24f1e620e8 | ||
|
|
ed6459ecd2 | ||
|
|
3a7f0b1e78 | ||
|
|
8f06153f46 | ||
|
|
858816b2d2 | ||
|
|
4bc70444a4 | ||
|
|
fcc027369f | ||
|
|
5c78582794 | ||
|
|
7f479a1dec | ||
|
|
4f2a7b2256 | ||
|
|
5c88e6ce61 | ||
|
|
650e374492 | ||
|
|
6319080ef2 | ||
|
|
3ac48bdd65 | ||
|
|
c3c8ada97d | ||
|
|
325d8cf5ca | ||
|
|
134c323958 | ||
|
|
fd5dd0c2ed | ||
|
|
4a83aa58ed | ||
|
|
7d96aa625c | ||
|
|
5520763a73 | ||
|
|
ad010e0647 | ||
|
|
d57a4c6565 | ||
|
|
73f5c060ca | ||
|
|
c67e39f126 | ||
|
|
5a3c301582 | ||
|
|
dc5a8a9c4e | ||
|
|
1e49343ff4 | ||
|
|
93d1855e64 | ||
|
|
a39dd7e8b3 | ||
|
|
7e5cb92bab | ||
|
|
62cf0f86f6 | ||
|
|
c12e07754a | ||
|
|
cbc4266774 | ||
|
|
3a038d33e5 | ||
|
|
51ba4be998 | ||
|
|
2d50af8481 | ||
|
|
3fb971386a | ||
|
|
e438c98070 | ||
|
|
1e2a76de47 | ||
|
|
34311a60fa | ||
|
|
794d54a65c | ||
|
|
d759dd2dba | ||
|
|
fe46155997 | ||
|
|
cacb5b19a6 | ||
|
|
30803a38b2 | ||
|
|
9fc6fec1eb | ||
|
|
29babb974e | ||
|
|
66578bf57b | ||
|
|
1da5f9563c | ||
|
|
52039f75a3 | ||
|
|
bb6fcc3b5c | ||
|
|
1fc1d8aedb | ||
|
|
042a86c984 | ||
|
|
364f3ea030 | ||
|
|
c87d27a06d | ||
|
|
68d7c69a4b | ||
|
|
6873d85650 | ||
|
|
b59e57e4cc | ||
|
|
d0f9d6216a | ||
|
|
28564064ff | ||
|
|
ff9636b8e0 | ||
|
|
d83d23bee0 | ||
|
|
63f35e9f52 | ||
|
|
5ad38d52e8 | ||
|
|
9d6cd40d8d | ||
|
|
4362cd655e | ||
|
|
0c44630029 | ||
|
|
a01af79331 | ||
|
|
2df6ce78a4 | ||
|
|
3951871d70 | ||
|
|
5a1a9df623 | ||
|
|
a6f67e25e3 | ||
|
|
b69ec54695 | ||
|
|
465aee1b66 | ||
|
|
14d3c59682 | ||
|
|
3f2d8f8865 | ||
|
|
dc8449bd0e | ||
|
|
d3a6277714 | ||
|
|
81d8944b96 | ||
|
|
54faaaf087 | ||
|
|
5a43d5ffe9 | ||
|
|
c628e51e6c | ||
|
|
a66b269198 | ||
|
|
9e07202e21 | ||
|
|
9e2a34ca9d | ||
|
|
4cf80c6685 | ||
|
|
455c31c0e9 | ||
|
|
a8d5fd48c1 | ||
|
|
294a5404c2 | ||
|
|
6d01267030 | ||
|
|
1c48d237a8 | ||
|
|
11ae5c8c44 | ||
|
|
9d10bd035a | ||
|
|
7b48c02d2f | ||
|
|
d8a9331464 | ||
|
|
b60968b045 | ||
|
|
da41bdb632 | ||
|
|
5fcfd0e4e8 | ||
|
|
2d2d1112d6 | ||
|
|
7cf6934515 | ||
|
|
757327ba10 | ||
|
|
a82843d3ab | ||
|
|
5779f6676d | ||
|
|
b359424858 | ||
|
|
a5f7d92960 | ||
|
|
83167d8c15 | ||
|
|
7d2270f8c8 | ||
|
|
f87dbb83b1 | ||
|
|
1a613d03a9 | ||
|
|
d42f4ff169 | ||
|
|
ffbcf96d90 | ||
|
|
f5e246ebb0 | ||
|
|
467a88c4f8 | ||
|
|
f021bad1d5 | ||
|
|
ecd97ec4ea | ||
|
|
c71882816c | ||
|
|
ef5d43fac9 | ||
|
|
fb5404947e | ||
|
|
f24086fe89 | ||
|
|
3e64214e68 | ||
|
|
ed4f0f7b6d | ||
|
|
50c18d6274 | ||
|
|
d5cf734a21 | ||
|
|
43f0c059d3 | ||
|
|
e775ef5c27 | ||
|
|
06b7a41add | ||
|
|
06d2a11127 | ||
|
|
6dd195bbc6 | ||
|
|
8a259612cd | ||
|
|
9fb88b8f47 | ||
|
|
528fcbde56 | ||
|
|
a0397315b2 | ||
|
|
44ec248340 | ||
|
|
7eba48576c | ||
|
|
451027deec | ||
|
|
16b42b6c63 | ||
|
|
a543b918f0 | ||
|
|
619ddf54b9 | ||
|
|
116c947af9 | ||
|
|
a0931c117d | ||
|
|
79e1e88f2e | ||
|
|
af3b5f3227 | ||
|
|
7bebf0a062 | ||
|
|
6dad044ab7 | ||
|
|
19bd0d5eba | ||
|
|
f922fa56e4 | ||
|
|
290faf192d | ||
|
|
054bbad65a | ||
|
|
df7fbe085a | ||
|
|
b03cebff7b | ||
|
|
c9c46e87b5 | ||
|
|
d4e6332eca | ||
|
|
80594adcbb | ||
|
|
4ea14fb9da | ||
|
|
5a22af7639 | ||
|
|
7b157ab5f4 | ||
|
|
a73425eb00 | ||
|
|
b254afc229 | ||
|
|
a1edda3437 | ||
|
|
c784369f76 | ||
|
|
0b7462c4f2 | ||
|
|
23ff6e0120 | ||
|
|
06491889ea | ||
|
|
abf441ee63 | ||
|
|
9615a51123 | ||
|
|
a0bfa7faeb | ||
|
|
44b741e445 | ||
|
|
41d336e7fb | ||
|
|
fc177914e1 | ||
|
|
d0056e0cc8 | ||
|
|
6075cf2df6 | ||
|
|
1eacb8c71d | ||
|
|
7476f71af6 | ||
|
|
d86b5d2c0d | ||
|
|
09f86d603e | ||
|
|
ca3d7dab0b | ||
|
|
7e35a60650 | ||
|
|
2b5bd7275e | ||
|
|
ca37d07184 | ||
|
|
6f2efbcb32 | ||
|
|
1ce6a90f95 | ||
|
|
0a101e15d1 | ||
|
|
d2f7766f8a | ||
|
|
ba7a0935f2 | ||
|
|
7277a94411 | ||
|
|
197bbc1fd3 | ||
|
|
b9e2d7b13d | ||
|
|
579501d98e | ||
|
|
dc352450ca | ||
|
|
21b2bbc8ca | ||
|
|
bd9105a104 | ||
|
|
935d851cdf | ||
|
|
68142e8ff8 | ||
|
|
1dad495280 | ||
|
|
fb2310b48a | ||
|
|
247e9a4f09 | ||
|
|
c1ec1ada0e | ||
|
|
d030dbd61c | ||
|
|
bebd56ee21 | ||
|
|
75586eec0e | ||
|
|
659343d287 | ||
|
|
8e63c72867 | ||
|
|
65416bb8b6 | ||
|
|
71a647b66b | ||
|
|
fc57e9dde0 | ||
|
|
4acfe0975c | ||
|
|
158e8ead50 | ||
|
|
0fc69c4d9e | ||
|
|
e314bf03ce | ||
|
|
6f2decdacf | ||
|
|
4bd3e09a0d | ||
|
|
a16f508b8a | ||
|
|
1642db3441 | ||
|
|
b389079417 | ||
|
|
8f7be637b2 | ||
|
|
94c15aa0cc | ||
|
|
951c8952ff | ||
|
|
59f91a2405 | ||
|
|
f4a3d52654 | ||
|
|
517e177d7a | ||
|
|
e72184e9ee | ||
|
|
73348d69d2 | ||
|
|
15eff9e412 | ||
|
|
dd70cd5b40 | ||
|
|
b290f995d0 | ||
|
|
c1dd0e1e43 | ||
|
|
44a02c1f5f | ||
|
|
a0071b301b | ||
|
|
c77281f724 | ||
|
|
8a0578c93c | ||
|
|
c7dcb1daae | ||
|
|
af330fb61b | ||
|
|
ab64afa2a7 | ||
|
|
85792f9946 | ||
|
|
e0d4e63e48 | ||
|
|
b2bd9f4ca9 | ||
|
|
189356680b | ||
|
|
0e0cd2c950 | ||
|
|
a849a41367 | ||
|
|
4b1c13e5cb | ||
|
|
f3777b9306 | ||
|
|
3e5e12e1ac | ||
|
|
a50176c259 | ||
|
|
94e524a1e6 | ||
|
|
cb3259b23f | ||
|
|
ec811d3c4a | ||
|
|
bf67321336 | ||
|
|
4b71ef9354 | ||
|
|
23bf16a638 | ||
|
|
c3ada352f4 | ||
|
|
610bdc4aca | ||
|
|
6675f4645f | ||
|
|
2895bfe269 | ||
|
|
27e2d632cd | ||
|
|
abdaa7b5b3 | ||
|
|
e0ed1d6d61 | ||
|
|
f8b1287153 | ||
|
|
5ed50d68f2 | ||
|
|
2f0a6c01c2 | ||
|
|
c8edd6c795 | ||
|
|
2b8930a5bf | ||
|
|
7c89563108 | ||
|
|
fcb94bcecf | ||
|
|
593e9e0f2f | ||
|
|
4209dfaa7f | ||
|
|
0fac7be5b9 | ||
|
|
0936913bf6 | ||
|
|
03ebc320f1 | ||
|
|
ea11670593 | ||
|
|
607080857b | ||
|
|
6728fdb3b1 | ||
|
|
580c1b7be4 | ||
|
|
03a43d09a4 | ||
|
|
7f043d7b07 | ||
|
|
77a8c6667f | ||
|
|
418a3f6978 | ||
|
|
6b300d2e4c | ||
|
|
50ae9d93a6 | ||
|
|
168ee37d30 | ||
|
|
81528d64d5 | ||
|
|
e6b8a133a8 | ||
|
|
047ca43b72 | ||
|
|
3c6509184a | ||
|
|
ec1ce4cf98 | ||
|
|
526478338d | ||
|
|
f49e6e8dc3 | ||
|
|
186d58eef7 | ||
|
|
d2bbc1b7c1 | ||
|
|
2a503b5c81 | ||
|
|
a25b918a67 | ||
|
|
821376f552 | ||
|
|
4387de4be8 | ||
|
|
0663b30528 | ||
|
|
37b0eb2c48 | ||
|
|
de0272abcf | ||
|
|
cfc3634108 | ||
|
|
1c62b1599d | ||
|
|
1d2ec17d52 | ||
|
|
0d9e8a0c3c | ||
|
|
9b28bb59c9 | ||
|
|
0fce559711 | ||
|
|
de191d213e | ||
|
|
ae89c307bf | ||
|
|
0dba7ba99b | ||
|
|
1b67c83359 | ||
|
|
d28465b656 | ||
|
|
bb3493bdf0 | ||
|
|
0cd8326f21 | ||
|
|
5c5c818bc5 | ||
|
|
124b99b2a4 | ||
|
|
1cabac151a | ||
|
|
df48b734a2 | ||
|
|
039d744960 | ||
|
|
004e8a4fcf | ||
|
|
d8f8acbe38 | ||
|
|
8a01f9ee09 | ||
|
|
315af061cd | ||
|
|
18491c933d | ||
|
|
d01c0232da | ||
|
|
91e32e3f02 | ||
|
|
88294f4161 | ||
|
|
9cdc23159a | ||
|
|
c95f1d95af | ||
|
|
45c87d392f | ||
|
|
1c0a4999b8 | ||
|
|
30bfc7bcea | ||
|
|
48f8c1c1c8 | ||
|
|
c47ea136b6 | ||
|
|
a3d30b2a89 | ||
|
|
11e15ff0f2 | ||
|
|
fb4b4fb14a | ||
|
|
0ede82e059 | ||
|
|
708b660c0b | ||
|
|
9f27bba490 | ||
|
|
095da2890e | ||
|
|
389d76cbc1 | ||
|
|
493cbc030c | ||
|
|
2f7b936cd6 | ||
|
|
6f3ee1eebf | ||
|
|
32f7b212bd | ||
|
|
4fcdabca90 | ||
|
|
b03de37155 | ||
|
|
73af713503 | ||
|
|
a903532cef | ||
|
|
d6178b3139 | ||
|
|
ec1241a6d8 | ||
|
|
ae819901ab | ||
|
|
3c0294cf3a | ||
|
|
21bc767445 | ||
|
|
47b6368ef7 | ||
|
|
a3098b5dfd | ||
|
|
bd69c9382f | ||
|
|
b47f43df59 | ||
|
|
e9217d02f0 | ||
|
|
6741c8420a | ||
|
|
fe45847841 | ||
|
|
5d13b87dd3 | ||
|
|
e1f5fbdc33 | ||
|
|
b342cf683b | ||
|
|
e94946cc8c | ||
|
|
8604ca1b85 | ||
|
|
9847f57ce7 | ||
|
|
74e2c4cbcb | ||
|
|
7b54159af3 | ||
|
|
16ad9c868e | ||
|
|
26f4ad3db2 | ||
|
|
715928e143 | ||
|
|
40d694e893 | ||
|
|
4d84fb97c9 | ||
|
|
ab7bb7a82d | ||
|
|
171be40a1f | ||
|
|
18d4a8a0f8 | ||
|
|
dedaa7e617 | ||
|
|
6173ae42a9 | ||
|
|
792604127e | ||
|
|
81d0aaf7bc | ||
|
|
26c495e5b3 | ||
|
|
a1f8717170 | ||
|
|
460a38b994 | ||
|
|
dbefae706c | ||
|
|
a33e82af60 | ||
|
|
8f283b3c2b | ||
|
|
b1ae3a98e8 | ||
|
|
fcaaa68f87 | ||
|
|
b7622b7407 | ||
|
|
a56358c8f8 | ||
|
|
dafe4bea1a | ||
|
|
408a6cb70e | ||
|
|
97c0ddbee4 | ||
|
|
330502ea1e | ||
|
|
662118b5c6 | ||
|
|
8bee2291fd | ||
|
|
39c4db3e66 | ||
|
|
749b1034f9 | ||
|
|
735102d4a0 | ||
|
|
5e30d7486e | ||
|
|
71f864bc5c | ||
|
|
b31c1a11d5 | ||
|
|
bf03f733a6 | ||
|
|
ca04d699bc | ||
|
|
530aaaae38 | ||
|
|
36970f3240 | ||
|
|
7c97dc8131 | ||
|
|
a7336c2c5e | ||
|
|
8866935d0b | ||
|
|
4f06c2392b | ||
|
|
677113cfbe | ||
|
|
a01faf1bb8 | ||
|
|
050b43757f | ||
|
|
448c4b21b5 | ||
|
|
84d8dea5ba | ||
|
|
5fa5b680f0 | ||
|
|
5b26427079 | ||
|
|
d426d2ca88 | ||
|
|
2e5bc32b33 | ||
|
|
b0b975e8ef | ||
|
|
1f4df63577 | ||
|
|
cf7c218a65 | ||
|
|
1a1751b45d | ||
|
|
0354c2fcc3 | ||
|
|
1679cd2fff | ||
|
|
32db9f2e71 | ||
|
|
6b98bee683 | ||
|
|
7de77cf13c | ||
|
|
8334f4e68a | ||
|
|
1ac7e7129d | ||
|
|
daec1268f9 | ||
|
|
c47bd34760 | ||
|
|
0d9ebfc820 | ||
|
|
3332d8df66 | ||
|
|
852c173c96 | ||
|
|
bcf30f2dfc | ||
|
|
2ea1aec7fd | ||
|
|
dc5a26c5d3 | ||
|
|
3c8f164371 | ||
|
|
93c14be188 | ||
|
|
b305cc29fc | ||
|
|
c2001fb9d2 | ||
|
|
d3a8321be0 | ||
|
|
8bfd588b4c | ||
|
|
5268fd3749 | ||
|
|
19bbd85d9d | ||
|
|
deca987299 | ||
|
|
1a4eed3b69 | ||
|
|
1214f99227 | ||
|
|
51530e03a5 | ||
|
|
66263dd7b3 | ||
|
|
6b0ce64d5e | ||
|
|
3b080058ed | ||
|
|
00996a2a02 | ||
|
|
c0299f4a1e | ||
|
|
e09105de98 |
8
README.md
Normal file
8
README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
thread
|
||||
======
|
||||
|
||||
Portable C++ multi-threading. C++11, C++14.
|
||||
|
||||
### License
|
||||
|
||||
Distributed under the [Boost Software License, Version 1.0](http://boost.org/LICENSE_1_0.txt).
|
||||
@@ -36,6 +36,7 @@ import os ;
|
||||
import feature ;
|
||||
import indirect ;
|
||||
import path ;
|
||||
import configure ;
|
||||
|
||||
project boost/thread
|
||||
: source-location ../src
|
||||
@@ -84,12 +85,12 @@ project boost/thread
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
<toolset>clang:<cxxflags>-Wno-variadic-macros
|
||||
|
||||
<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>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>gcc:<cxxflags>-Wno-missing-field-initializers
|
||||
|
||||
<toolset>darwin-4.6.2:<cxxflags>-Wno-delete-non-virtual-dtor
|
||||
@@ -140,6 +141,8 @@ local rule default_threadapi ( )
|
||||
feature.feature threadapi : pthread win32 : propagated ;
|
||||
feature.set-default threadapi : [ default_threadapi ] ;
|
||||
|
||||
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
|
||||
|
||||
rule tag ( name : type ? : property-set )
|
||||
{
|
||||
local result = $(name) ;
|
||||
@@ -236,10 +239,10 @@ rule usage-requirements ( properties * )
|
||||
}
|
||||
}
|
||||
|
||||
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.1 in $(properties)
|
||||
{
|
||||
#if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.1 in $(properties)
|
||||
#{
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
#}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -264,16 +267,15 @@ rule requirements ( properties * )
|
||||
}
|
||||
}
|
||||
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
|
||||
if ! [ configure.builds has_atomic_flag_lockfree
|
||||
: $(properties) : "lockfree boost::atomic_flag" ] {
|
||||
result += <library>/boost/atomic//boost_atomic ;
|
||||
}
|
||||
} else {
|
||||
result += <define>BOOST_THREAD_USES_CHRONO ;
|
||||
result += <library>/boost/chrono//boost_chrono ;
|
||||
}
|
||||
|
||||
if <toolset>pgi in $(properties) || <toolset>vacpp in $(properties)
|
||||
{
|
||||
result += <library>/boost/atomic//boost_atomic ;
|
||||
}
|
||||
|
||||
return $(result) ;
|
||||
}
|
||||
|
||||
|
||||
13
build/has_atomic_flag_lockfree_test.cpp
Normal file
13
build/has_atomic_flag_lockfree_test.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
|
||||
//
|
||||
// Use modification and distribution are subject to the boost Software
|
||||
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
|
||||
|
||||
#include "../../../boost/atomic.hpp"
|
||||
#include "../../../boost/static_assert.hpp"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
|
||||
return 0;
|
||||
}
|
||||
956
doc/async_executors.qbk
Normal file
956
doc/async_executors.qbk
Normal file
@@ -0,0 +1,956 @@
|
||||
[/
|
||||
/ Copyright (c) 2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:executors Executors and Schedulers -- EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from tis paper to show the differences.]
|
||||
|
||||
Executors are objects that can execute units of work packaged as function objects. Boost.Thread differs from N3785 mainly in the an Executor doesn't needs to inherit from an abstract class Executor. Static polymorphism is used instead and type erasure is used internally.
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
Multithreaded programs often involve discrete (sometimes small) units of work that are executed asynchronously. This often involves passing work units to some component that manages execution. We already have boost::async, which potentially executes a function asynchronously and eventually returns its result in a future. (“As if” by launching a new thread.)
|
||||
|
||||
If there is a regular stream of small work items then we almost certainly don’t want to launch a new thread for each, and it’s likely that we want at least some control over which thread(s) execute which items. It is often convenient to represent that control as multiple executor objects. This allows programs to start executors when necessary, switch from one executor to another to control execution policy, and use multiple executors to prevent interference and thread exhaustion. Several possible implementations exist of the executor class and in practice there are a number of main groups of executors which have been found to be useful in real-world code (more implementations exist, this is simply a high level classification of them). These differ along a couple main dimensions, how many execution contexts will be used, how they are selected, and how they are prioritized.
|
||||
|
||||
# Thread Pools
|
||||
# Simple unbounded thread pool, which can queue up an unbounded amount of work and maintains a dedicated set of threads (up to some maximum) which
|
||||
dequeue and execute work as available.
|
||||
# Bounded thread pools, which can be implemented as a specialization of the previous ones with a bounded queue or semaphore, which limits the amount of queuing in an attempt to bound the time spent waiting to execute and/or limit resource utilization for work tasks which hold state which is expensive to hold.
|
||||
# Thread-spawning executors, in which each work always executes in a new thread.
|
||||
# Prioritized thread pools, which have works which are not equally prioritized such that work can move to the front of the execution queue if necessary. This requires a special comparator or prioritization function to allow for work ordering and normally is implemented as a blocking priority queue in front of the pool instead of a blocking queue. This has many uses but is a somewhat specialized in nature and would unnecessarily clutter the initial interface.
|
||||
# Work stealing thread pools, this is a specialized use case and is encapsulated in the ForkJoinPool in java, which allows lightweight work to be created by tasks in the pool and either run by the same thread for invocation efficiency or stolen by another thread without additional work. These have been left out until there is a more concrete fork-join proposal or until there is a more clear need as these can be complicated to implement
|
||||
|
||||
# Mutual exclusion executors
|
||||
# Serial executors, which guarantee all work to be executed such that no two works will execute concurrently. This allows for a sequence of operations to be queued in sequence and that sequential order is maintained and work can be queued on a separate thread but with no mutual exclusion required.
|
||||
# Loop executor, in which one thread donates itself to the executor to execute all queued work. This is related to the serial executor in that it guarantees mutual exclusion, but instead guarantees a particular thread will execute the work. These are particularly useful for testing purposes where code assumes an executor but testing code desires control over execution.
|
||||
# GUI thread executor, where a GUI framework can expose an executor interface to allow other threads to queue up work to be executed as part of the GUI thread. This behaves similarly to a loop executor, but must be implemented as a custom interface as part of the framework.
|
||||
|
||||
# Inline executors, which execute inline to the thread which calls submit(). This has no queuing and behaves like a normal executor, but always uses the caller’s thread to execute. This allows parallel execution of works, though. This type of executor is often useful when there is an executor required by an interface, but when for performance reasons it’s better not to queue work or switch threads. This is often very useful as an optimization for work continuations which should execute immediately or quickly and can also be useful for optimizations when an interface requires an executor but the work tasks are too small to justify the overhead of a full thread pool.
|
||||
|
||||
A question arises of which of these executors (or others) be included in this library. There are use cases for these and many other executors. Often it is useful to have more than one implemented executor (e.g. the thread pool) to have more precise control of where the work is executed due to the existence of a GUI thread, or for testing purposes. A few core executors are frequently useful and these have been outlined here as the core of what should be in this library, if common use cases arise for alternative executor implementations, they can be added in the future. The current set provided here are: a basic thread pool `basic_thread_pool`, a serial executor `serial_executor`, a loop executor `loop_executor`, an inline executor `inline_executor` and a thread-spawning executor `thread_executor`.
|
||||
[endsect]
|
||||
|
||||
[/
|
||||
[/////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
|
||||
[endsect]
|
||||
]
|
||||
[////////////////]
|
||||
[section:examples Examples]
|
||||
|
||||
[section:quick_sort Parallel Quick Sort]
|
||||
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
template<typename T>
|
||||
struct sorter
|
||||
{
|
||||
boost::basic_thread_pool pool;
|
||||
typedef std::list<T> return_type;
|
||||
|
||||
std::list<T> do_sort(std::list<T> chunk_data)
|
||||
{
|
||||
if(chunk_data.empty()) {
|
||||
return chunk_data;
|
||||
}
|
||||
|
||||
std::list<T> result;
|
||||
result.splice(result.begin(),chunk_data, chunk_data.begin());
|
||||
T const& partition_val=*result.begin();
|
||||
|
||||
typename std::list<T>::iterator divide_point =
|
||||
std::partition(chunk_data.begin(), chunk_data.end(),
|
||||
[&](T const& val){return val<partition_val;});
|
||||
|
||||
std::list<T> new_lower_chunk;
|
||||
new_lower_chunk.splice(new_lower_chunk.end(), chunk_data,
|
||||
chunk_data.begin(), divide_point);
|
||||
boost::future<std::list<T> > new_lower =
|
||||
boost::async(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
|
||||
std::list<T> new_higher(do_sort(chunk_data));
|
||||
result.splice(result.end(),new_higher);
|
||||
while(!new_lower.is_ready()) {
|
||||
pool.schedule_one_or_yield();
|
||||
}
|
||||
result.splice(result.begin(),new_lower.get());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
std::list<T> parallel_quick_sort(std::list<T>& input) {
|
||||
if(input.empty()) {
|
||||
return input;
|
||||
}
|
||||
sorter<T> s;
|
||||
return s.do_sort(input);
|
||||
}
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[////////////////////////]
|
||||
[section:rationale Design Rationale]
|
||||
|
||||
The authors of Boost.Thread have taken a different approach respect to N3785. Instead of basing all the design on a abstract executor class we make executor concepts. We believe that this is the good direction as a static polymorphic executor can be seen as a dynamic polymorphic executor using a simple adaptor. We believe also that it would make the library more usable, and more convenient for users.
|
||||
|
||||
The major design decisions concern deciding what a unit of work is, how to manage with units of work and time related functions in a polymorphic way.
|
||||
|
||||
An Executor is an object that schedules the closures that have been submitted to it, usually asynchronously. There could be multiple models of the Executor class. Some specific design notes:
|
||||
|
||||
* Thread pools are well know models of the Executor concept, and this library does indeed include a basic_thread_pool class, but other implementations also exist, including the ability to schedule work on GUI threads, scheduling work on a donor thread, as well as several specializations of thread pools.
|
||||
|
||||
* The choice of which executor to use is explicit. This is important for reasons described in the Motivation section. In particular, consider the common case of an asynchronous operation that itself spawns asynchronous operations. If both operations ran on the same executor, and if that executor had a bounded number of worker threads, then we could get deadlock. Programs often deal with such issues by splitting different kinds of work between different executors.
|
||||
|
||||
* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable a robust way.
|
||||
|
||||
* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is suing without making it a template and it possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
|
||||
|
||||
* Conceptually, an executor puts closures on a queue and at some point executes them. The queue is always unbounded, so adding a closure to an executor never blocks. (Defining “never blocks” formally is challenging, but informally we just mean that submit() is an ordinary function that executes something and returns, rather than waiting for the completion of some potentially long running operation in another thread.)
|
||||
|
||||
[heading Closure]
|
||||
|
||||
One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `voidv.
|
||||
|
||||
N3785 choose the more specific `std::function<void()>` as it provides only dynamic polymorphism and states that in practice the implementation of a template based approach or another approach is impractical. The authors of this library think that the template based approach is compatible with a dynamic based approach. They give some arguments:
|
||||
|
||||
The first one is that a virtual function can not be a template. This is true but it is also true that the executor interface can provide the template functions that call to the virtual public functions. Another reason they give is that "a template parameter would complicate the interface without adding any real generality. In the end an executor class is going to need some kind of type erasure to handle all the different kinds of function objects with `void()` signature, and that’s exactly what std::function already does". We think that it is up to the executor to manage with this implementation details, not to the user.
|
||||
|
||||
We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what is needs.
|
||||
|
||||
The third one is related to performance. They assert that "any mechanism for storing closures on an executor’s queue will have to use some form of type erasure. There’s no reason to believe that a custom closure mechanism, written just for std::executor and used nowhere else within the standard library, would be better in that respect than `std::function<void()>`". We believe that the implementation can do better that storing the closure on a `std::function<void()>`. e.g. the implementation can use intrusive data to store the closure and the pointers to other nodes needed to store the closures in a given order.
|
||||
|
||||
In addition `std::function<void()>` can not be constructed by moving the closure, so e.g. `std::packaged_task` could not be a Closure.
|
||||
|
||||
[/
|
||||
[heading Scheduled work]
|
||||
|
||||
The approach of this library respect to scheduled work of the N3785 proposal is quite different. Instead of adding the scheduled operations to a specific scheduled_executor polymorphic interface, we opt by adding two member template functions to a class scheduled_executor that wraps an existing executor. This has several advantages:
|
||||
|
||||
* The scheduled operations are available for all the executors.
|
||||
* The template functions could accept any chrono `time_point` and `duration` respectively as we are not working with virtual functions.
|
||||
|
||||
In order to manage with all the clocks, there are two alternatives:
|
||||
|
||||
* transform the submit_at operation to a `submit_after` operation and let a single `scheduled_executor` manage with a single clock.
|
||||
* have a single instance of a `scheduled_executor<Clock>` for each `CLock`.
|
||||
|
||||
The library chose the first of those options, largely for simplicity.
|
||||
]
|
||||
|
||||
[heading Not Handled Exceptions]
|
||||
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
|
||||
Note that when we combine `boost::async` and `Executors`, the exception will be caught by the closure associated to the returned future, so that the exception is stored on the returned future, as for the other `async` overloads.
|
||||
|
||||
[heading At thread entry]
|
||||
|
||||
It is common idiom to set some thread local variable at the beginning of a thread. As Executors could instantiate threads internally these Executors shall have the ability to call a user specific function at thread entry on the executor constructor.
|
||||
|
||||
For executors that don't instantiate any thread an that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
|
||||
|
||||
[heading Cancelation]
|
||||
|
||||
The library does not provision yet for the ability to cancel/interrupt work, though this is a commonly requested feature.
|
||||
|
||||
This could be managed externally by an additional cancelation object that can be shared between the creator of the unit of work and the unit of work.
|
||||
|
||||
We can think also of a cancelable closure that could be used in a more transparent way.
|
||||
|
||||
An alternative is to make async return a cancelable_task but this will need also a cancelable closure.
|
||||
|
||||
|
||||
[/
|
||||
The library would provide in the future a cancelable_task that could support cancelation.
|
||||
|
||||
class cancelation_state {
|
||||
std::atomic<bool> requested; std::atomic<bool> enabled; std::condition_variable* cond; std::mutex cond_mutex;
|
||||
public:
|
||||
cancelation_state(): thread_cond(0) {} void cancel() { requested.store(true,std::memory_order_relaxed); std::lock_guard<std::mutex> lk(cond_mutex); if(cond) { cond->notify_all(); } } bool cancellation_requested() const { return requested.load(std::memory_order_relaxed); }
|
||||
void enable() { enable.store(true,std::memory_order_relaxed); } void disable() { enable.store(false,std::memory_order_relaxed); } bool cancellation_enabled() const { return enabled.load(std::memory_order_relaxed); } void set_condition_variable(std::condition_variable& cv) { std::lock_guard<std::mutex> lk(cond_mutex); cond = &cv; } void clear_condition_variable() { std::lock_guard<std::mutex> lk(cond_mutex); cond = 0; } struct clear_cv_on_destruct { ~clear_cv_on_destruct() { this_thread_interrupt_flag.clear_condition_variable(); } };
|
||||
void cancelation_point();
|
||||
void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { cancelation_point(); this_cancelable_state.set_condition_variable(cv); this_cancelable_state::clear_cv_on_destruct guard; interruption_point();
|
||||
cv.wait_for(lk, std::chrono::milliseconds(1)); this_cancelable_state.clear_condition_variable(); cancelation_point(); }
|
||||
class disable_cancelation
|
||||
{
|
||||
public:
|
||||
disable_cancelation(const disable_cancelation&) = delete;
|
||||
disable_cancelation& operator=(const disable_cancelation&) = delete;
|
||||
disable_cancelation(cancelable_closure& closure) noexcept;
|
||||
~disable_cancelation() noexcept;
|
||||
};
|
||||
class restore_cancelation
|
||||
{
|
||||
public:
|
||||
restore_cancelation(const restore_cancelation&) = delete;
|
||||
restore_cancelation& operator=(const restore_cancelation&) = delete;
|
||||
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
|
||||
~restore_cancelation() noexcept;
|
||||
};
|
||||
};
|
||||
|
||||
template <class Closure>
|
||||
struct cancelable_closure_mixin : cancelable_closure {
|
||||
void operator() {
|
||||
cancel_point();
|
||||
this->Closure::run();
|
||||
}
|
||||
};
|
||||
|
||||
struct my_clousure : cancelable_closure_mixin<my_clousure>
|
||||
{
|
||||
void run() {
|
||||
while () {
|
||||
cancel_point();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
]
|
||||
|
||||
[heading Current executor]
|
||||
|
||||
The library does not provision for the ability to get the current executor, though having access to it could simplify a lot the user code.
|
||||
|
||||
The reason is that the user can always use a thread_local variable and reset it using the `at_thread_entry ` member function.
|
||||
|
||||
thread_local current_executor_state_type current_executor_state;
|
||||
executor* current_executor() { return current_executor_state.current_executor(); }
|
||||
basic_thread_pool pool(
|
||||
// at_thread_entry
|
||||
[](basic_thread_pool& pool) {
|
||||
current_executor_state.set_current_executor(pool);
|
||||
}
|
||||
);
|
||||
|
||||
[heading Default executor]
|
||||
|
||||
The library authors share some of the concerns of the C++ standard committee (introduction of a new single shared resource, a singleton, could make it difficult to make it portable to all the environments) and that this library doesn't need to provide a default executor for the time been.
|
||||
|
||||
The user can always define his default executor himself and use the `at_thread_entry ` member function to set the default constructor.
|
||||
|
||||
thread_local default_executor_state_type default_executor_state;
|
||||
executor* default_executor() { return default_executor_state.default_executor(); }
|
||||
|
||||
// in main
|
||||
MyDefaultExecutor myDefaultExecutor(
|
||||
// at_thread_entry
|
||||
[](MyDefaultExecutor& ex) {
|
||||
default_executor_state.set_default_executor(ex);
|
||||
}
|
||||
);
|
||||
|
||||
basic_thread_pool pool(
|
||||
// at_thread_entry
|
||||
[&myDefaultExecutor](basic_thread_pool& pool) {
|
||||
default_executor_state.set_default_executor(myDefaultExecutor);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////]
|
||||
[section:ref Reference]
|
||||
|
||||
|
||||
[////////////////////////////////]
|
||||
[section:concept_closure Concept `Closure`]
|
||||
|
||||
|
||||
A type `E` meets the `Closure` requirements if is a model of `Callable(void())` and a model of `CopyConstructible`/`MoveConstructible`.
|
||||
|
||||
[endsect]
|
||||
[////////////////////////////////]
|
||||
[section:concept_executor Concept `Executor`]
|
||||
|
||||
The `Executor` concept models the common operations of all the executors.
|
||||
|
||||
A type `E` meets the `Executor` requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `E::work`
|
||||
* `e.submit(lw);`
|
||||
* `e.submit(rw);`
|
||||
* `e.submit(lc);`
|
||||
* `e.submit(rc);`
|
||||
* `e.close();`
|
||||
* `b = e.closed();`
|
||||
* `e.try_executing_one();`
|
||||
* `e.reschedule_until(p);`
|
||||
|
||||
where
|
||||
|
||||
* `e` denotes a value of type `E`,
|
||||
* `lw` denotes a lvalue referece of type `E::work`,
|
||||
* `rc` denotes a rvalue referece of type `E::work`
|
||||
* `lc` denotes a lvalue referece of type `Closure`,
|
||||
* `rc` denotes a rvalue referece of type `Closure`
|
||||
* `p` denotes a value of type `Predicate`
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:submitlw `e.submit(lw);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitrw `e.submit(rw);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitlc `e.submit(lc);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:submitrc `e.submit(lc);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
|
||||
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
|
||||
|
||||
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:close `e.close();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [close the executor `e` for submissions.]]
|
||||
|
||||
[[Remark:] [The worker threads will work until there is no more closures to run.]]
|
||||
|
||||
[[Return type:] [`void`.]]
|
||||
|
||||
[[Throws:] [Whatever exception that can be throw while ensuring the thread safety.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:close `b = e.close();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [`void`.]]
|
||||
|
||||
[[Throws:] [whether the pool is closed for submissions.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_executing_one `e.try_executing_one();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [try to execute one work.]]
|
||||
|
||||
[[Remark:] [whether a work has been executed.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Whether a work has been executed.]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_executing_one `e.reschedule_until(p);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [This must be called from an scheduled work]]
|
||||
|
||||
[[Effects:] [reschedule works until `p()`.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Whether a work has been executed.]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////]
|
||||
[section:work Class `work`]
|
||||
|
||||
#include <boost/thread/work.hpp>
|
||||
namespace boost {
|
||||
typedef 'implementation_defined' work;
|
||||
}
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [work is a model of 'Closure']]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////]
|
||||
[section:executor Class `executor`]
|
||||
|
||||
Executor abstract base class.
|
||||
|
||||
#include <boost/thread/executor.hpp>
|
||||
namespace boost {
|
||||
class executor
|
||||
{
|
||||
public:
|
||||
typedef boost::work work;
|
||||
|
||||
executor(executor const&) = delete;
|
||||
executor& operator=(executor const&) = delete;
|
||||
|
||||
executor();
|
||||
virtual ~executor() {};
|
||||
|
||||
virtual void close() = 0;
|
||||
virtual bool closed() = 0;
|
||||
|
||||
virtual void submit(work&& closure) = 0;
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
virtual bool try_executing_one() = 0;
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `executor()`]
|
||||
|
||||
executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Destructor `~executor()`]
|
||||
|
||||
virtual ~executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:executor_adaptor Template Class `executor_adaptor`]
|
||||
|
||||
Polymorphic adaptor of a model of Executor to an executor.
|
||||
|
||||
#include <boost/thread/executor.hpp>
|
||||
namespace boost {
|
||||
template <typename Executor>
|
||||
class executor_adaptor : public executor
|
||||
{
|
||||
Executor ex; // for exposition only
|
||||
public:
|
||||
typedef executor::work work;
|
||||
|
||||
executor_adaptor(executor_adaptor const&) = delete;
|
||||
executor_adaptor& operator=(executor_adaptor const&) = delete;
|
||||
|
||||
template <typename ...Args>
|
||||
executor_adaptor(Args&& ... args);
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `executor_adaptor(Args&& ...)`]
|
||||
|
||||
template <typename ...Args>
|
||||
executor_adaptor(Args&& ... args);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a executor_adaptor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~executor_adaptor()`]
|
||||
|
||||
virtual ~ executor_adaptor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the executor_adaptor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:scheduled_executor Template Class `scheduled_executor`]
|
||||
|
||||
Executor providing time related functions.
|
||||
|
||||
#include <boost/thread/scheduled_executor.hpp>
|
||||
namespace boost {
|
||||
template <class Executor>
|
||||
class scheduled_executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
typedef executor::work work;
|
||||
|
||||
scheduled_executor(scheduled_executor const&) = delete;
|
||||
scheduled_executor& operator=(scheduled_executor const&) = delete;
|
||||
|
||||
template <class Rep, class Period>
|
||||
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
template <class Clock, class Duration>
|
||||
void submit_at(chrono::time_point<Clock,Duration> abs_time, work&& closure);
|
||||
template <class Rep, class Period>
|
||||
void submit_after(chrono::duration<Rep,Period> rel_time, work&& closure);
|
||||
template <class Clock, class Duration, typename Closure>
|
||||
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
|
||||
template <class Rep, class Period, typename Closure>
|
||||
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `scheduled_executor(Executor&, chrono::duration<Rep, Period>)`]
|
||||
|
||||
template <class Rep, class Period>
|
||||
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a scheduled_executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~scheduled_executor()`]
|
||||
|
||||
~scheduled_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the executor_adaptor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:scheduled_executor Template Class `serial_executor`]
|
||||
|
||||
A serial executor ensuring that there are no two work units that executes concurrently.
|
||||
|
||||
#include <boost/thread/serial_executor.hpp>
|
||||
namespace boost {
|
||||
template <class Executor>
|
||||
class serial_executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
typedef executors::work work;
|
||||
|
||||
serial_executor(serial_executor const&) = delete;
|
||||
serial_executor& operator=(serial_executor const&) = delete;
|
||||
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
void submit(work&& closure);
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `serial_executor(Executor&, chrono::duration<Rep, Period>)`]
|
||||
|
||||
serial_executor(Executor& ex);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a serial_executor. ]]
|
||||
|
||||
[[Throws:] [Nothing. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~serial_executor()`]
|
||||
|
||||
~serial_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the serial_executor.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:underlying_executor Function member `underlying_executor()`]
|
||||
|
||||
Executor& underlying_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [The underlying executor instance. ]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[///////////////////////////////////////]
|
||||
[section:basic_thread_pool Class `basic_thread_pool`]
|
||||
|
||||
A thread pool with up to a fixed number of threads.
|
||||
|
||||
#include <boost/thread/work.hpp>
|
||||
namespace boost {
|
||||
class basic_thread_pool
|
||||
{
|
||||
public:
|
||||
typedef boost::work work;
|
||||
|
||||
basic_thread_pool(basic_thread_pool const&) = delete;
|
||||
basic_thread_pool& operator=(basic_thread_pool const&) = delete;
|
||||
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency());
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
|
||||
~basic_thread_pool();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `basic_thread_pool(unsigned const)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [creates a thread pool that runs closures on `thread_count` threads. ]]
|
||||
|
||||
[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~basic_thread_pool()`]
|
||||
|
||||
virtual ~basic_thread_pool();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the thread pool.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////]
|
||||
[section:loop_executor Class `loop_executor`]
|
||||
|
||||
A user scheduled executor.
|
||||
|
||||
#include <boost/thread/loop_executor.hpp>
|
||||
namespace boost {
|
||||
class loop_executor
|
||||
{
|
||||
public:
|
||||
typedef thread_detail::work work;
|
||||
|
||||
loop_executor(loop_executor const&) = delete;
|
||||
loop_executor& operator=(loop_executor const&) = delete;
|
||||
|
||||
loop_executor();
|
||||
~loop_executor();
|
||||
|
||||
void close();
|
||||
bool closed();
|
||||
|
||||
template <typename Closure>
|
||||
void submit(Closure&& closure);
|
||||
|
||||
bool try_executing_one();
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred);
|
||||
|
||||
void loop();
|
||||
void run_queued_closures();
|
||||
};
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `loop_executor()`]
|
||||
|
||||
loop_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [creates a executor that runs closures using one of its closure-executing methods. ]]
|
||||
|
||||
[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:destructor Destructor `~loop_executor()`]
|
||||
|
||||
virtual ~loop_executor();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Destroys the thread pool.]]
|
||||
|
||||
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
|
||||
|
||||
]
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:loop Function member `loop()`]
|
||||
|
||||
void loop();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [reschedule works until `closed()` or empty. ]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:run_queued_closures Function member `run_queued_closures()`]
|
||||
|
||||
void run_queued_closures();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return:] [reschedule the enqueued works. ]]
|
||||
|
||||
[[Throws:] [whatever the current work constructor throws or the `work()` throws.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
@@ -1,11 +1,12 @@
|
||||
[/
|
||||
(C) Copyright 2007-8 Anthony Williams.
|
||||
(C) Copyright 2013 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:barriers Barriers]
|
||||
[section:barriers Barriers -- EXTENSION]
|
||||
|
||||
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
|
||||
@@ -22,14 +23,18 @@ arrived. Once the `n`-th thread has reached the barrier, all the waiting threads
|
||||
barrier& operator=(barrier const&) = delete;
|
||||
|
||||
barrier(unsigned int count);
|
||||
template <typename F>
|
||||
barrier(unsigned int count, F&&);
|
||||
|
||||
~barrier();
|
||||
|
||||
bool wait();
|
||||
void count_down_and_wait();
|
||||
};
|
||||
|
||||
Instances of __barrier__ are not copyable or movable.
|
||||
|
||||
[heading Constructor]
|
||||
[section Constructor `barrier(unsigned int)`]
|
||||
|
||||
barrier(unsigned int count);
|
||||
|
||||
@@ -41,7 +46,24 @@ Instances of __barrier__ are not copyable or movable.
|
||||
|
||||
]
|
||||
|
||||
[heading Destructor]
|
||||
[endsect]
|
||||
[section Constructor `barrier(unsigned int, F&&)`]
|
||||
|
||||
barrier(unsigned int count, F&& completion);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [The result type of the completion function call `completion()` is `void` or `unsigned int`.]]
|
||||
|
||||
[[Effects:] [Construct a barrier for `count` threads and a completion function `completion`.]]
|
||||
|
||||
[[Throws:] [__thread_resource_error__ if an error occurs.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[section Destructor `~barrier()`]
|
||||
|
||||
~barrier();
|
||||
|
||||
@@ -55,24 +77,55 @@ Instances of __barrier__ are not copyable or movable.
|
||||
|
||||
]
|
||||
|
||||
[heading Member function `wait`]
|
||||
[endsect]
|
||||
[section 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. ]]
|
||||
[[Effects:] [Block until `count` threads have called `wait` or `count_down_and_wait` on `*this`. When the `count`-th thread calls `wait`, the barrier is reset and all waiting threads are unblocked.
|
||||
The reset depends on whether the barrier was constructed with a completion function or not. If there is no completion function or if the completion function result is void, the reset consists in restoring the original count. Otherwise the rest consist in assigning the result of the completion function (which must not be 0).]]
|
||||
|
||||
[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
|
||||
|
||||
[[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.]]
|
||||
[[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.
|
||||
|
||||
]]
|
||||
|
||||
[[Notes:] [`wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section Member Function `count_down_and_wait()`]
|
||||
|
||||
void count_down_and_wait();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Block until `count` threads have called `wait` or `count_down_and_wait` on `*this`. When the `count`-th thread calls `wait`, the barrier is reset and all waiting threads are unblocked.
|
||||
The reset depends on whether the barrier was constructed with a completion function or not. If there is no completion function or if the completion function result is void, the reset consists in restoring the original count. Otherwise the rest consist in assigning the result of the completion function (which must not be 0).]]
|
||||
|
||||
[[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.
|
||||
|
||||
]]
|
||||
|
||||
[[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
121
doc/changes.qbk
121
doc/changes.qbk
@@ -1,6 +1,6 @@
|
||||
[/
|
||||
(C) Copyright 2007-11 Anthony Williams.
|
||||
(C) Copyright 2011-13 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-14 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
@@ -8,23 +8,110 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[/
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
[heading Version 4.3.0 - boost 1.56]
|
||||
|
||||
[*New Features:]
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro:Add externally locked streams.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro:Add concurrent queue.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6782 #6782] call_once uses incorrect barrier intrinsic on Visual Studio
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9307 #9307] future::fallback_to assert with ERRORRRRR boost: mutex lock failed in pthread_mutex_lock: Invalid argument
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9308 #9308] future::async fails with terminate called throwing an exception when called with a lambda - clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9425 #9425] Boost promise & future does not use supplied allocator for value storage
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9558 #9558] future continuations unit test hangs in get()/pthread_cond_wait() on Mac 10.7/32-bit/x86/darwin-4.2.1
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/release/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries,
|
||||
* The experimental features of boost::future have some severe holes that make the program crash unexpectedly.
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro: Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8615 #8615] Async: Replace make_future/make_shared_future by make_ready_future.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8677 #8677] Async: Add future<>::get_or.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8678 #8678] Async: Add future<>::fallback_to.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
]
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9333 #9333] ex_scoped_thread compile fails on msvc-12.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9366 #9366] async(Executor, ...) fails to compile with msvc-10,11,12
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9402 #9402] test_excutor regression on msvc-10,11,12
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9404 #9404] ex_make_future regression error
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9471 #9471] Synchronization documentation nits
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9535 #9535] Missing exception safety might result in crash
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9618 #9618] try_join_for problem: program is not terminate.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9673 #9673] thread compilation with MingW/gcc on Windows gives errors
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9708 #9708] boost::condition_variable::timed_wait unexpectedly wakes up while should wait infinite
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9711 #9711] future continuation called twice
|
||||
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
|
||||
[*Know Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2442 #2442] Application statically linked with Boost.Thread crashes when Google Desktop is installed (Windows XP)
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3926 #3926] thread_specific_ptr + dlopen library causes a SIGSEGV.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4833 #4833] MinGW/test_tss_lib: Support of automatic tss cleanup for native threading API not available
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6782 #6782] call_once uses incorrect barrier intrinsic on Visual Studio
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7319 #7319] Take care of c++std-lib-32966 issue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8600 #8600] wait_for_any hangs, if called with multiple copies of shared_future referencing same task
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9307 #9307] future::fallback_to assert with ERRORRRRR boost: mutex lock failed in pthread_mutex_lock: Invalid argument
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9308 #9308] future::async fails with terminate called throwing an exception when called with a lambda - clang-darwin-asan11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9311 #9311] ex_lambda_future fails on msvc-11.0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9310 #9310] test_4648_lib fails on clang-darwin-asan11
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread trunk regression test] to see the current state.
|
||||
|
||||
[*Sever limitations:]
|
||||
|
||||
There are some severe bugs that prevent the use of the library on concrete contexts, in particular:
|
||||
|
||||
* on thread specific storage that prevent the library to be used with dynamic libraries,
|
||||
* The experimental features of boost::future have some severe holes that make the program crash unexpectedly.
|
||||
|
||||
[*New Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8615 #8615] Async: Replace make_future/make_shared_future by make_ready_future.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap and unwrapping constructor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8677 #8677] Async: Add future<>::get_or.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8678 #8678] Async: Add future<>::fallback_to.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8891 #8891] upgrade_to_unique_lock: missing mutex() function.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8955 #8955] Request for more efficient way to get exception_ptr from future.
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8768 #8768] win32 condition_variable::wait_until infinite wait in rare cases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8817 #8817] Boost Thread Windows CE _createthreadex handling breaks mingw w64.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8943 #8943] Failed to compile code using boost::call_once with Intel C++ Composer XE 2013 on Windows.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8931 #8931] Typos in external_locking reference.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9029 #9029] Misprint in documentation.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9037 #9037] gcc -Wshadow gives warnings in condition_variable{,_fwd}.hpp.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9041 #9041] Boost.Thread DSO's may need to link with Boost.Atomic.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9048 #9048] boost::scoped_thread useless ctor with variadic template arguments.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9079 #9079] Condition variable will wait forever for some timepoint values (Win).
|
||||
|
||||
[heading Version 4.1.0 - boost 1.54]
|
||||
|
||||
@@ -416,11 +503,7 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
|
||||
# Add some features based on C++ proposals, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Sync: Add a completion_latch class
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
|
||||
|
||||
# Add some of the extension proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf A Standardized Representation of Asynchronous Operations] or extension to them, in particular
|
||||
@@ -428,14 +511,10 @@ The following features will be included in next releases.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap.
|
||||
|
||||
# And some additional extensions related to futures as:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8677 #8677] Async: Add future<>::get_or.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8678 #8678] Async: Add future<>::fallback_to.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic shared_future::then.
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
(C) Copyright 2011-12 Vicente J. Botet Escriba.
|
||||
(C) Copyright 2011-2013 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
[section:cpp11 C++11 standard Thread library]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 standard]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 - Standard for Programming Language C++]]]
|
||||
|
||||
|
||||
[table C++11 standard Conformance
|
||||
@@ -73,24 +73,23 @@
|
||||
[[30.6.9] [Class template packaged_task] [Yes] [-] [-]]
|
||||
]
|
||||
|
||||
[/
|
||||
|
||||
[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] [-]]
|
||||
]
|
||||
|
||||
[/
|
||||
[[30.x] [Thread Local Storage] [-]]
|
||||
[[30.y] [Class thread_group] [-]]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:cxx14 C++14 standard Thread library - accepted changes]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.html C++14 on-going standard]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3797.html Working Draft, Standard for Programming Language C++]]
|
||||
|
||||
|
||||
[table [@http://isocpp.org/files/papers/N3659.html N3659 Shared locking in C++ revision 2] Conformance
|
||||
@@ -106,8 +105,8 @@
|
||||
|
||||
[section:latch C++ Latches and Barriers]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3659 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3666.html N3659 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3600 C++ Latches and Barriers]]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3817.html N3817 C++ Latches and Barriers]]
|
||||
|
||||
[table C++ Latches and Barriers Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
@@ -124,105 +123,103 @@
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Conceptual interface] [Partial] [ The interface provided has some differences respect to this proposal. All the functions having a queue_op_status are not provided. No lock-free concrete classes ]]
|
||||
[[X.1.1] [Basic Operations] [Partial] [ - ]]
|
||||
[[X.1.1.1] [push] [yes] [ - ]]
|
||||
[[X.1.1.2] [value_pop] [no] [ renamed pull with two flavors + a ptr_pull that returns a sharted_ptr<>. ]]
|
||||
[[X.1.1.1] [push] [yes] [ renamed push_back. ]]
|
||||
[[X.1.1.2] [value_pop] [no] [ renamed pull_front with two flavors. ]]
|
||||
[[X.1.2] [Non-waiting operations] [ - ] [ - ]]
|
||||
[[X.1.2.1] [try_push] [Partial] [ return bool instead ]]
|
||||
[[X.1.2.2] [try_pop] [Partial] [ renamed try_pull, returns null ]]
|
||||
[[X.1.2.1] [try_push] [yes] [ renamed try_push_back ]]
|
||||
[[X.1.2.2] [try_pop] [yes] [ renamed try_pull_back ]]
|
||||
[[X.1.3] [Non-blocking operations] [ - ] [ - ]]
|
||||
[[X.1.3.1] [nonblocking_push] [Partial] [ renamed try_push(no_block, ]]
|
||||
[[X.1.3.2] [nonblocking_pop] [Partial] [ renamed try_pop(no_block, ]]
|
||||
[[X.1.3.1] [nonblocking_push] [Yes] [ renamed nonblocking_push_back ]]
|
||||
[[X.1.3.2] [nonblocking_pop] [Yes] [ renamed nonblocking_pull_front ]]
|
||||
[[X.1.4] [Push-front operations] [No] [ - ]]
|
||||
[[X.1.5] [Closed queues] [Partial] [ - ]]
|
||||
[[X.1.5.1] [close] [Yes] [ - ]]
|
||||
[[X.1.5.2] [is_closed] [Yes] [ - ]]
|
||||
[[X.1.5.3] [wait_push] [Partial] [ - ]]
|
||||
[[X.1.5.4] [wait_pop] [Partial] [ - ]]
|
||||
[[X.1.5.2] [is_closed] [Yes] [ renamed closed ]]
|
||||
[[X.1.5.3] [wait_push] [Yes] [ renamed wait_push_back ]]
|
||||
[[X.1.5.4] [wait_pop] [Yes] [ renamed wait_pull_front ]]
|
||||
[[X.1.5.5] [wait_push_front] [no] [ - ]]
|
||||
[[X.1.5.6] [wait_pop] [Partial] [ - ]]
|
||||
[[X.1.5.6] [wait_pop_back] [no] [ - ]]
|
||||
[[X.1.5.6] [open] [no] [ - ]]
|
||||
[[X.1.6] [Empty and Full Queues] [Yes] [ - ]]
|
||||
[[X.1.6.1] [is_empty] [Yes] [ - ]]
|
||||
[[X.1.6.2] [is_full] [Yes] [ Added capacity ]]
|
||||
[[X.1.7] [Queue Names] [No] [ Not considere a must for the time been. ]]
|
||||
[[X.1.7] [Queue Names] [No] [ Not considered a must for the time been. ]]
|
||||
[[X.1.8] [Element Type Requirements] [Yes?] [ - ]]
|
||||
[[X.1.9] [Exception Handling] [Yes?] [ - ]]
|
||||
[[X.1.10] [Queue Ordering] [Yes?] [ - ]]
|
||||
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Move aware. ]]
|
||||
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Boost.Move aware. ]]
|
||||
[[X.2] [Concrete queues] [Partial] [ - ]]
|
||||
[[X.2.1] [Locking Buffer Queue] [Partial] [ classes sync_queue and a sync_bounded_queue. ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ - ]]
|
||||
[[X.2.1] [Lock-Free Buffer Queue] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Boost.Move aware. ]]
|
||||
[[X.3] [Additional Conceptual Tools] [No] [ - ]]
|
||||
[[X.3.1] [Fronts and Backs] [No] [ - ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ - ]]
|
||||
[[X.3.2] [Streaming Iterators] [No] [ - ]]
|
||||
[[X.3.3] [Storage Iterators] [No] [ - ]]
|
||||
[[X.3.4] [Binary Interfaces] [No] [ - ]]
|
||||
[[X.3.4] [Managed Indirection] [No] [ - ]]
|
||||
]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:executors Asynchronous Executors]
|
||||
|
||||
While Boost.Thread implementation of executors would not use dynamic polymorphism, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3378.pdf N3378 A preliminary proposal for work executors]]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3785.pdf N3785 Executors and Schedulers]]
|
||||
|
||||
[table Asynchronous Executors
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.X.1] [Class executor] [No] [ - ]]
|
||||
[[30.X.1.1] [add] [No] [ renamed with a function template submit ]]
|
||||
[[30.X.1.1] [num_of_pendin_closures] [??] [ ]]
|
||||
[[30.X.2] [Class sceduled_executor] [No] [ - ]]
|
||||
[[30.X.2.1] [add_at] [No] [ renamed with a function template submit_at ]]
|
||||
[[30.X.2.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
||||
[[30.X.3] [Executor utilities functions] [No] [ - ]]
|
||||
[[30.X.3.1] [default_executor] [No] [ - ]]
|
||||
[[30.X.3.2] [set_default_executor] [No] [ - ]]
|
||||
[[30.X.3.3] [singleton_inline_executor] [No] [ - ]]
|
||||
[[30.X.4] [Concrete executor classes] [No] [ - ]]
|
||||
[[30.X.4.1] [loop_executor] [No] [ - ]]
|
||||
[[30.X.4.1] [serial_executor] [No] [ - ]]
|
||||
[[30.X.4.1] [thread_pool] [No] [ #8513 ]]
|
||||
[[V.1.1] [Class executor] [Yes] [ - ]]
|
||||
[[V.1.1] [add] [Yes] [ renamed with a function template submit ]]
|
||||
[[V.1.1] [num_of_pendin_closures] [No] [ ]]
|
||||
[[V.1.2] [Class sceduled_executor] [No] [ - ]]
|
||||
[[V.1.2] [add_at] [No] [ renamed with a function template submit_at ]]
|
||||
[[V.1.2] [add_after] [No] [ renamed with a function template submit_after ]]
|
||||
[[V.2] [Concrete executor classes] [No] [ - ]]
|
||||
[[V.2.1] [thread_pool] [Yes] [ static version Basic_thread_pool, dynamic one execduler_adaptor<basic_thread_pool> ]]
|
||||
[[V.2.2] [serial_executor] [yes] [ - ]]
|
||||
[[V.2.3] [loop_executor] [Yes] [ static version loop_scheduler, dynamic one execduler_adaptor<loop_scheduler> ]]
|
||||
[[V.2.4] [inline_executor] [Yes] [ static version inline_executor, dynamic one execduler_adaptor<inline_executor> ]]
|
||||
[[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor<thread_executor> ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:async Improvements to std::future<T> and Related APIs]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3857.pdf N3857-Improvements to std::future<T> and Related APIs]]
|
||||
|
||||
[section:async A Standardized Representation of Asynchronous Operations]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf N3558 A Standardized Representation of Asynchronous Operations]]
|
||||
[note These functions are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
[note These functions are based on [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
|
||||
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[30.6.6] [Class template future] [Partial] [ - ]]
|
||||
[[30.6.6.1] [then] [Partial] [ executor interface missing #8516 ]]
|
||||
[[30.6.6.2] [unwrap] [Yes] [ - ]]
|
||||
[[30.6.6.3] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
|
||||
[[30.6.6] [then] [Yes] [ - ]]
|
||||
[[30.6.6] [unwrap] [Yes] [ - ]]
|
||||
[[30.6.6] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
|
||||
[[30.6.7.1] [then] [Yes] [ executor interface missing #8516 ]]
|
||||
[[30.6.7.2] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7.3] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_any] [No] [ #7446 ]]
|
||||
[[30.6.X] [Function template when_all] [No] [ #7447 ]]
|
||||
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
|
||||
[[30.6.7] [then] [Yes] [ - ]]
|
||||
[[30.6.7] [unwrap] [No] [ #XXXX ]]
|
||||
[[30.6.7] [ready] [Partial] [ is_ready ]]
|
||||
[[30.6.X] [Function template when_all] [Partial] [ interface not complete #7447 ]]
|
||||
[[30.6.X] [Function template when_any] [Partial] [ interface not complete #7446 ]]
|
||||
[[30.6.X] [Function template when_any_swaped] [No] [ #XXXX ]]
|
||||
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
|
||||
[[30.6.8] [Function template async ] [No] [ executor interface missing #7448 ]]
|
||||
[[30.6.8] [Function template async ] [Yes] [ - ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:stream_mutex C++ Stream Mutexes - C++ Stream Guards]
|
||||
|
||||
While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard.
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html N3535 - C++ Stream Mutexes]. This has been replaced already by N3678 - C++ Stream Guards.]
|
||||
[note These functions are based on [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html [*N3535 - C++ Stream Mutexes]] by Lawrence Crowl.]
|
||||
|
||||
[table C++ C++ Stream MutexesConformance
|
||||
[note This proposal has been replaced already by [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3678 - C++ Stream Guards], which has been replaced by [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3665 - Uninterleaved String Output Streaming] and [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3750 - C++ Ostream Buffers]]
|
||||
|
||||
[table C++ Stream Mutexes Conformance
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[X.1] [Class template stream_mutex] [Partial] [ externally_locked_stream<> ]]
|
||||
[[X.2.1] [constructor] [Partial] [ externally_locked_stream needs a mutex in addition as argumement. ]]
|
||||
[[X.1] [Class template stream_mutex] [Partial] [ Renamed externally_locked_stream<> ]]
|
||||
[[X.2.1] [constructor] [Partial] [ externally_locked_stream needs a mutex in addition as argument. ]]
|
||||
[[X.2.2] [lock] [yes] [ - ]]
|
||||
[[X.2.3] [unlock] [yes] [ - ]]
|
||||
[[X.2.4] [try_lock] [yes] [ - ]]
|
||||
@@ -232,12 +229,10 @@ While Boost.Thread implementation of stream mutexes differ in the approach, it i
|
||||
[[X.2.1] [stream_guard] [Yes] [ - ]]
|
||||
[[X.2.2] [~stream_guard] [Yes] [ - ]]
|
||||
[[X.2.3] [bypass] [Yes] [ - ]]
|
||||
[[X.3] [Stream Operators] [Yes] [.]]
|
||||
[[X.4] [Predefined Objects] [No] [.]]
|
||||
[[X.3] [Stream Operators] [Yes] [-]]
|
||||
[[X.4] [Predefined Objects] [No] [-]]
|
||||
]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3678 - C++ Stream Guards]]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -78,20 +78,28 @@ When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:move Boost.Atomic]
|
||||
|
||||
[section:thread_eq `boost::thread::oprator==` deprecated]
|
||||
Boost.Thread uses by default an Boost.Atomic in POSIX platforms to implement call_once..
|
||||
|
||||
The following nested typedefs are deprecated:
|
||||
Define `BOOST_THREAD_USES_ATOMIC ` if you want to use Boost.Atomic.
|
||||
Define `BOOST_THREAD_DONT_USE_ATOMIC ` if you don't want to use Boost.Atomic or if it is not supported in your platform.
|
||||
|
||||
* `boost::thread::oprator==`
|
||||
* `boost::thread::oprator!=`
|
||||
[endsect]
|
||||
|
||||
[section:thread_eq `boost::thread::operator==` deprecated]
|
||||
|
||||
The following operators are deprecated:
|
||||
|
||||
* `boost::thread::operator==`
|
||||
* `boost::thread::operator!=`
|
||||
|
||||
When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature.
|
||||
|
||||
Use instead
|
||||
|
||||
* `boost::thread::id::oprator==`
|
||||
* `boost::thread::id::oprator!=`
|
||||
* `boost::thread::id::operator==`
|
||||
* `boost::thread::id::operator!=`
|
||||
|
||||
[warning This is a breaking change respect to version 1.x.]
|
||||
|
||||
@@ -296,8 +304,12 @@ When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKA
|
||||
|
||||
C++11 thread constructor accep a variable number of rvalue argumentshas. When `BOOST_THREAD_PROVIDES_VARIADIC_THREAD ` is defined Boost.Thread provides this C++ feature if the following are not defined
|
||||
|
||||
* BOOST_NO_SFINAE_EXPR
|
||||
* BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
* BOOST_NO_CXX11_DECLTYPE
|
||||
* BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
* BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
* BOOST_NO_CXX11_TRAILING_RESULT_TYPES
|
||||
* BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
* BOOST_NO_CXX11_HDR_TUPLE
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
/ Copyright (c) 2008,2012 Vicente J. Botet Escriba
|
||||
/ Copyright (c) 2008,2012,2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -8,7 +8,7 @@
|
||||
[section External Locking -- `strict_lock` and `externally_locked` classes]
|
||||
|
||||
|
||||
[note This tutorial is an adaptation of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System"
|
||||
[note This tutorial is an adaptation of the paper by Andrei Alexandrescu "Multithreading and the C++ Type System"
|
||||
to the Boost library.]
|
||||
|
||||
[/
|
||||
@@ -163,7 +163,7 @@ Obviously, the caller-ensured locking approach has a safety problem. BankAccount
|
||||
To conclude, if in designing a multi-threaded class you settle on internal locking, you expose yourself to inefficiency or deadlocks. On the other hand, if you rely on caller-provided locking, you make your class error-prone and difficult to use. Finally, external locking completely avoids the issue by leaving it all to the client code.
|
||||
[endsect]
|
||||
]
|
||||
[section Locks as Permits]
|
||||
[section Locks as permits]
|
||||
|
||||
So what to do? Ideally, the BankAccount class should do the following:
|
||||
|
||||
@@ -182,9 +182,9 @@ For now, let's make a couple of enhancements to the `lock_guard` class template
|
||||
We'll call the enhanced version `strict_lock`. Essentially, a `strict_lock`'s role is only to live on the stack as an automatic variable.
|
||||
`strict_lock` must adhere to a non-copy and non-alias policy.
|
||||
`strict_lock` disables copying by making the copy constructor and the assignment operator private.
|
||||
[/
|
||||
While we're at it, let's disable operator new and operator delete.
|
||||
|
||||
[/
|
||||
`strict_lock` are not intended to be allocated on the heap.
|
||||
`strict_lock` avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.
|
||||
]
|
||||
@@ -217,7 +217,7 @@ Silence can be sometimes louder than words-what's forbidden to do with a `strict
|
||||
* You can create a `strict_lock<T>` only starting from a valid T object. Notice that there is no other way you can create a `strict_lock<T>`.
|
||||
|
||||
BankAccount myAccount("John Doe", "123-45-6789");
|
||||
strict_locerk<BankAccount> myLock(myAccount); // ok
|
||||
strict_lock<BankAccount> myLock(myAccount); // ok
|
||||
|
||||
* You cannot copy `strict_lock`s to one another. In particular, you cannot pass `strict_lock`s by value to functions or have them returned by functions:
|
||||
|
||||
@@ -293,7 +293,7 @@ A little code is worth 1,000 words, a (hacked into) saying goes, so here's the n
|
||||
}
|
||||
};
|
||||
|
||||
Now, if you want the benefit of internal locking, you simply call Deposit(int) and Withdraw(int). If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
|
||||
Now, if you want the benefit of internal locking, you simply call `Deposit(int)` and `Withdraw(int)`. If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
|
||||
|
||||
void ATMWithdrawal(BankAccount& acct, int sum) {
|
||||
strict_lock<BankAccount> guard(acct);
|
||||
@@ -453,7 +453,7 @@ We achieved two important goals. First, the declaration of `checkingAcct_` and `
|
||||
|
||||
[section Allowing other strict locks]
|
||||
|
||||
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compiles:
|
||||
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compile:
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard(*this, defer_lock);
|
||||
@@ -465,10 +465,10 @@ Now imagine that the AccountManager function needs to take a `unique_lock` in or
|
||||
do_something_else();
|
||||
}
|
||||
|
||||
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
|
||||
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` during the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
|
||||
|
||||
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
|
||||
unique_lock<AccountManager> guard(*this, defer_lock);
|
||||
unique_lock<AccountManager> guard1(*this, defer_lock);
|
||||
if (some_condition()) {
|
||||
guard1.lock();
|
||||
}
|
||||
@@ -480,9 +480,9 @@ We need a way to transfer the ownership from the `unique_lock` to a `strict_lock
|
||||
guard1.unlock();
|
||||
}
|
||||
|
||||
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.
|
||||
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. We also need to store which kind of reference we have stored, and in the destructor call either to the Lockable `unlock` or restore the ownership.
|
||||
|
||||
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. Ths is really nice.
|
||||
This seems too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that checks that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to believe it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.
|
||||
|
||||
Now we need to state that both classes are `strict_lock`s.
|
||||
|
||||
@@ -496,9 +496,9 @@ Now we need to state that both classes are `strict_lock`s.
|
||||
struct is_strict_lock<nested_strict_lock<Locker> > : mpl::true_ {}
|
||||
|
||||
|
||||
Well let me show how this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
|
||||
Well let me show what this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
|
||||
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction he will restore the ownership. Note also that the Locker needs to have already a reference to the mutex otherwise an exception is thrown and the use of the `lock_traits`.
|
||||
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction it will restore the ownership. Note the use of `lock_traits` and that the `Locker` needs to have a reference to the mutex otherwise and exception is thrown.
|
||||
|
||||
template <typename Locker >
|
||||
class nested_strict_lock
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -293,7 +293,7 @@ that is to allow multiple concurrent get operations.
|
||||
|
||||
[heading Multiple get]
|
||||
|
||||
The second `get()` call in the following example future
|
||||
The second `get()` call in the following example is undefined.
|
||||
|
||||
void bad_second_use( type arg ) {
|
||||
|
||||
@@ -308,7 +308,7 @@ The second `get()` call in the following example future
|
||||
use3( ftr.get() ); // second use is undefined
|
||||
}
|
||||
|
||||
Using a `shared_mutex` solves the issue
|
||||
Using a `shared_future` solves the issue
|
||||
|
||||
void good_second_use( type arg ) {
|
||||
|
||||
@@ -341,7 +341,7 @@ Here `share()` could be used to simplify the code
|
||||
use3( ftr.get() ); // second use is defined
|
||||
}
|
||||
|
||||
[heading Writting on get()]
|
||||
[heading Writing on get()]
|
||||
|
||||
The user can either read or write the future avariable.
|
||||
|
||||
@@ -369,17 +369,17 @@ and a `shared_future` that can be shared between several threads, but there were
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:make_future Making immediate futures easier]
|
||||
[section:make_ready_future Making immediate futures easier]
|
||||
|
||||
Some functions may know the value at the point of construction. In these cases the value is immediately available,
|
||||
but needs to be returned as a future or shared_future. By using make_future (make_shared_future) a future (shared_future)
|
||||
but needs to be returned as a future or shared_future. By using make_ready_future a future
|
||||
can be created which holds a pre-computed result in its shared state.
|
||||
|
||||
Without these features it is non-trivial to create a future directly from a value.
|
||||
First a promise must be created, then the promise is set, and lastly the future is retrieved from the promise.
|
||||
This can now be done with one operation.
|
||||
|
||||
[heading make_future / make_shared_future]
|
||||
[heading make_ready_future]
|
||||
|
||||
This function creates a future for a given value. If no value is given then a future<void> is returned.
|
||||
This function is primarily useful in cases where sometimes, the return value is immediately available, but sometimes
|
||||
@@ -389,16 +389,14 @@ the function must return an eventual value represented as a future.
|
||||
|
||||
boost::future<int> compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_future(0);
|
||||
if (x < 0) return boost::make_future(-1);
|
||||
if (x == 0) return boost::make_ready_future(0);
|
||||
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error"));
|
||||
boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
return f1;
|
||||
}
|
||||
|
||||
There are two variations of this function. The first takes a value of any type, and returns a future of that type.
|
||||
The input value is passed to the shared state of the returned future. The second version takes no input and returns a future<void>.
|
||||
make_shared_future has the same functionality as make_future, except has a return type of shared_future.
|
||||
|
||||
The input value is passed to the shared state of the returned future. The second version takes no input and returns a future<void>.
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -406,16 +404,16 @@ make_shared_future has the same functionality as make_future, except has a retur
|
||||
|
||||
In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second
|
||||
operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future.
|
||||
With .then, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is
|
||||
invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits
|
||||
With `.then`, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is
|
||||
invoked when the result is ready. Continuations registered using the `.then` function will help to avoid blocking waits
|
||||
or wasting threads on polling, greatly improving the responsiveness and scalability of an application.
|
||||
|
||||
future.then provides the ability to sequentially compose two futures by declaring one to be the continuation of another.
|
||||
With .then the antecedent future is ready (has a value or exception stored in the shared state) before the continuation
|
||||
`future.then()` provides the ability to sequentially compose two futures by declaring one to be the continuation of another.
|
||||
With `.then()` the antecedent future is ready (has a value or exception stored in the shared state) before the continuation
|
||||
starts as instructed by the lambda function.
|
||||
|
||||
In the example below the future<int> f2 is registered to be a continuation of future<int> f1 using the .then member
|
||||
function. This operation takes a lambda function which describes how f2 should proceed after f1 is ready.
|
||||
In the example below the `future<string>` `f2` is registered to be a continuation of `future<int>` `f1` using the `.then()` member
|
||||
function. This operation takes a lambda function which describes how `f2` should proceed after `f1` is ready.
|
||||
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
@@ -428,7 +426,7 @@ function. This operation takes a lambda function which describes how f2 should p
|
||||
|
||||
One key feature of this function is the ability to chain multiple asynchronous operations. In asynchronous programming,
|
||||
it's common to define a sequence of operations, in which each continuation executes only when the previous one completes.
|
||||
In some cases, the antecedent future produces a value that the continuation accepts as input. By using future.then,
|
||||
In some cases, the antecedent future produces a value that the continuation accepts as input. By using `future.then()`,
|
||||
creating a chain of continuations becomes straightforward and intuitive:
|
||||
|
||||
myFuture.then(...).then(...).then(...).
|
||||
@@ -441,21 +439,20 @@ Some points to note are:
|
||||
|
||||
Input Parameters:
|
||||
|
||||
* Lambda function2: One option which was considered was to follow JavaScript's approach and take two functions, one for
|
||||
success and one for error handling. However this option is not viable in C++ as there is no single base type for
|
||||
exceptions as there is in JavaScript. The lambda function takes a future as its input which carries the exception
|
||||
* Lambda function: One option which can be considered is to take two functions, one for
|
||||
success and one for error handling. However this option has not been retained for the moment.
|
||||
The lambda function takes a future as its input which carries the exception
|
||||
through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
|
||||
* Scheduler: Providing an overload to .then, to take a scheduler reference places great flexibility over the execution
|
||||
* Scheduler: Providing an overload to `.then`, to take a scheduler reference places great flexibility over the execution
|
||||
of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful
|
||||
asynchronous operations. The lifetime of the scheduler must outlive the continuation.
|
||||
* Launch policy: if the additional flexibility that the scheduler provides is not required.
|
||||
|
||||
|
||||
Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using
|
||||
.then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning
|
||||
a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A
|
||||
shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future
|
||||
to a shared_future when needed using future::share().
|
||||
`.then()`. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning
|
||||
a `future` object rather than a `shared_future` is also a much cheaper operation thereby improving performance. A
|
||||
`shared_future` object is not necessary to take advantage of the chaining feature. It is also easy to go from a `future`
|
||||
to a `shared_future` when needed using future::share().
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
[/
|
||||
/ Copyright (c) 2008 Vicente J. Botet Escriba
|
||||
/ Copyright (c) 2008,2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -14,7 +14,7 @@ Consider, for example, modeling a bank account class that supports simultaneous
|
||||
|
||||
From here a component is a model of the `Callable` concept.
|
||||
|
||||
On C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
|
||||
I C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
|
||||
|
||||
boost::thread thread1(S);
|
||||
|
||||
@@ -53,12 +53,12 @@ The following example includes a bank account of a person (Joe) and two componen
|
||||
return 0;
|
||||
}
|
||||
|
||||
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. Joe will similarly withdraw $100 from his account. These sentences describe that the bankAgent and Joe are executed concurrently.
|
||||
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. `Joe` will similarly withdraw $100 from his account. These sentences describe that the `bankAgent` and `Joe` are executed concurrently.
|
||||
|
||||
[endsect]
|
||||
[section Internal locking]
|
||||
|
||||
The above example works well as long as the bankAgent and Joe doesn't access JoesAccount at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
|
||||
The above example works well as long as the components `bankAgent` and `Joe` doesn't access `JoesAccount` at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_;
|
||||
@@ -82,11 +82,11 @@ The above example works well as long as the bankAgent and Joe doesn't access Joe
|
||||
}
|
||||
};
|
||||
|
||||
Execution of the Deposit and Withdraw operations will no longer be able to make simultaneous access to balance.
|
||||
Execution of the `Deposit` and `Withdraw` operations will no longer be able to make simultaneous access to balance.
|
||||
|
||||
Mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
|
||||
A mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
|
||||
|
||||
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
|
||||
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object `mtx_`, and guard's destructor unlocks `mtx_`.
|
||||
|
||||
class BankAccount {
|
||||
boost::mutex mtx_; // explicit mutex declaration
|
||||
@@ -135,10 +135,10 @@ In an attempt to solve this problem, let's lock the account from the outside dur
|
||||
acct.Withdraw(2);
|
||||
}
|
||||
|
||||
Notice that the code above doesn't compiles, the `mtx_` field is private.
|
||||
Notice that the code above doesn't compile, the `mtx_` field is private.
|
||||
We have two possibilities:
|
||||
|
||||
* make `mtx_` public which seams odd
|
||||
* make `mtx_` public which seems odd
|
||||
* make the `BankAccount` lockable by adding the lock/unlock functions
|
||||
|
||||
We can add these functions explicitly
|
||||
|
||||
@@ -7,13 +7,19 @@
|
||||
|
||||
[section:latches Latches -- EXPERIMENTAL]
|
||||
|
||||
[////////////////////]
|
||||
[section Introdcution]
|
||||
|
||||
Latches are a thread co-ordination mechanism that allow one or more threads to block until one or more threads have reached a point. An individual latch is a reusable object; once the operation has been completed, the threads can re-use the same barrier. It is thus useful for managing repeated tasks handled by multiple threads.
|
||||
Latches are a thread co-ordination mechanism that allow one or more threads to block until one or more threads have reached a point.
|
||||
|
||||
[/
|
||||
An individual latch is a reusable object; once the operation has been completed, the threads can re-use the same barrier. It is thus useful for managing repeated tasks handled by multiple threads.
|
||||
|
||||
A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[////////////////]
|
||||
[section Examples]
|
||||
|
||||
Sample use cases for the latch include:
|
||||
@@ -38,7 +44,6 @@ An example of the first use case would be as follows:
|
||||
|
||||
An example of the second use case is shown below. We need to load data and then process it using a number of threads. Loading the data is I/O bound, whereas starting threads and creating data structures is CPU bound. By running these in parallel, throughput can be increased.
|
||||
|
||||
|
||||
void DoWork() {
|
||||
latch start_latch(1);
|
||||
vector<thread*> workers;
|
||||
@@ -57,6 +62,7 @@ An example of the second use case is shown below. We need to load data and then
|
||||
start_latch.count_down();
|
||||
}
|
||||
|
||||
[/
|
||||
The completion latches can be used to co-ordinate also a set of threads carrying out a repeated task. The number of threads can be adjusted dynamically to respond to changing requirements.
|
||||
|
||||
In the example below, a number of threads are performing a multi-stage task. Some tasks may require fewer steps than others, meaning that some threads may finish before others. We reduce the number of threads waiting on the latch when this happens.
|
||||
@@ -96,8 +102,10 @@ In the example below, a number of threads are performing a multi-stage task. Som
|
||||
GetNextStage(tasks);
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////]
|
||||
[section:latch Class `latch`]
|
||||
|
||||
#include <boost/thread/latch.hpp>
|
||||
@@ -119,16 +127,20 @@ In the example below, a number of threads are performing a multi-stage task. Som
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
void count_down();
|
||||
void count_down_and_wait();
|
||||
void reset(std::size_t count);
|
||||
|
||||
};
|
||||
|
||||
|
||||
[/
|
||||
void reset(std::size_t count);
|
||||
]
|
||||
|
||||
A latch maintains an internal counter that is initialized when the latch is created. One or more threads may block waiting until the counter is decremented to 0.
|
||||
|
||||
Instances of __latch__ are not copyable or movable.
|
||||
|
||||
[section Constructor]
|
||||
[///////////////////]
|
||||
[section Constructor `latch(std::size_t)`]
|
||||
|
||||
latch(std::size_t count);
|
||||
|
||||
@@ -136,14 +148,15 @@ Instances of __latch__ are not copyable or movable.
|
||||
|
||||
[[Effects:] [Construct a latch with is initial value for the internal counter.]]
|
||||
|
||||
[[Note:] [The counter could be zero and reset later.]]
|
||||
[[Note:] [The counter could be zero.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section Destructor]
|
||||
[//////////////////]
|
||||
[section Destructor `~latch()`]
|
||||
|
||||
~latch();
|
||||
|
||||
@@ -158,7 +171,8 @@ Instances of __latch__ are not copyable or movable.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:wait Member function `wait()`]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait Member Function `wait()`]
|
||||
|
||||
void wait();
|
||||
|
||||
@@ -178,8 +192,8 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:try_wait Member function `try_wait()`]
|
||||
[/////////////////////////////////////////////]
|
||||
[section:try_wait Member Function `try_wait()`]
|
||||
|
||||
bool try_wait();
|
||||
|
||||
@@ -194,8 +208,8 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:wait_for Member function `wait_for() `]
|
||||
[//////////////////////////////////////////////]
|
||||
[section:wait_for Member Function `wait_for() `]
|
||||
|
||||
template <class Rep, class Period>
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
@@ -216,7 +230,8 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:wait_until Member function `wait_until()`]
|
||||
[/////////////////////////////////////////////////]
|
||||
[section:wait_until Member Function `wait_until()`]
|
||||
|
||||
template <class lock_type, class Clock, class Duration>
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
@@ -237,7 +252,8 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:count_down Member function `count_down()`]
|
||||
[/////////////////////////////////////////////////]
|
||||
[section:count_down Member Function `count_down()`]
|
||||
|
||||
void count_down();
|
||||
|
||||
@@ -256,7 +272,8 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:count_down_and_wait Member function `count_down_and_wait()`]
|
||||
[///////////////////////////////////////////////////////////////////]
|
||||
[section:count_down_and_wait Member Function `count_down_and_wait()`]
|
||||
|
||||
void count_down_and_wait();
|
||||
|
||||
@@ -275,8 +292,9 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:reset Member function `reset()`]
|
||||
[///////////////////////////////////////]
|
||||
[
|
||||
[section:reset Member Function `reset()`]
|
||||
|
||||
reset( size_t );
|
||||
|
||||
@@ -293,9 +311,11 @@ are unblocked. ]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
]
|
||||
[endsect] [/ latch]
|
||||
|
||||
[/
|
||||
[//////////////////////////////////////////////////]
|
||||
[section:completion_latch Class `completion_latch `]
|
||||
|
||||
#include <boost/thread/completion_latch.hpp>
|
||||
@@ -333,6 +353,7 @@ Instances of completion_latch are not copyable or movable.
|
||||
|
||||
Only the additional functions are documented.
|
||||
|
||||
[/////////////////////]
|
||||
[section:c Constructor]
|
||||
|
||||
completion_latch(std::size_t count);
|
||||
@@ -348,6 +369,7 @@ Only the additional functions are documented.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[///////////////////////////////////////////////]
|
||||
[section:cf Constructor with completion function]
|
||||
|
||||
template <typename F>
|
||||
@@ -368,7 +390,8 @@ Only the additional functions are documented.
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:then Member function `then`]
|
||||
[///////////////////////////////////]
|
||||
[section:then Member Function `then`]
|
||||
|
||||
template <typename F>
|
||||
completion_function then(F&& funct);
|
||||
@@ -391,6 +414,6 @@ Only the additional functions are documented.
|
||||
[endsect]
|
||||
|
||||
[endsect] [/ completion_latch]
|
||||
|
||||
]
|
||||
|
||||
[endsect] [/ Latches]
|
||||
|
||||
@@ -298,8 +298,6 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.]
|
||||
[warning
|
||||
DEPRECATED since 4.00. The following expressions were required on version 2, but are now deprecated.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use instead __try_lock_for, __try_lock_until.
|
||||
]
|
||||
|
||||
@@ -460,8 +458,6 @@ ownership of `m`.]]
|
||||
[warning
|
||||
DEPRECATED since 3.00. The following expressions were required on version 2, but are now deprecated.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __try_lock_shared_for, __try_lock_shared_until.
|
||||
]
|
||||
|
||||
@@ -1119,6 +1115,44 @@ object passed to the constructor.]]
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:with_lock_guard With Lock Guard]
|
||||
|
||||
// #include <boost/thread/with_lock_guard.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(Lockable& m, Function&& func, Args&&... args) -> decltype(func(boost::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
[section:with_lock_guard Non Member Function `with_lock_guard`]
|
||||
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(
|
||||
Lockable& m,
|
||||
Function&& func,
|
||||
Args&&... args
|
||||
) -> decltype(func(boost::forward<Args>(args)...));
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Precondition:] [`m` must be in unlocked state]]
|
||||
[[Effects:] [call `func` in scope locked by `m`]]
|
||||
[[Returns:] [Result of `func(args...)` call]]
|
||||
[[Throws:] [Any exception thrown by the call to `m.lock` and `func(args...)`]]
|
||||
[[Postcondition:] [`m` is in unlocked state]]
|
||||
|
||||
[[Limitations:] [Without c++11 variadic templates support number of arguments is limited to `4`]]
|
||||
[[] [Without rvalue references support calling class method with `boost::bind` must be const]]
|
||||
[[] [For correct work with lambda macro `BOOST_RESULT_OF_USE_DECLTYPE` may be needed to define]]
|
||||
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
@@ -1273,7 +1307,7 @@ The following classes are models of `StrictLock`:
|
||||
explicit operator bool() const noexcept;
|
||||
bool owns_lock() const noexcept;
|
||||
|
||||
Lockable* mutex() const noexcept;
|
||||
mutex_type* mutex() const noexcept;
|
||||
|
||||
#if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO
|
||||
unique_lock(Lockable& m_,system_time const& target_time);
|
||||
@@ -1535,7 +1569,7 @@ object associated with `*this`.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:mutex `Lockable* mutex() const`]
|
||||
[section:mutex `Lockable* mutex() const noexcept`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -1907,7 +1941,7 @@ state (including the destructor) must be called by the same thread that acquired
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`]
|
||||
[section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock` -- EXTENSION]
|
||||
|
||||
// #include <boost/thread/locks.hpp>
|
||||
// #include <boost/thread/lock_types.hpp>
|
||||
@@ -1930,6 +1964,8 @@ state (including the destructor) must be called by the same thread that acquired
|
||||
|
||||
explicit operator bool() const;
|
||||
bool owns_lock() const;
|
||||
mutex_type* mutex() const;
|
||||
|
||||
};
|
||||
|
||||
__upgrade_to_unique_lock__ allows for a temporary upgrade of an __upgrade_lock__ to exclusive ownership. When constructed with a
|
||||
@@ -1939,7 +1975,7 @@ __lockable_concept_type__ is downgraded back to ['upgrade ownership].
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:scoped_try_lock Mutex-specific class `scoped_try_lock`]
|
||||
[section:scoped_try_lock Mutex-specific class `scoped_try_lock` -- DEPRECATED]
|
||||
|
||||
class MutexType::scoped_try_lock
|
||||
{
|
||||
|
||||
@@ -34,9 +34,10 @@ Scoped Threads are wrappers around a thread that allows the user to state what t
|
||||
|
||||
The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface than __thread and forwards all the operations.
|
||||
|
||||
boost::strict_scoped_thread<> t1((boost::thread(F)));
|
||||
boost::strict_scoped_thread<> t2((boost::thread(F)));
|
||||
t2.interrupt();
|
||||
boost::strict_scoped_thread<> t1((boost::thread(f)));
|
||||
//t1.detach(); // compile fails
|
||||
boost::scoped_thread<> t2((boost::thread(f)));
|
||||
t2.detach();
|
||||
|
||||
[endsect]
|
||||
|
||||
@@ -190,7 +191,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
|
||||
explicit scoped_thread(thread&& th) noexcept;
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
explicit scoped_thread(F&&, Args&&...);
|
||||
|
||||
~scoped_thread();
|
||||
|
||||
@@ -216,6 +217,7 @@ This wrapper can be used to join the thread before destroying it seems a natural
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
static unsigned physical_concurrency() noexcept;
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
@@ -323,7 +325,7 @@ any) to `*this`.
|
||||
[section:call_constructor Move Constructor from a Callable]
|
||||
|
||||
template <typename F&&, typename ...Args>
|
||||
explicit strict_scoped_thread(F&&, Args&&...);
|
||||
explicit scoped_thread(F&&, Args&&...);
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -458,6 +460,20 @@ any) to `*this`.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Equivalent to return `thread::physical_concurrency()`.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef thread::native_handle_type native_handle_type;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:synchronized_queues Synchronized Queues -- EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
@@ -12,6 +13,18 @@
|
||||
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3533.html [*N3533 - C++ Concurrent Queues]] C++1y proposal from Lawrence Crowl and Chris Mysen and [@http://www.manning.com/williams/ [*C++ Concurrency in Action]] from Anthony Williams.]
|
||||
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
Queues provide a mechanism for communicating data between components of a system.
|
||||
|
||||
The existing deque in the standard library is an inherently sequential data structure. Its reference-returning element access operations cannot synchronize access to those elements with other queue operations. So, concurrent pushes and pops on queues require a different interface to the queue structure.
|
||||
|
||||
Moreover, concurrency adds a new dimension for performance and semantics. Different queue implementation must trade off uncontended operation cost, contended operation cost, and element order guarantees. Some of these trade-offs will necessarily result in semantics weaker than a serial queue.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Concurrent queues are a well know mechanism for communicating data between different threads.
|
||||
@@ -19,7 +32,13 @@ Concurrent queues are a well know mechanism for communicating data between diffe
|
||||
Concurrent queues have inherently copy/move semantics for the data handling operation. Reference-returning interfaces are forbidden as multiple access to these references can not be thread-safe.
|
||||
|
||||
[endsect]
|
||||
[////////////////]
|
||||
[section Examples]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:ref Reference]
|
||||
|
||||
[section:sync_queue_req Synchronized Queue Model]
|
||||
@@ -37,16 +56,15 @@ Locking queues can by nature block waiting for the queue to be non-empty or non-
|
||||
Lock-free queues will have some trouble waiting for the queue to be non-empty or non-full queues. These queues can not define operations such as push (and pull for bounded queues). That is, it could have blocking operations (presumably emulated with busy wait) but not waiting operations.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:closed Closed Queue]
|
||||
|
||||
Threads using a queue for communication need some mechanism to signal when the queue is no longer needed. The usual approach is add an additional out-of-band signal. However, this approach suffers from the flaw that threads waiting on either full or empty queues need to be woken up when the queue is no longer needed. Rather than require an out-of-band signal, we chose to directly support such a signal in the queue itself, which considerably simplifies coding.
|
||||
|
||||
To achieve this signal, a thread may close a queue. Once closed, no new elements may be pushed onto the queue. Push operations on a closed queue will either return queue_op_status::closed (when they have a queue_op_status return type), set the closed parameter if it has one or throw sync_queue::closed (when they do not). Elements already on the queue may be pulled off. When a queue is empty and closed, pull operations will either return queue_op_status::closed (when they have a status return), set the closed parameter if it has one or throw sync_queue::closed (when they do not).
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:exception Concurrent Queues Throw specification]
|
||||
[section:locking Locking]
|
||||
|
||||
@@ -57,6 +75,7 @@ All the functions are defined as if we had in addition to its specific Throw spe
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:bad_alloc Allocation]
|
||||
|
||||
All the functions that allocate a resource are defined as if we had in addition to its specific Throw specification the following:
|
||||
@@ -67,7 +86,7 @@ All the functions that allocate a resource are defined as if we had in addition
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:BasicConcurrentQueue Basic Concurrent Queue Operations]
|
||||
|
||||
The essential solution to the problem of concurrent queuing is to shift to value-based operations, rather than reference-based operations.
|
||||
@@ -78,11 +97,11 @@ A type `Q` meets the BasicConcurrentQueue requirements if the following expressi
|
||||
|
||||
* Q::value_type
|
||||
* Q::size_type
|
||||
* `q.push(e);`
|
||||
* `q.push(rve);`
|
||||
* `q.pull(lre);`
|
||||
* `lre = q.pull();`
|
||||
* `spe = q.ptr_pull();`
|
||||
* `q.push_back(e);`
|
||||
* `q.push_back(rve);`
|
||||
* `q.pull_front(lre);`
|
||||
* `lre = q.pull_front();`
|
||||
[/* `spe = q.ptr_pull_front();`]
|
||||
* `b = q.empty();`
|
||||
* `u = q.size();`
|
||||
|
||||
@@ -93,14 +112,16 @@ where
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
* `qs` denotes a variable of of type `queus_op_status`,
|
||||
|
||||
|
||||
[section:push `q.push(e);`]
|
||||
[/////////////////////////////////////]
|
||||
[section:push_back `q.push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push back `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -115,11 +136,12 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:push_m `q.push(rve);`]
|
||||
[/////////////////////////////////////]
|
||||
[section:push_back_m `q.push_back(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it back in the queue (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -134,13 +156,12 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section:pull_lv `q.pull(lve)`]
|
||||
[/////////////////////////////////////]
|
||||
[section:pull_front_lv `q.pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
[[Effects:] [Waits until the queue is not empty and then pull_front the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
@@ -155,8 +176,8 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:pull `e = q.pull()`]
|
||||
[/////////////////////////////////////]
|
||||
[section:pull_front `e = q.pull_front()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -179,8 +200,9 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:ptr_pull `spe = q.ptr_pull()`]
|
||||
[/
|
||||
[/////////////////////////////////////]
|
||||
[section:ptr_pull_front `spe = q.ptr_pull_front()`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -203,11 +225,10 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:non_waaiting Non-waiting Concurrent Queue Operations]
|
||||
|
||||
The ConcurrentQueue concept models a queue with .
|
||||
@@ -215,33 +236,42 @@ The ConcurrentQueue concept models a queue with .
|
||||
|
||||
A type `Q` meets the ConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
|
||||
|
||||
* `b = q.try_push(e);`
|
||||
* `b = q.try_push(rve);`
|
||||
* `b = q.try_pull(lre);`
|
||||
* `s = q.try_push_back(e);`
|
||||
* `s = q.try_push_back(rve);`
|
||||
* `s = q.try_pull_front(lre);`
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `e` denotes a value of type `Q::value_type`,
|
||||
* `s` denotes a value of type `queue_status`,
|
||||
* `u` denotes a value of type `Q::size_type`,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
|
||||
|
||||
[section:try_push `q.try_push(e);`]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_push_back `s = q.try_push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full, push the `e` to the queue copying it.]]
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` to the queue copying it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation when the operation succeeds. ]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
[[Return:] [
|
||||
|
||||
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
|
||||
- If the queue is closed, returns `queue_op_status::closed`,
|
||||
|
||||
- otherwise if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;
|
||||
]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
@@ -250,28 +280,37 @@ where
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:try_push_m `q.try_push(rve());`]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_push_back_m `s = q.try_push_back(rve());`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full, push the `e` onto the queue moving it.]]
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` onto the queue moving it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
[[Return:] [
|
||||
|
||||
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
|
||||
- If the queue is closed, returns `queue_op_status::closed`,
|
||||
|
||||
- otherwise if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
- otherwise return `queue_op_status::success`;
|
||||
]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [ Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[section:pull_lv `b = q.try_pull(lve)`]
|
||||
[/////////////////////////////////////]
|
||||
[section:try_pull_front_lv `s = q.try_pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
@@ -283,7 +322,13 @@ where
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
|
||||
[[Return:] [
|
||||
|
||||
- If the queue `q` is empty return `queue_op_status::empty`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;
|
||||
|
||||
]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
@@ -293,30 +338,120 @@ where
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:non_blocking Non-blocking Concurrent Queue Operations]
|
||||
|
||||
For cases when blocking for mutual exclusion is undesirable, we have non-blocking operations. The interface is the same as the try operations but is allowed to also return queue_op_status::busy in case the operation is unable to complete without blocking.
|
||||
For cases when blocking for mutual exclusion is undesirable, we have non-blocking operations.
|
||||
The interface is the same as the try operations but is allowed to also return queue_op_status::busy
|
||||
in case the operation is unable to complete without blocking.
|
||||
|
||||
Non-blocking operations are provided only for BlockingQueues
|
||||
|
||||
* `b = q.try_push(nb, e);`
|
||||
* `b = q.try_push(nb, rve);`
|
||||
* `b = q.try_pull(nb, lre);`
|
||||
* `s = q.nonblocking_push_back(nb, e);`
|
||||
* `s = q.nonblocking_push_back(nb, rve);`
|
||||
* `s = q.nonblocking_pull_front(nb, lre);`
|
||||
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `e` denotes a value of type Q::value_type,
|
||||
* `u` denotes a value of type Q::size_type,
|
||||
* `s` denotes a value of type `queue_status`,
|
||||
* `lve` denotes a lvalue referece of type Q::value_type,
|
||||
* `rve` denotes a rvalue referece of type Q::value_type:
|
||||
* `spe` denotes a shared_ptr<Q::value_type>
|
||||
[/* `spe` denotes a shared_ptr<Q::value_type>]
|
||||
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_push_back `s = q.nonblocking_push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` to the queue copying it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation when the operation succeeds. ]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the operation would block, return queue_op_status::busy,
|
||||
|
||||
- otherwise, if the queue is closed, return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_push_back_m `s = q.nonblocking_push_back(rve());`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [If the queue `q` is not full and not closed, push back the `e` onto the queue moving it.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the operation would block, return queue_op_status::busy,
|
||||
|
||||
- otherwise if the queue is closed, returns `queue_op_status::closed`,
|
||||
|
||||
- otherwise if the queue `q` is full return `queue_op_status::full`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;]]
|
||||
|
||||
[[Postcondition:] [If the call returns `queue_op_status::success`, `! q.empty()`.]]
|
||||
|
||||
[[Throws:] [ Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:nonblocking_pull_front_lv `s = q.nonblocking_pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the operation would block, return queue_op_status::busy,
|
||||
|
||||
- otherwise if the queue `q` is empty return `queue_op_status::empty`,
|
||||
|
||||
- otherwise return `queue_op_status::success`;]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:bounded Bounded Concurrent Queue Operations]
|
||||
|
||||
Bounded queues add the following valid expressions
|
||||
@@ -325,38 +460,164 @@ Bounded queues add the following valid expressions
|
||||
* `b = q.full();`
|
||||
* `u = q.capacity();`
|
||||
|
||||
|
||||
where
|
||||
|
||||
* `q` denotes a value of type `Q`,
|
||||
* `b` denotes a value of type `bool`,
|
||||
* `u` denotes a value of type `Q::size_type`,
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:full `b = q.full();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Return `true` iff the queue is full.]]
|
||||
|
||||
[[Remark:] [Not all queues will have a full state, and these would always return false if the function is provided.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:capacity `b = q.capacity();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`Q::size_type`.]]
|
||||
|
||||
[[Return:] [Return the capacity of queue.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:closed_op Closed Concurrent Queue Operations]
|
||||
|
||||
Closed queues add the following valid expressions
|
||||
|
||||
* `q.close();`
|
||||
* `b = q.closed();`
|
||||
|
||||
Basic expressions
|
||||
* `s = q.wait_push_back(e);`
|
||||
* `s = q.wait_push_back(rve);`
|
||||
* `s = q.wait_pull_front(lre);`
|
||||
|
||||
* `q.push(e,c);`
|
||||
* `q.push(rve,c);`
|
||||
* `q.pull(lre,c);`
|
||||
* `spe = q.ptr_pull(c);`
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back `q.close();`]
|
||||
|
||||
Non-waiting operations
|
||||
[variablelist
|
||||
|
||||
* `b = q.try_push(e, c);`
|
||||
* `b = q.try_push(rve, c);`
|
||||
* `b = q.try_pull(lre, c);`
|
||||
[[Effects:] [Close the queue.]]
|
||||
|
||||
Non-blocking operations are provided by BlockingQueues
|
||||
]
|
||||
|
||||
* `b = q.try_push(nb, e, c);`
|
||||
* `b = q.try_push(nb, rve, c);`
|
||||
* `b = q.try_pull(nb, lre, c);`
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back `b = q.closed();`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Return type:] [`bool`.]]
|
||||
|
||||
[[Return:] [Return `true` iff the queue is closed.]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back `s = q.wait_push_back(e);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push back `e` to the queue copying it (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.empty()`.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is closed retun `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
|
||||
]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_push_back_m `s = q.wait_push_back(rve);`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it back in the queue (this could need an allocation for unbounded queues).]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.empty()`.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is closed return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
|
||||
.]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the copy of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:wait_pull_front_lv `s = q.wait_pull_front(lve)`]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [if the queue is not empty and not closed, waits until the queue is not empty and then pull_front the element from the queue `q` and moves the pulled element into `lve`.]]
|
||||
|
||||
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
|
||||
|
||||
[[Postcondition:] [`! q.full()`.]]
|
||||
|
||||
[[Return type:] [`queue_op_status`.]]
|
||||
|
||||
[[Return:] [
|
||||
|
||||
- If the queue is empty and closed, return `queue_op_status::closed`,
|
||||
|
||||
- otherwise, return `queue_op_status::success` if no exception is thrown.
|
||||
]]
|
||||
|
||||
[[Throws:] [Any exception thrown by the move of `e`.]]
|
||||
|
||||
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_bounded_queue_ref Synchronized Bounded Queue]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -377,6 +638,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_queue_is_closed Class `sync_queue_is_closed`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -387,7 +649,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
}
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_bounded_queue Class template `sync_bounded_queue<>`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -415,27 +677,61 @@ Non-blocking operations are provided by BlockingQueues
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(value_type&& x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, value_type&& x);
|
||||
void push_back(const value_type& x);
|
||||
void push_back(value_type&& x);
|
||||
|
||||
queue_op_status try_push_back(const value_type& x);
|
||||
queue_op_status try_push_back(value_type&&) x);
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x);
|
||||
queue_op_status nonblocking_push_back(value_type&& x);
|
||||
|
||||
void pull_front(value_type&);
|
||||
value_type pull_front();
|
||||
|
||||
queue_op_status try_pull_front(value_type&);
|
||||
queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
void pull(value_type&);
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
[/ shared_ptr<ValueType> ptr_pull_front();]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `sync_bounded_queue(size_type)`]
|
||||
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a sync_bounded_queue with a maximum number of elements given by `max_elems`. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructort Template Constructor `sync_bounded_queue(size_type, Range)`]
|
||||
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs a sync_bounded_queue with a maximum number of elements given by `max_elems` and push back the elements of the range. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_out_operators Non-Member Function `operator<<()`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -448,6 +744,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_in_operators Non-Member Function `operator>>()`]
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
@@ -460,6 +757,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
[endsect]
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_queue_ref Synchronized Unbounded Queue]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
@@ -477,6 +775,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem);
|
||||
}
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:sync_queue Class template `sync_queue<>`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
@@ -488,13 +787,14 @@ Non-blocking operations are provided by BlockingQueues
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef csbl::deque<ValueType> underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
sync_queue(sync_queue const&) = delete;
|
||||
sync_queue& operator=(sync_queue const&) = delete;
|
||||
sync_queue();
|
||||
explicit template <typename Range>
|
||||
sync_queue(Range range);
|
||||
sync_queue(Range range); // Not yet implemented
|
||||
~sync_queue();
|
||||
|
||||
// Observers
|
||||
@@ -504,27 +804,89 @@ Non-blocking operations are provided by BlockingQueues
|
||||
bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void push(const value_type& x);
|
||||
void push(value_type&& x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(value_type&&) x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, value_type&& x);
|
||||
void push_back(const value_type& x);
|
||||
void push_back(value_type&& x);
|
||||
|
||||
void pull(value_type&);
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
queue_op_status try_push_back(const value_type& x);
|
||||
queue_op_status try_push_back(value_type&&) x);
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x);
|
||||
queue_op_status nonblocking_push_back(value_type&& x);
|
||||
|
||||
void pull_front(value_type&);
|
||||
value_type pull_front();
|
||||
|
||||
queue_op_status try_pull_front(value_type&);
|
||||
queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
underlying_queue_type underlying_queue() noexcept;
|
||||
|
||||
void close();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
[/ shared_ptr<ValueType> ptr_pull_front();]
|
||||
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Constructor `sync_bounded_queue(size_type)`]
|
||||
|
||||
explicit sync_queue();
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an empty sync_queue. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructort Template Constructor `sync_bounded_queue(size_type, Range)`]
|
||||
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Constructs an sync_queue with all the elements of the range. ]]
|
||||
|
||||
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:full Member Function `full()`]
|
||||
|
||||
bool full() const;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [false. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:constructor Member Function `underlying_queue()`]
|
||||
|
||||
underlying_queue_type underlying_queue() noexcept;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [Moves internal queue. ]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_out_operators Non-Member Function `operator<<()`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
@@ -537,6 +899,7 @@ Non-blocking operations are provided by BlockingQueues
|
||||
}
|
||||
|
||||
[endsect]
|
||||
[/////////////////////////////////////]
|
||||
[section:stream_in_operators Non-Member Function `operator>>()`]
|
||||
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
[endsect] [/tutorial]
|
||||
|
||||
[/////////////////////]
|
||||
[section:ref Reference]
|
||||
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
@@ -48,7 +49,7 @@
|
||||
operator>>(externally_locked_stream<Stream, RecursiveMutex>& mtx, T& arg);
|
||||
}
|
||||
|
||||
|
||||
[/////////////////////////////////////////]
|
||||
[section:stream_guard Class `stream_guard`]
|
||||
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
@@ -78,6 +79,7 @@
|
||||
|
||||
`stream_guard` is a model of __StrictLock.
|
||||
|
||||
[//////////////////////////////////////////////////]
|
||||
[section:constructor `stream_guard(mutex_type & m)`]
|
||||
|
||||
[variablelist
|
||||
@@ -89,7 +91,7 @@
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[////////////////////////////////////////////////////////////////////////////]
|
||||
[section:constructor_adopt `stream_guard(mutex_type & m,boost::adopt_lock_t)`]
|
||||
|
||||
[variablelist
|
||||
@@ -105,8 +107,7 @@ obtained by a call to [lock_ref_link `m.lock()`].]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:move_constructor `stream_guard(stream_guard && m)`]
|
||||
|
||||
|
||||
@@ -119,8 +120,7 @@ obtained by a call to [lock_ref_link `m.lock()`].]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[////////////////////////////////////]
|
||||
[section:destructor `~stream_guard()`]
|
||||
|
||||
[variablelist
|
||||
@@ -134,8 +134,8 @@ object passed to the constructor.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
[//////////////////////////////////////////////////////////////////]
|
||||
[section:externally_locked_stream Class `externally_locked_stream `]
|
||||
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
@@ -152,7 +152,6 @@ object passed to the constructor.]]
|
||||
|
||||
// Modifiers
|
||||
stream_guard<Stream, RecursiveMutex> hold();
|
||||
Stream& bypass() const;
|
||||
|
||||
};
|
||||
}
|
||||
@@ -162,6 +161,7 @@ provides full access to that object through the `get` member functions, provided
|
||||
pass a reference to a strict lock object.
|
||||
|
||||
|
||||
[////////////////////////////////////////////////////////////////////////]
|
||||
[section:constructor `externally_locked_stream(Stream&, RecursiveMutex&)`]
|
||||
|
||||
[variablelist
|
||||
@@ -172,6 +172,7 @@ pass a reference to a strict lock object.
|
||||
|
||||
[endsect]
|
||||
|
||||
[/////////////////////]
|
||||
[section:hold `hold()`]
|
||||
|
||||
[variablelist
|
||||
@@ -182,6 +183,8 @@ pass a reference to a strict lock object.
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
@@ -20,24 +20,44 @@ In addition to the C++11 standard locks, Boost.Thread provides other locks and s
|
||||
|
||||
[section:with Executing Around a Function]
|
||||
|
||||
In particular, the library provides some lock factories.
|
||||
In particular, the library provides a way to lock around the execution of a function.
|
||||
|
||||
template <class Lockable, class Function>
|
||||
auto with_lock_guard(Lockable& m, Function f) -> decltype(fn())
|
||||
{
|
||||
auto&& _ = boost::make_lock_guard(f);
|
||||
f();
|
||||
template <class Lockable, class Function, class... Args>
|
||||
auto with_lock_guard(
|
||||
Lockable& m,
|
||||
Function&& func,
|
||||
Args&&... args
|
||||
) -> decltype(func(boost::forward<Args>(args)...)) {
|
||||
boost::lock_guard<Lockable> lock(m);
|
||||
return func(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
that can be used with regular functions:
|
||||
|
||||
that can be used as
|
||||
int func(int, int&);
|
||||
//...
|
||||
boost::mutex m;
|
||||
int a;
|
||||
int result = boost::with_lock_guard(m, func, 1, boost::ref(a));
|
||||
|
||||
int i = with_lock_guard(mtx, {}() -> bool
|
||||
{
|
||||
// access the protected state
|
||||
return true;
|
||||
});
|
||||
with boost::bind:
|
||||
|
||||
int result = boost::with_lock_guard(
|
||||
m, boost::bind(func, 2, boost::ref(a))
|
||||
);
|
||||
|
||||
or with lambda expression:
|
||||
|
||||
int a;
|
||||
int result = boost::with_lock_guard(
|
||||
m,
|
||||
[&a](int x) {
|
||||
// this scope is protected by mutex m
|
||||
a = 3;
|
||||
return x + 4;
|
||||
},
|
||||
5
|
||||
);
|
||||
|
||||
[endsect] [/ With]
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
/]
|
||||
|
||||
|
||||
[section:synchronized_valuesxxx Synchronized values - EXPERIMENTAL]
|
||||
[section:synchronized_valuesxxx Synchronized Values - EXPERIMENTAL]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
[library Thread
|
||||
[quickbook 1.5]
|
||||
[version 4.1.0]
|
||||
[version 4.3.0]
|
||||
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
|
||||
[copyright 2007-11 Anthony Williams]
|
||||
[copyright 2011-13 Vicente J. Botet Escriba]
|
||||
[copyright 2011-14 Vicente J. Botet Escriba]
|
||||
[purpose C++ Library for launching threads and synchronizing data between them]
|
||||
[category text]
|
||||
[license
|
||||
@@ -239,9 +239,9 @@
|
||||
[include condition_variables.qbk]
|
||||
[include once.qbk]
|
||||
[include barrier.qbk]
|
||||
[/include latch.qbk]
|
||||
[include latch.qbk]
|
||||
[include async_executors.qbk]
|
||||
[include futures.qbk]
|
||||
[/include async_executors.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
[include synchronized_value.qbk]
|
||||
[/include sync_queues_ref.qbk]
|
||||
[include sync_queues_ref.qbk]
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
|
||||
@@ -470,6 +470,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() noexcept;
|
||||
static unsigned physical_concurrency() noexcept;
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
native_handle_type native_handle();
|
||||
@@ -532,24 +533,14 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
|
||||
|
||||
thread& operator=(thread&& other) noexcept;
|
||||
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE behavior.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Join the thread before moving.
|
||||
]
|
||||
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [Transfers ownership of the thread managed by `other` (if
|
||||
any) to `*this`.
|
||||
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If there was a thread previously associated with `*this` then that thread is detached, DEPRECATED
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable call __detach__, DEPRECATED
|
||||
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate.
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to `std::terminate()`.
|
||||
]]
|
||||
|
||||
[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]]
|
||||
@@ -568,7 +559,7 @@ any) to `*this`.
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Requires:] [`Callable` must by Copyable and `func()` must be a valid expression.]]
|
||||
[[Requires:] [`Callable` must be Copyable and `func()` must be a valid expression.]]
|
||||
|
||||
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -595,7 +586,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`Callable` must by copyable.]]
|
||||
[[Preconditions:] [`Callable` must be copyable.]]
|
||||
|
||||
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -623,7 +614,7 @@ If the attributes declare the native thread as detached, the boost::thread will
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`Callable` must by Movable.]]
|
||||
[[Preconditions:] [`Callable` must be Movable.]]
|
||||
|
||||
[[Effects:] [`func` is moved into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -650,7 +641,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`Callable` must by copyable.]]
|
||||
[[Preconditions:] [`Callable` must be copyable.]]
|
||||
|
||||
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
|
||||
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
|
||||
@@ -679,7 +670,7 @@ If the attributes declare the native thread as detached, the boost::thread will
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [`F` and each `A`n must by copyable or movable.]]
|
||||
[[Preconditions:] [`F` and each `A`n must be copyable or movable.]]
|
||||
|
||||
[[Effects:] [As if [link
|
||||
thread.thread_management.thread.callable_constructor
|
||||
@@ -706,24 +697,17 @@ are copied into internal storage for access by the new thread.]]]
|
||||
|
||||
~thread();
|
||||
|
||||
[warning
|
||||
DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE behavior.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Join the thread before destroying or use a scoped thread.
|
||||
]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Effects:] [
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If `*this` has an associated thread of execution, calls __detach__, DEPRECATED
|
||||
- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls __detach__, DEPRECATED
|
||||
|
||||
- BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate. Destroys `*this`.]]
|
||||
- if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to `std::terminate`. Destroys `*this`.]]
|
||||
|
||||
[[Throws:] [Nothing.]]
|
||||
|
||||
[[Note:] [Either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.]]
|
||||
[[Note:] [The reason to moving to std::terminate is that either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable. Join the thread before destroying or use an scoped thread.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -794,8 +778,6 @@ corresponding successful `join()` return. ]]
|
||||
[warning
|
||||
DEPRECATED since 3.00.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use instead __try_join_for, __try_join_until.
|
||||
]
|
||||
|
||||
@@ -991,6 +973,21 @@ or 0 if this information is not available.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:physical_concurrency Static member function `physical_concurrency()`]
|
||||
|
||||
unsigned physical_concurrency() noexecpt;
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Returns:] [The number of physical cores available on the current system. In contrast to `hardware_concurrency()` it does not return
|
||||
the number of virtual cores, but it counts only physical cores.]]
|
||||
|
||||
[[Throws:] [Nothing]]
|
||||
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:nativehandle Member function `native_handle()`]
|
||||
|
||||
typedef platform-specific-type native_handle_type;
|
||||
@@ -1014,8 +1011,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
|
||||
[warning
|
||||
DEPRECATED since 4.0.0.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use `a.__get_id()==b.__get_id()` instead`.
|
||||
]
|
||||
|
||||
@@ -1036,8 +1031,6 @@ Use `a.__get_id()==b.__get_id()` instead`.
|
||||
[warning
|
||||
DEPRECATED since 4.0.0.
|
||||
|
||||
Available only up to Boost 1.58.
|
||||
|
||||
Use `a.__get_id()!=b.__get_id()` instead`.
|
||||
]
|
||||
|
||||
@@ -1056,8 +1049,6 @@ Use `a.__get_id()!=b.__get_id()` instead`.
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
|
||||
]
|
||||
|
||||
@@ -1081,8 +1072,6 @@ Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`.
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `this_thread::__yield()`.
|
||||
]
|
||||
|
||||
@@ -1474,8 +1463,6 @@ thread attributes implementation. If no such instance exists, `native_handle()`
|
||||
[warning
|
||||
DEPRECATED since 3.0.0.
|
||||
|
||||
Available only up to Boost 1.56.
|
||||
|
||||
Use `__sleep_for()` and `__sleep_until()` instead.
|
||||
]
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ class bounded_buffer : private boost::noncopyable
|
||||
public:
|
||||
typedef boost::unique_lock<boost::mutex> lock;
|
||||
|
||||
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
bounded_buffer(int n) : boost::noncopyable(), begin(0), end(0), buffered(0), circular_buf(n) { }
|
||||
|
||||
void send (int m) {
|
||||
lock lk(monitor);
|
||||
|
||||
146
example/executor.cpp
Normal file
146
example/executor.cpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/loop_executor.hpp>
|
||||
#include <boost/thread/executors/serial_executor.hpp>
|
||||
#include <boost/thread/executors/inline_executor.hpp>
|
||||
#include <boost/thread/executors/thread_executor.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
#include <boost/thread/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
void p1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
//boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
//boost::this_thread::sleep_for(boost::chrono::seconds(10));
|
||||
}
|
||||
|
||||
int f1()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 1;
|
||||
}
|
||||
int f2(int i)
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(2));
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
void submit_some(boost::executor& tp)
|
||||
{
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tp.submit(&p2);
|
||||
}
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tp.submit(&p1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void at_th_entry(boost::basic_thread_pool& )
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
boost::executor_adaptor < boost::basic_thread_pool > ea(4);
|
||||
submit_some( ea);
|
||||
{
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
boost::future<int> t2 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
submit_some(ea);
|
||||
{
|
||||
boost::basic_thread_pool ea3(1);
|
||||
boost::future<int> t1 = boost::async(ea3, &f1);
|
||||
boost::future<int> t2 = boost::async(ea3, &f1);
|
||||
//boost::future<int> t2 = boost::async(ea3, f2, 1); // todo this doesn't compiles yet on C++11
|
||||
//boost::future<int> t2 = boost::async(ea3, boost::bind(f2, 1)); // todo this doesn't compiles yet on C++98
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
// std::cout << BOOST_CONTEXTOF << " t2= " << t2.get() << std::endl;
|
||||
}
|
||||
submit_some(ea);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::loop_executor > ea2;
|
||||
submit_some( ea2);
|
||||
ea2.underlying_executor().run_queued_closures();
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::basic_thread_pool > ea1(4);
|
||||
boost::executor_adaptor < boost::serial_executor > ea2(ea1);
|
||||
submit_some(ea2);
|
||||
}
|
||||
#endif
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::inline_executor > ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::executor_adaptor < boost::thread_executor > ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea(4, at_th_entry);
|
||||
boost::future<int> t1 = boost::async(ea, &f1);
|
||||
// std::cout << BOOST_CONTEXTOF << " t1= " << t1.get() << std::endl;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
return 0;
|
||||
}
|
||||
106
example/future_fallback_to.cpp
Normal file
106
example/future_fallback_to.cpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
|
||||
int p1_ex()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
throw std::logic_error("kk");
|
||||
}
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
return 1;;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
//boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(&p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.fallback_to(-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f2.wait();
|
||||
BOOST_ASSERT(f2.get()==1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1_ex);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.fallback_to(-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
f2.wait();
|
||||
BOOST_ASSERT(f2.get()==-1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -3,8 +3,18 @@
|
||||
// Distributed under the 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>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
//&& ! defined BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
@@ -19,15 +29,16 @@ int p1()
|
||||
return 123;
|
||||
}
|
||||
|
||||
int p2(boost::future<int>& f)
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << "P2<" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
@@ -38,25 +49,78 @@ int p2(boost::future<int>& f)
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
int p2s(boost::shared_future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG << "<P2S" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
(void)f2.get();
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2S>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(&p1);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.then(&p2);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
(void)f2.get();
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
{
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::shared_future<int> f1 = boost::async(&p1).share();
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = f1.then(&p2s);
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
(void)f2.get();
|
||||
BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
|
||||
73
example/future_unwrap.cpp
Normal file
73
example/future_unwrap.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
|
||||
return 123;
|
||||
}
|
||||
|
||||
boost::future<int> p2()
|
||||
{
|
||||
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
|
||||
return boost::move(f1);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
|
||||
boost::future<int> inner_future = outer_future.unwrap();
|
||||
int ii = inner_future.get();
|
||||
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
166
example/future_when_all.cpp
Normal file
166
example/future_when_all.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <string>
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
|
||||
int p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "P1" << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 123;
|
||||
}
|
||||
int p1b()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "P1b" << BOOST_THREAD_END_LOG;
|
||||
boost::this_thread::sleep_for(boost::chrono::seconds(1));
|
||||
return 321;
|
||||
}
|
||||
|
||||
int p2(boost::future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " P2 " << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "P2>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
int p2s(boost::shared_future<int> f)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "<P2" << BOOST_THREAD_END_LOG;
|
||||
try
|
||||
{
|
||||
return 2 * f.get();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "P2>" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<std::tuple<> > all0 = boost::when_all();
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<std::tuple<> > all0 = boost::when_any();
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::vector<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
using namespace boost;
|
||||
|
||||
void f( boost::csbl::vector<future<int> > &//vec
|
||||
, BOOST_THREAD_RV_REF(future<int>) //f
|
||||
) {
|
||||
//vec.push_back(boost::forward<future<int> >(f));
|
||||
}
|
||||
int main()
|
||||
{
|
||||
boost::csbl::vector<future<int> > vec;
|
||||
f(vec, make_ready_future(0));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -8,22 +8,30 @@
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
&& ! defined BOOST_NO_CXX11_LAMBDAS && ! (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
|
||||
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
{
|
||||
@@ -33,18 +41,20 @@ int main()
|
||||
}
|
||||
{
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
|
||||
boost::future<int> f2 = f1.then([](boost::future<int>& f) {return 2*f.get(); });
|
||||
boost::future<int> f2 = f1.then([](boost::future<int> f) {return 2*f.get(); });
|
||||
int result = f2.get();
|
||||
BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERRORRRRR exception thrown" << std::endl;
|
||||
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -3,59 +3,127 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
exception_ptr make_exception_ptr(T v)
|
||||
{
|
||||
return copy_exception(v);
|
||||
}
|
||||
}
|
||||
|
||||
int p1() { return 5; }
|
||||
int& p1r() { static int i=0; return i; }
|
||||
|
||||
void p() { }
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
boost::future<void> void_compute()
|
||||
{
|
||||
return BOOST_THREAD_MAKE_RV_REF(boost::make_future());
|
||||
return BOOST_THREAD_MAKE_RV_REF(boost::make_ready_future());
|
||||
}
|
||||
#endif
|
||||
|
||||
boost::future<int> compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_future(0);
|
||||
if (x < 0) return boost::make_future(-1);
|
||||
if (x == 0) return boost::make_ready_future(0);
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
if (x < 0) return boost::make_exceptional_future<int>(std::logic_error("Error"));
|
||||
#else
|
||||
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
|
||||
#endif
|
||||
//boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, p1);
|
||||
boost::future<int> f1 = boost::async(p1);
|
||||
return boost::move(f1);
|
||||
}
|
||||
|
||||
boost::future<int&> compute_ref(int x)
|
||||
{
|
||||
static int i = 0;
|
||||
//if (x == 0) return boost::make_ready_future<int&>(i); //This must not compile as the type is deduced as boost::future<int>
|
||||
if (x == 0) return boost::make_ready_no_decay_future<int&>(i);
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
if (x < 0) return boost::make_exceptional_future<int&>(std::logic_error("Error"));
|
||||
#else
|
||||
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
|
||||
#endif
|
||||
boost::future<int&> f1 = boost::async(p1r);
|
||||
return boost::move(f1);
|
||||
}
|
||||
|
||||
boost::shared_future<int> shared_compute(int x)
|
||||
{
|
||||
if (x == 0) return boost::make_shared_future(0);
|
||||
if (x < 0) return boost::make_shared_future(-1);
|
||||
if (x == 0) return boost::make_ready_future(0).share();
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
if (x < 0) return boost::make_exceptional_future<int>(std::logic_error("Error")).share();
|
||||
#else
|
||||
if (x < 0) return boost::make_exceptional(std::logic_error("Error"));
|
||||
#endif
|
||||
//boost::future<int> f1 = boost::async([]() { return x+1; });
|
||||
boost::shared_future<int> f1 = boost::async(p1).share();
|
||||
return boost::move(f1);
|
||||
boost::shared_future<int> f1 = boost::async(&p1).share();
|
||||
return f1;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
const int number_of_tests = 100;
|
||||
for (int i=0; i< number_of_tests; i++)
|
||||
try
|
||||
{
|
||||
// {
|
||||
// std::cout << __FILE__ << " "<<__LINE__ << std::endl;
|
||||
// boost::future<int> f = boost::async(boost::launch::async, p1);
|
||||
// std::cout << i << " "<<f.get() << std::endl;
|
||||
// }
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<void> f = void_compute();
|
||||
f.get();
|
||||
}
|
||||
#endif
|
||||
{
|
||||
boost::future<int> f = compute(2);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int> f = compute(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
{
|
||||
boost::shared_future<int> f = shared_compute(2);
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::future<int&> f = compute_ref(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
// {
|
||||
// std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
// boost::future<int> f = compute(2);
|
||||
// std::cout << f.get() << std::endl;
|
||||
// }
|
||||
{
|
||||
std::cout << __FILE__ << " "<< __LINE__ << std::endl;
|
||||
boost::shared_future<int> f = shared_compute(0);
|
||||
std::cout << f.get() << std::endl;
|
||||
}
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << "ERRORRRRR "<<"ERRORRRRR exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ int main()
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
|
||||
scoped_thread<> t1(thread(use_cerr, boost::ref(mcerr)));
|
||||
scoped_thread<> t2(thread(use_cout, boost::ref(mcout)));
|
||||
scoped_thread<> t1(boost::thread(use_cerr, boost::ref(mcerr)));
|
||||
scoped_thread<> t2(boost::thread(use_cout, boost::ref(mcout)));
|
||||
this_thread::sleep_for(chrono::seconds(2));
|
||||
std::string nm;
|
||||
{
|
||||
|
||||
61
example/not_interleaved2.cpp
Normal file
61
example/not_interleaved2.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// (C) Copyright 2012 Howard Hinnant
|
||||
// (C) Copyright 2012 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/ostream_buffer.hpp>
|
||||
|
||||
void use_cerr()
|
||||
{
|
||||
using namespace boost;
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
int i = 0;
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
ostream_buffer<std::ostream> mcerr(std::cerr);
|
||||
mcerr.stream() << "logging data to cerr " << i++ << "\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
|
||||
void use_cout()
|
||||
{
|
||||
using namespace boost;
|
||||
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
|
||||
int i = 0;
|
||||
while (chrono::steady_clock::now() < tf)
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << "logging data to cout " << i++ << "\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
scoped_thread<> t1(&use_cerr);
|
||||
scoped_thread<> t2(&use_cout);
|
||||
this_thread::sleep_for(chrono::seconds(2));
|
||||
std::string nm = "he, he\n";
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << "Enter name: \n";
|
||||
}
|
||||
t1.join();
|
||||
t2.join();
|
||||
{
|
||||
ostream_buffer<std::ostream> mcout(std::cout);
|
||||
mcout.stream() << nm;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
100
example/parallel_accumulate.cpp
Normal file
100
example/parallel_accumulate.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
//#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
template<typename Iterator,typename T>
|
||||
struct accumulate_block
|
||||
{
|
||||
//typedef T result_type;
|
||||
T operator()(Iterator first,Iterator last)
|
||||
{
|
||||
return std::accumulate(first,last,T());
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Iterator,typename T>
|
||||
T parallel_accumulate(Iterator first,Iterator last,T init)
|
||||
{
|
||||
unsigned long const length=std::distance(first,last);
|
||||
|
||||
if(!length)
|
||||
return init;
|
||||
|
||||
unsigned long const block_size=25;
|
||||
unsigned long const num_blocks=(length+block_size-1)/block_size;
|
||||
|
||||
boost::csbl::vector<boost::future<T> > futures(num_blocks-1);
|
||||
boost::basic_thread_pool pool;
|
||||
|
||||
Iterator block_start=first;
|
||||
for(unsigned long i=0;i<(num_blocks-1);++i)
|
||||
{
|
||||
Iterator block_end=block_start;
|
||||
std::advance(block_end,block_size);
|
||||
futures[i]=boost::async(pool, accumulate_block<Iterator,T>(), block_start, block_end);
|
||||
block_start=block_end;
|
||||
}
|
||||
T last_result=accumulate_block<Iterator,T>()(block_start,last);
|
||||
T result=init;
|
||||
for(unsigned long i=0;i<(num_blocks-1);++i)
|
||||
{
|
||||
result+=futures[i].get();
|
||||
}
|
||||
result += last_result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
const int s = 1001;
|
||||
std::vector<int> vec;
|
||||
vec.reserve(s);
|
||||
for (int i=0; i<s;++i)
|
||||
vec.push_back(1);
|
||||
int r = parallel_accumulate(vec.begin(), vec.end(),0);
|
||||
std::cout << r << std::endl;
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
///#warning "This compiler doesn't supports variadics"
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
109
example/parallel_quick_sort.cpp
Normal file
109
example/parallel_quick_sort.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
//#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
|
||||
//#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
|
||||
//#endif
|
||||
|
||||
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
|
||||
#include <numeric>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
|
||||
template<typename T>
|
||||
struct sorter
|
||||
{
|
||||
boost::basic_thread_pool pool;
|
||||
typedef std::list<T> return_type;
|
||||
|
||||
std::list<T> do_sort(std::list<T> chunk_data)
|
||||
{
|
||||
if(chunk_data.empty())
|
||||
{
|
||||
return chunk_data;
|
||||
}
|
||||
|
||||
std::list<T> result;
|
||||
result.splice(result.begin(),chunk_data, chunk_data.begin());
|
||||
T const& partition_val=*result.begin();
|
||||
|
||||
typename std::list<T>::iterator divide_point=
|
||||
std::partition(chunk_data.begin(), chunk_data.end(), [&](T const& val){return val<partition_val;});
|
||||
|
||||
std::list<T> new_lower_chunk;
|
||||
new_lower_chunk.splice(new_lower_chunk.end(), chunk_data, chunk_data.begin(), divide_point);
|
||||
|
||||
boost::future<std::list<T> > new_lower = boost::async(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
|
||||
//boost::future<std::list<T> > new_lower = boost::async<return_type>(pool, &sorter::do_sort, this, std::move(new_lower_chunk));
|
||||
|
||||
std::list<T> new_higher(do_sort(chunk_data));
|
||||
|
||||
result.splice(result.end(),new_higher);
|
||||
while(!new_lower.is_ready())
|
||||
{
|
||||
pool.schedule_one_or_yield();
|
||||
}
|
||||
|
||||
result.splice(result.begin(),new_lower.get());
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
std::list<T> parallel_quick_sort(std::list<T>& input)
|
||||
{
|
||||
if(input.empty())
|
||||
{
|
||||
return input;
|
||||
}
|
||||
sorter<T> s;
|
||||
|
||||
return s.do_sort(input);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
try
|
||||
{
|
||||
const int s = 101;
|
||||
std::list<int> lst;
|
||||
for (int i=0; i<s;++i)
|
||||
lst.push_back(100-i);
|
||||
std::list<int> r = parallel_quick_sort(lst);
|
||||
for (std::list<int>::const_iterator it=r.begin(); it != r.end(); ++it)
|
||||
std::cout << *it << std::endl;
|
||||
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cout << "ERROR= " << ex.what() << "" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << " ERROR= exception thrown" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
//#warning "This compiler doesn't supports variadics and move semantics"
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -143,7 +143,7 @@ namespace
|
||||
{
|
||||
typedef SharedData<Types> S;
|
||||
|
||||
auto best_producer_time = std::numeric_limits<Stopwatch::rep>::max();
|
||||
auto best_producer_time = std::numeric_limits<Stopwatch::rep>::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
|
||||
|
||||
std::vector<std::thread> consumers
|
||||
{ consumer_count };
|
||||
@@ -165,7 +165,7 @@ namespace
|
||||
for (unsigned i = 0; i < consumer_count; ++i)
|
||||
consumers[i].join();
|
||||
|
||||
best_producer_time = std::min(best_producer_time, shared_data.producer_time);
|
||||
best_producer_time = std::min BOOST_PREVENT_MACRO_SUBSTITUTION (best_producer_time, shared_data.producer_time);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ void unique()
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::chrono::high_resolution_clock::duration best_time(std::numeric_limits<boost::chrono::high_resolution_clock::duration::rep>::max());
|
||||
boost::chrono::high_resolution_clock::duration best_time(std::numeric_limits<boost::chrono::high_resolution_clock::duration::rep>::max BOOST_PREVENT_MACRO_SUBSTITUTION ());
|
||||
for (int i =100; i>0; --i) {
|
||||
boost::chrono::high_resolution_clock clock;
|
||||
boost::chrono::high_resolution_clock::time_point s1 = clock.now();
|
||||
@@ -61,7 +61,7 @@ int main()
|
||||
// t13.join();
|
||||
boost::chrono::high_resolution_clock::time_point f1 = clock.now();
|
||||
//std::cout << " Time spent:" << (f1 - s1) << std::endl;
|
||||
best_time = std::min(best_time, f1 - s1);
|
||||
best_time = std::min BOOST_PREVENT_MACRO_SUBSTITUTION (best_time, f1 - s1);
|
||||
|
||||
}
|
||||
std::cout << "Best Time spent:" << best_time << std::endl;
|
||||
|
||||
@@ -7,21 +7,28 @@
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#ifdef XXXX
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
typedef boost::externally_locked_stream<std::ostream> the_ostream;
|
||||
#else
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
|
||||
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
void producer(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
//sbq.push(i);
|
||||
sbq << i;
|
||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
sbq.push_back(i);
|
||||
//sbq << i;
|
||||
mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
@@ -35,16 +42,19 @@ void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_qu
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
void consumer(
|
||||
the_ostream &mos,
|
||||
boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
//sbq.pull(r);
|
||||
sbq >> r;
|
||||
sbq.pull_front(r);
|
||||
//sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
@@ -57,17 +67,18 @@ void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_qu
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
bool closed=false;
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r, closed);
|
||||
if (closed) break;
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
queue_op_status st = sbq.try_pull_front(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
@@ -76,7 +87,7 @@ void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_q
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
|
||||
//void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
@@ -100,19 +111,25 @@ int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#ifdef XXXX
|
||||
recursive_mutex terminal_mutex;
|
||||
|
||||
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
#else
|
||||
the_ostream &mcerr = std::cout;
|
||||
the_ostream &mcout = std::cerr;
|
||||
//the_istream &mcin = std::cin;
|
||||
#endif
|
||||
|
||||
sync_queue<int> sbq;
|
||||
|
||||
{
|
||||
mcout << "begin of main" << std::endl;
|
||||
scoped_thread<> t11(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
|
||||
@@ -7,76 +7,86 @@
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
//#define XXXX
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#ifdef XXXX
|
||||
#include <boost/thread/externally_locked_stream.hpp>
|
||||
typedef boost::externally_locked_stream<std::ostream> the_ostream;
|
||||
#else
|
||||
typedef std::ostream the_ostream;
|
||||
typedef std::istream the_istream;
|
||||
#endif
|
||||
|
||||
#include <boost/thread/sync_bounded_queue.hpp>
|
||||
|
||||
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
void producer(the_ostream &/*mos*/, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
//sbq.push(i);
|
||||
sbq << i;
|
||||
mos << "push(" << i << ") "<< sbq.size()<<"\n";
|
||||
sbq.push_back(i);
|
||||
//sbq << i;
|
||||
//mos << "push_back(" << i << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
void consumer(the_ostream &/*mos*/, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
//sbq.pull(r);
|
||||
sbq >> r;
|
||||
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
|
||||
sbq.pull_front(r);
|
||||
//sbq >> r;
|
||||
//mos << i << " pull_front(" << r << ") "<< sbq.size()<<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
//mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
void consumer2(the_ostream &/*mos*/, boost::sync_bounded_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
bool closed=false;
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
sbq.pull(r, closed);
|
||||
if (closed) break;
|
||||
mos << i << " pull(" << r << ")\n";
|
||||
queue_op_status st = sbq.try_pull_front(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
//mos << i << " pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
//mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
//void consumer3(the_ostream &mos, boost::sync_bounded_queue<int> & sbq)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
@@ -86,33 +96,38 @@ void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_b
|
||||
// int r;
|
||||
// queue_op_status res = sbq.wait_and_pull(r);
|
||||
// if (res==queue_op_status::closed) break;
|
||||
// mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// //mos << i << " wait_and_pull(" << r << ")\n";
|
||||
// this_thread::sleep_for(chrono::milliseconds(250));
|
||||
// }
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// mos << "exception !!!\n";
|
||||
// //mos << "exception !!!\n";
|
||||
// }
|
||||
//}
|
||||
|
||||
int main()
|
||||
{
|
||||
using namespace boost;
|
||||
|
||||
#ifdef XXXX
|
||||
recursive_mutex terminal_mutex;
|
||||
|
||||
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
|
||||
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
|
||||
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
|
||||
#else
|
||||
the_ostream &mcerr = std::cout;
|
||||
the_ostream &mcout = std::cerr;
|
||||
//the_istream &mcin = std::cin;
|
||||
#endif
|
||||
|
||||
sync_bounded_queue<int> sbq(10);
|
||||
|
||||
{
|
||||
mcout << "begin of main" << std::endl;
|
||||
scoped_thread<> t11(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
|
||||
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ void do_something(int& i)
|
||||
{
|
||||
++i;
|
||||
}
|
||||
void f(int, int)
|
||||
{
|
||||
}
|
||||
|
||||
struct func
|
||||
{
|
||||
@@ -81,7 +84,10 @@ int main()
|
||||
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
|
||||
{
|
||||
boost::scoped_thread<> g( &f, 1, 2 );
|
||||
do_something_in_current_thread();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#undef BOOST_THREAD_VERSION
|
||||
#define BOOST_THREAD_VERSION 2
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/condition.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
|
||||
68
example/thread_pool.cpp
Normal file
68
example/thread_pool.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
// Copyright (C) 2012-2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void submit_some(boost::basic_thread_pool& tp) {
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::basic_thread_pool tp;
|
||||
submit_some(tp);
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
70
example/user_scheduler.cpp
Normal file
70
example/user_scheduler.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright (C) 2013 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/loop_executor.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <string>
|
||||
|
||||
void p1()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void p2()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
|
||||
void submit_some(boost::loop_executor& tp) {
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
tp.submit(&p1);
|
||||
tp.submit(&p2);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
|
||||
{
|
||||
try
|
||||
{
|
||||
boost::loop_executor tp;
|
||||
submit_some(tp);
|
||||
tp.run_queued_closures();
|
||||
submit_some(tp);
|
||||
tp.run_queued_closures();
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BOOST_THREAD_LOG
|
||||
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
53
example/with_lock_guard.cpp
Normal file
53
example/with_lock_guard.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// (C) Copyright 2013 Ruslan Baratov
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// See www.boost.org/libs/thread for documentation.
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
|
||||
#include <iostream> // std::cout
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/with_lock_guard.hpp>
|
||||
|
||||
boost::mutex m; // protection for 'x' and 'std::cout'
|
||||
int x;
|
||||
|
||||
#if defined(BOOST_NO_CXX11_LAMBDAS) || (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
void print_x() {
|
||||
++x;
|
||||
std::cout << "x = " << x << std::endl;
|
||||
}
|
||||
|
||||
void job() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
boost::with_lock_guard(m, print_x);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
#else
|
||||
void job() {
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
boost::with_lock_guard(
|
||||
m,
|
||||
[]() {
|
||||
++x;
|
||||
std::cout << "x = " << x << std::endl;
|
||||
}
|
||||
);
|
||||
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
#if defined(BOOST_NO_CXX11_LAMBDAS) || (defined BOOST_MSVC && _MSC_VER < 1700)
|
||||
std::cout << "(no lambdas)" << std::endl;
|
||||
#endif
|
||||
boost::scoped_thread<> thread_1((boost::thread(job)));
|
||||
boost::scoped_thread<> thread_2((boost::thread(job)));
|
||||
boost::scoped_thread<> thread_3((boost::thread(job)));
|
||||
return 0;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (C) 2002-2003
|
||||
// David Moore, William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -17,51 +18,228 @@
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_void.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/utility/result_of.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
typedef detail::nullary_function<void()> void_completion_function;
|
||||
typedef detail::nullary_function<size_t()> size_completion_function;
|
||||
|
||||
class barrier
|
||||
struct default_barrier_reseter
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( barrier )
|
||||
unsigned int size_;
|
||||
default_barrier_reseter(unsigned int size) :
|
||||
size_(size)
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE(default_barrier_reseter)
|
||||
|
||||
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."));
|
||||
}
|
||||
default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_)
|
||||
{
|
||||
}
|
||||
default_barrier_reseter(BOOST_THREAD_RV_REF(default_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_)
|
||||
{
|
||||
}
|
||||
|
||||
bool wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> 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;
|
||||
unsigned int operator()()
|
||||
{
|
||||
return size_;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
struct void_functor_barrier_reseter
|
||||
{
|
||||
unsigned int size_;
|
||||
void_completion_function fct_;
|
||||
template <typename F>
|
||||
void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct)
|
||||
: size_(size), fct_(boost::move(funct))
|
||||
{}
|
||||
template <typename F>
|
||||
void_functor_barrier_reseter(unsigned int size, F& funct)
|
||||
: size_(size), fct_(funct)
|
||||
{}
|
||||
|
||||
BOOST_THREAD_MOVABLE(void_functor_barrier_reseter)
|
||||
|
||||
void_functor_barrier_reseter(void_functor_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_), fct_(other.fct_)
|
||||
{
|
||||
}
|
||||
void_functor_barrier_reseter(BOOST_THREAD_RV_REF(void_functor_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int operator()()
|
||||
{
|
||||
fct_();
|
||||
return size_;
|
||||
}
|
||||
};
|
||||
struct void_fct_ptr_barrier_reseter
|
||||
{
|
||||
unsigned int size_;
|
||||
void(*fct_)();
|
||||
void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) :
|
||||
size_(size), fct_(funct)
|
||||
{
|
||||
}
|
||||
BOOST_THREAD_MOVABLE(void_fct_ptr_barrier_reseter)
|
||||
|
||||
void_fct_ptr_barrier_reseter(void_fct_ptr_barrier_reseter const& other) BOOST_NOEXCEPT :
|
||||
size_(other.size_), fct_(other.fct_)
|
||||
{
|
||||
}
|
||||
void_fct_ptr_barrier_reseter(BOOST_THREAD_RV_REF(void_fct_ptr_barrier_reseter) other) BOOST_NOEXCEPT :
|
||||
size_(BOOST_THREAD_RV(other).size_), fct_(BOOST_THREAD_RV(other).fct_)
|
||||
{
|
||||
}
|
||||
unsigned int operator()()
|
||||
{
|
||||
fct_();
|
||||
return size_;
|
||||
}
|
||||
};
|
||||
}
|
||||
class barrier
|
||||
{
|
||||
static inline unsigned int check_counter(unsigned int count)
|
||||
{
|
||||
if (count == 0) boost::throw_exception(
|
||||
thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
|
||||
return count;
|
||||
}
|
||||
struct dummy
|
||||
{
|
||||
};
|
||||
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( barrier)
|
||||
|
||||
explicit barrier(unsigned int count) :
|
||||
m_count(check_counter(count)), m_generation(0), fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count)))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
BOOST_THREAD_RV_REF(F) funct,
|
||||
typename enable_if<
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count,
|
||||
boost::move(funct)))
|
||||
)
|
||||
{
|
||||
}
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
F &funct,
|
||||
typename enable_if<
|
||||
typename is_void<typename result_of<F>::type>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_functor_barrier_reseter(count,
|
||||
funct))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
BOOST_THREAD_RV_REF(F) funct,
|
||||
typename enable_if<
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(boost::move(funct))
|
||||
{
|
||||
}
|
||||
template <typename F>
|
||||
barrier(
|
||||
unsigned int count,
|
||||
F& funct,
|
||||
typename enable_if<
|
||||
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
|
||||
>::type=0
|
||||
)
|
||||
: m_count(check_counter(count)),
|
||||
m_generation(0),
|
||||
fct_(funct)
|
||||
{
|
||||
}
|
||||
|
||||
barrier(unsigned int count, void(*funct)()) :
|
||||
m_count(check_counter(count)), m_generation(0),
|
||||
fct_(funct
|
||||
? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::void_fct_ptr_barrier_reseter(count, funct))))
|
||||
: BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))))
|
||||
)
|
||||
{
|
||||
}
|
||||
barrier(unsigned int count, unsigned int(*funct)()) :
|
||||
m_count(check_counter(count)), m_generation(0),
|
||||
fct_(funct
|
||||
? BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(funct))
|
||||
: BOOST_THREAD_MAKE_RV_REF(thread_detail::size_completion_function(BOOST_THREAD_MAKE_RV_REF(thread_detail::default_barrier_reseter(count))))
|
||||
)
|
||||
{
|
||||
}
|
||||
|
||||
bool wait()
|
||||
{
|
||||
boost::unique_lock < boost::mutex > lock(m_mutex);
|
||||
unsigned int gen = m_generation;
|
||||
|
||||
if (--m_count == 0)
|
||||
{
|
||||
m_generation++;
|
||||
m_count = static_cast<unsigned int>(fct_());
|
||||
BOOST_ASSERT(m_count != 0);
|
||||
m_cond.notify_all();
|
||||
return true;
|
||||
}
|
||||
|
||||
while (gen == m_generation)
|
||||
m_cond.wait(lock);
|
||||
return false;
|
||||
}
|
||||
|
||||
void count_down_and_wait()
|
||||
{
|
||||
wait();
|
||||
}
|
||||
|
||||
private:
|
||||
mutex m_mutex;
|
||||
condition_variable m_cond;
|
||||
unsigned int m_count;
|
||||
unsigned int m_generation;
|
||||
thread_detail::size_completion_function fct_;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
|
||||
56
include/boost/thread/caller_context.hpp
Normal file
56
include/boost/thread/caller_context.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_CALL_CONTEXT_HPP
|
||||
#define BOOST_THREAD_CALL_CONTEXT_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#include <boost/thread/thread.hpp>
|
||||
#endif
|
||||
#include <boost/current_function.hpp>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
struct caller_context_t
|
||||
{
|
||||
const char * filename;
|
||||
unsigned lineno;
|
||||
const char * func;
|
||||
caller_context_t(const char * filename, unsigned lineno, const char * func) :
|
||||
filename(filename), lineno(lineno), func(func)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
#define BOOST_CONTEXTOF boost::caller_context_t(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION)
|
||||
|
||||
template <typename OStream>
|
||||
OStream& operator<<(OStream& os, caller_context_t const& ctx)
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
{
|
||||
io::ios_flags_saver ifs( os );
|
||||
os << std::left << std::setw(14) << boost::this_thread::get_id() << " ";
|
||||
}
|
||||
#endif
|
||||
{
|
||||
io::ios_flags_saver ifs(os);
|
||||
os << ctx.filename << "["
|
||||
<< std::setw(4) << std::right << std::dec<< ctx.lineno << "] ";
|
||||
os << ctx.func << " " ;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -16,12 +16,8 @@
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <boost/function.hpp>
|
||||
#else
|
||||
#include <functional>
|
||||
#endif
|
||||
//#include <boost/thread/latch.hpp>
|
||||
//#include <boost/thread/detail/nullary_function.hpp>
|
||||
#include <boost/thread/csbl/functional.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -37,11 +33,8 @@ namespace boost
|
||||
{
|
||||
public:
|
||||
/// the implementation defined completion function type
|
||||
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
typedef function<void()> completion_function;
|
||||
#else
|
||||
typedef std::function<void()> completion_function;
|
||||
#endif
|
||||
//typedef detail::nullary_function<void()> completion_function;
|
||||
typedef csbl::function<void()> completion_function;
|
||||
/// noop completion function factory
|
||||
static completion_function noop()
|
||||
{
|
||||
|
||||
37
include/boost/thread/csbl/deque.hpp
Normal file
37
include/boost/thread/csbl/deque.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_DEQUE_HPP
|
||||
#define BOOST_CSBL_DEQUE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#define BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#endif
|
||||
#include <boost/container/deque.hpp>
|
||||
#else
|
||||
#include <deque>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE
|
||||
using ::boost::container::deque;
|
||||
|
||||
#else
|
||||
using ::std::deque;
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
49
include/boost/thread/csbl/functional.hpp
Normal file
49
include/boost/thread/csbl/functional.hpp
Normal file
@@ -0,0 +1,49 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_FUNCTIONAL_HPP
|
||||
#define BOOST_CSBL_FUNCTIONAL_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL || defined BOOST_NO_CXX11_HDR_FUNCTIONAL || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_FUNCTIONAL
|
||||
#define BOOST_THREAD_USES_BOOST_FUNCTIONAL
|
||||
#endif
|
||||
#include <boost/function.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_FUNCTIONAL
|
||||
using ::boost::function;
|
||||
#else
|
||||
// D.8.1, base (deprecated):
|
||||
// 20.9.3, reference_wrapper:
|
||||
// 20.9.4, arithmetic operations:
|
||||
// 20.9.5, comparisons:
|
||||
// 20.9.6, logical operations:
|
||||
// 20.9.7, bitwise operations:
|
||||
// 20.9.8, negators:
|
||||
// 20.9.9, bind:
|
||||
// D.9, binders (deprecated):
|
||||
// D.8.2.1, adaptors (deprecated):
|
||||
// D.8.2.2, adaptors (deprecated):
|
||||
// 20.9.10, member function adaptors:
|
||||
// 20.9.11 polymorphic function wrappers:
|
||||
using ::std::function;
|
||||
// 20.9.12, hash function primary template:
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/list.hpp
Normal file
35
include/boost/thread/csbl/list.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_LIST_HPP
|
||||
#define BOOST_CSBL_LIST_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_LIST || defined BOOST_NO_CXX11_HDR_LIST || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_LIST
|
||||
#define BOOST_THREAD_USES_BOOST_LIST
|
||||
#endif
|
||||
#include <boost/container/list.hpp>
|
||||
#else
|
||||
#include <list>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_LIST
|
||||
using ::boost::container::list;
|
||||
#else
|
||||
using ::std::list;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
61
include/boost/thread/csbl/memory.hpp
Normal file
61
include/boost/thread/csbl/memory.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_HPP
|
||||
#define BOOST_CSBL_MEMORY_HPP
|
||||
|
||||
// 20.7.2 Header <memory> synopsis
|
||||
|
||||
// 20.7.3, pointer traits
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
|
||||
// 20.7.4, pointer safety
|
||||
// 20.7.5, pointer alignment function
|
||||
|
||||
// 20.7.6, allocator argument tag
|
||||
#include <boost/thread/csbl/memory/allocator_arg.hpp>
|
||||
|
||||
// 20.7.8, allocator traits
|
||||
#include <boost/thread/csbl/memory/allocator_traits.hpp>
|
||||
|
||||
// 20.7.7, uses_allocator
|
||||
#include <boost/thread/csbl/memory/scoped_allocator.hpp>
|
||||
|
||||
// 20.7.9, the default allocator:
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::allocator;
|
||||
}
|
||||
}
|
||||
// 20.7.10, raw storage iterator:
|
||||
// 20.7.11, temporary buffers:
|
||||
// 20.7.12, specialized algorithms:
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
// default_delete
|
||||
#include <boost/thread/csbl/memory/default_delete.hpp>
|
||||
#include <boost/thread/csbl/memory/unique_ptr.hpp>
|
||||
|
||||
// 20.8.2.1, class bad_weak_ptr:
|
||||
// 20.8.2.2, class template shared_ptr:
|
||||
// 20.8.2.2.6, shared_ptr creation
|
||||
// 20.8.2.2.7, shared_ptr comparisons:
|
||||
// 20.8.2.2.8, shared_ptr specialized algorithms:
|
||||
// 20.8.2.2.9, shared_ptr casts:
|
||||
// 20.8.2.2.10, shared_ptr get_deleter:
|
||||
// 20.8.2.2.11, shared_ptr I/O:
|
||||
// 20.8.2.3, class template weak_ptr:
|
||||
// 20.8.2.3.6, weak_ptr specialized algorithms:
|
||||
// 20.8.2.3.7, class template owner_less:
|
||||
// 20.8.2.4, class template enable_shared_from_this:
|
||||
// 20.8.2.5, shared_ptr atomic access:
|
||||
// 20.8.2.6 hash support
|
||||
|
||||
#endif // header
|
||||
41
include/boost/thread/csbl/memory/allocator_arg.hpp
Normal file
41
include/boost/thread/csbl/memory/allocator_arg.hpp
Normal file
@@ -0,0 +1,41 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP
|
||||
#define BOOST_CSBL_MEMORY_ALLOCATOR_ARG_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.6, allocator argument tag
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::container::allocator_arg_t;
|
||||
using ::boost::container::allocator_arg;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::allocator_arg_t;
|
||||
using ::std::allocator_arg;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_ALLOCATOR
|
||||
namespace boost
|
||||
{
|
||||
using ::boost::csbl::allocator_arg_t;
|
||||
using ::boost::csbl::allocator_arg;
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/memory/allocator_traits.hpp
Normal file
35
include/boost/thread/csbl/memory/allocator_traits.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP
|
||||
#define BOOST_CSBL_MEMORY_ALLOCATOR_TRAITS_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.8, allocator traits
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::container::allocator_traits;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::allocator_traits;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_POINTER_TRAITS
|
||||
|
||||
#endif // header
|
||||
16
include/boost/thread/csbl/memory/config.hpp
Normal file
16
include/boost/thread/csbl/memory/config.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_CONFIG_HPP
|
||||
#define BOOST_CSBL_MEMORY_CONFIG_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#endif // header
|
||||
125
include/boost/thread/csbl/memory/default_delete.hpp
Normal file
125
include/boost/thread/csbl/memory/default_delete.hpp
Normal file
@@ -0,0 +1,125 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_DEFAULT_DELETE_HPP
|
||||
#define BOOST_CSBL_MEMORY_DEFAULT_DELETE_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
// default_delete
|
||||
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class _Ptr1, class _Ptr2,
|
||||
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
|
||||
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
|
||||
>::value
|
||||
>
|
||||
struct same_or_less_cv_qualified_imp
|
||||
: is_convertible<_Ptr1, _Ptr2>
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
|
||||
: false_type
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
|
||||
!is_pointer<_Ptr1>::value>
|
||||
struct same_or_less_cv_qualified
|
||||
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2>
|
||||
{};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
|
||||
: false_type
|
||||
{};
|
||||
|
||||
}
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
|
||||
{}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U>&,
|
||||
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT
|
||||
{}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (T* ptr) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
|
||||
{}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U[]>&,
|
||||
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT
|
||||
{}
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (U* ptr,
|
||||
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete [] ptr;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::default_delete;
|
||||
}
|
||||
}
|
||||
#endif // defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
namespace boost
|
||||
{
|
||||
using ::boost::csbl::default_delete;
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/memory/pointer_traits.hpp
Normal file
35
include/boost/thread/csbl/memory/pointer_traits.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP
|
||||
#define BOOST_CSBL_MEMORY_POINTER_TRAITS_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.3, pointer traits
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/intrusive/pointer_traits.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::intrusive::pointer_traits;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::pointer_traits;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_ALLOCATOR
|
||||
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/memory/scoped_allocator.hpp
Normal file
35
include/boost/thread/csbl/memory/scoped_allocator.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP
|
||||
#define BOOST_CSBL_MEMORY_SCOPED_ALLOCATOR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.7.7, uses_allocator
|
||||
#if defined BOOST_NO_CXX11_ALLOCATOR
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::container::uses_allocator;
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::uses_allocator;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_POINTER_TRAITS
|
||||
|
||||
#endif // header
|
||||
106
include/boost/thread/csbl/memory/unique_ptr.hpp
Normal file
106
include/boost/thread/csbl/memory/unique_ptr.hpp
Normal file
@@ -0,0 +1,106 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
#define BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
// 20.8.1 class template unique_ptr:
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
#include <boost/thread/csbl/memory/default_delete.hpp>
|
||||
|
||||
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
template <class T, class D = default_delete<T> > class unique_ptr :
|
||||
public ::boost::interprocess::unique_ptr<T,D>
|
||||
{
|
||||
typedef ::boost::interprocess::unique_ptr<T,D> base_type;
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr)
|
||||
protected:
|
||||
//typedef typename base_type::nat nat;
|
||||
//typedef typename base_type::nullptr_t nullptr_t;
|
||||
struct nat {int for_bool;};
|
||||
struct nat2 {int for_nullptr;};
|
||||
typedef int nat2::*nullptr_t;
|
||||
|
||||
public:
|
||||
typedef typename base_type::element_type element_type;
|
||||
typedef typename base_type::deleter_type deleter_type;
|
||||
typedef typename base_type::pointer pointer;
|
||||
|
||||
unique_ptr() : base_type()
|
||||
{}
|
||||
explicit unique_ptr(pointer p): base_type(p)
|
||||
{}
|
||||
unique_ptr(pointer p
|
||||
,typename interprocess::ipcdetail::if_<interprocess::ipcdetail::is_reference<D>
|
||||
,D
|
||||
,typename interprocess::ipcdetail::add_reference<const D>::type>::type d)
|
||||
: base_type(p, d)
|
||||
{}
|
||||
unique_ptr(BOOST_RV_REF(unique_ptr) u)
|
||||
: base_type(boost::move(static_cast<base_type&>(u)))
|
||||
{}
|
||||
template <class U, class E>
|
||||
unique_ptr(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u,
|
||||
typename interprocess::ipcdetail::enable_if_c<
|
||||
interprocess::ipcdetail::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
|
||||
interprocess::ipcdetail::is_convertible<E, D>::value &&
|
||||
(
|
||||
!interprocess::ipcdetail::is_reference<D>::value ||
|
||||
interprocess::ipcdetail::is_same<D, E>::value
|
||||
)
|
||||
,
|
||||
nat
|
||||
>::type = nat())
|
||||
: base_type(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)))
|
||||
{}
|
||||
unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u)
|
||||
{
|
||||
this->base_type::operator=(boost::move(static_cast<base_type&>(u)));
|
||||
return *this;
|
||||
}
|
||||
template <class U, class E>
|
||||
unique_ptr& operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u)
|
||||
{
|
||||
this->base_type::template operator=<U,E>(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)));
|
||||
return *this;
|
||||
}
|
||||
unique_ptr& operator=(nullptr_t t)
|
||||
{
|
||||
this->base_type::operator=(t);
|
||||
return *this;
|
||||
}
|
||||
void swap(unique_ptr& u)
|
||||
{
|
||||
this->base_type::swap(u);
|
||||
}
|
||||
};
|
||||
template <class T, class D>
|
||||
class unique_ptr<T[], D> :
|
||||
public ::boost::interprocess::unique_ptr<T[],D>
|
||||
{
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
#else
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::std::unique_ptr;
|
||||
}
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_SMART_PTR
|
||||
#endif // header
|
||||
45
include/boost/thread/csbl/tuple.hpp
Normal file
45
include/boost/thread/csbl/tuple.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_TUPLE_HPP
|
||||
#define BOOST_CSBL_TUPLE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_TUPLE || defined BOOST_NO_CXX11_HDR_TUPLE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#ifndef BOOST_THREAD_USES_BOOST_TUPLE
|
||||
#define BOOST_THREAD_USES_BOOST_TUPLE
|
||||
#endif
|
||||
|
||||
#else
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_TUPLE
|
||||
using ::boost::tuple;
|
||||
using ::boost::get;
|
||||
#else
|
||||
// 20.4.2, class template tuple:
|
||||
using ::std::tuple;
|
||||
using ::std::get;
|
||||
// 20.4.2.4, tuple creation functions:
|
||||
// 20.4.2.5, tuple helper classes:
|
||||
// 20.4.2.6, element access:
|
||||
// 20.4.2.7, relational operators:
|
||||
// 20.4.2.8, allocator-related traits
|
||||
// 20.4.2.9, specialized algorithms:
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
35
include/boost/thread/csbl/vector.hpp
Normal file
35
include/boost/thread/csbl/vector.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_VECTOR_HPP
|
||||
#define BOOST_CSBL_VECTOR_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR || defined BOOST_NO_CXX11_HDR_VECTOR || defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#ifndef BOOST_THREAD_USES_BOOST_VECTOR
|
||||
#define BOOST_THREAD_USES_BOOST_VECTOR
|
||||
#endif
|
||||
#include <boost/container/vector.hpp>
|
||||
#else
|
||||
#include <vector>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
#if defined BOOST_THREAD_USES_BOOST_VECTOR
|
||||
using ::boost::container::vector;
|
||||
#else
|
||||
using ::std::vector;
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
@@ -9,7 +9,7 @@
|
||||
#ifndef BOOST_THREAD_CV_STATUS_HPP
|
||||
#define BOOST_THREAD_CV_STATUS_HPP
|
||||
|
||||
#include <boost/detail/scoped_enum_emulation.hpp>
|
||||
#include <boost/core/scoped_enum.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -15,8 +15,7 @@
|
||||
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
|
||||
// ATTRIBUTE_MAY_ALIAS
|
||||
|
||||
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 302 \
|
||||
&& !defined(__INTEL_COMPILER)
|
||||
#if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
||||
|
||||
// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with
|
||||
// regard to violation of the strict aliasing rules.
|
||||
@@ -240,7 +239,8 @@
|
||||
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO) && \
|
||||
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
@@ -248,6 +248,22 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// ! defined(BOOST_NO_SFINAE_EXPR) &&
|
||||
// ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) &&
|
||||
// ! defined(BOOST_NO_CXX11_AUTO) &&
|
||||
// ! defined(BOOST_NO_CXX11_DECLTYPE) &&
|
||||
// ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) &&
|
||||
|
||||
|
||||
// MAKE_READY_AT_THREAD_EXIT
|
||||
#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \
|
||||
@@ -264,6 +280,11 @@
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
|
||||
#endif
|
||||
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_UNWRAP
|
||||
#define BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
|
||||
#endif
|
||||
|
||||
// FUTURE_INVALID_AFTER_GET
|
||||
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \
|
||||
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
|
||||
@@ -358,7 +379,9 @@
|
||||
// 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
|
||||
# if !defined(BOOST_THREAD_USE_DLL)
|
||||
# define BOOST_THREAD_USE_DLL
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
|
||||
@@ -75,15 +75,28 @@ namespace boost
|
||||
};
|
||||
struct counter_is_not_zero
|
||||
{
|
||||
counter_is_not_zero(const counter& count) : count_(count) {}
|
||||
counter_is_not_zero(counter const& count) : count_(count) {}
|
||||
bool operator()() const { return count_ != 0; }
|
||||
const counter& count_;
|
||||
counter const& count_;
|
||||
};
|
||||
struct counter_is_zero
|
||||
{
|
||||
counter_is_zero(const counter& count) : count_(count) {}
|
||||
counter_is_zero(counter const& count) : count_(count) {}
|
||||
bool operator()() const { return count_ == 0; }
|
||||
const counter& count_;
|
||||
counter const& count_;
|
||||
};
|
||||
struct is_zero
|
||||
{
|
||||
is_zero(std::size_t& count) : count_(count) {}
|
||||
bool operator()() const { return count_ == 0; }
|
||||
std::size_t& count_;
|
||||
};
|
||||
struct not_equal
|
||||
{
|
||||
not_equal(std::size_t& x, std::size_t& y) : x_(x), y_(y) {}
|
||||
bool operator()() const { return x_ != y_; }
|
||||
std::size_t& x_;
|
||||
std::size_t& y_;
|
||||
};
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
* BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or
|
||||
* makes it private.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
|
||||
CLASS(CLASS const&) = delete; \
|
||||
|
||||
93
include/boost/thread/detail/function_wrapper.hpp
Normal file
93
include/boost/thread/detail/function_wrapper.hpp
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// Make use of Boost.Move
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
|
||||
#define BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/thread/csbl/memory/unique_ptr.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class function_wrapper
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual void call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
typedef boost::csbl::unique_ptr<impl_base> impl_base_type;
|
||||
impl_base_type impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
impl_type(F const &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(function_wrapper)
|
||||
|
||||
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
function_wrapper(F const& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
//#endif
|
||||
template<typename F>
|
||||
function_wrapper(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<F>(boost::forward<F>(f)))
|
||||
{}
|
||||
function_wrapper(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
other.impl = 0;
|
||||
}
|
||||
function_wrapper()
|
||||
: impl(0)
|
||||
{
|
||||
}
|
||||
~function_wrapper()
|
||||
{
|
||||
}
|
||||
|
||||
function_wrapper& operator=(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
other.impl=0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void operator()()
|
||||
{ impl->call();}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -28,7 +28,11 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_member_function_pointer.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
|
||||
#include <functional>
|
||||
@@ -40,11 +44,11 @@ namespace boost
|
||||
{
|
||||
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
#if ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO)
|
||||
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_INVOKE
|
||||
|
||||
@@ -58,6 +62,13 @@ namespace boost
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class R, class Fp, class A0, class ...Args>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Fp, class A0, class ...Args>
|
||||
inline auto
|
||||
@@ -66,6 +77,13 @@ namespace boost
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class R, class Fp, class A0, class ...Args>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// bullets 3 and 4
|
||||
|
||||
@@ -85,14 +103,38 @@ namespace boost
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
template <class R, class Fp, class A0>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype(boost::forward<A0>(a0).*f)
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
|
||||
template <class R, class Fp, class A0>
|
||||
inline auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype((*boost::forward<A0>(a0)).*f)
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
|
||||
// bullet 5
|
||||
|
||||
template <class R, class Fp, class ...Args>
|
||||
inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class Fp, class ...Args>
|
||||
inline auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<Args>(args)...))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
// bullets 1 and 2
|
||||
@@ -105,21 +147,45 @@ namespace boost
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype((boost::forward<A0>(a0).*f)())
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
}
|
||||
template <class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(a1)))
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(a1));
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class R, class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2)))
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2));
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class R, class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype((boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
template <class Fp, class A0>
|
||||
@@ -130,21 +196,45 @@ namespace boost
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)();
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)())
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)();
|
||||
}
|
||||
template <class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1)))
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1));
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Fp, class A0, class A1>
|
||||
template <class R, class Fp, class A0, class A1>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2)))
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<Args>(a1), boost::forward<Args>(a2));
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class R, class Fp, class A0, class A1, class A2>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype(((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return ((*boost::forward<A0>(a0)).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
// bullets 3 and 4
|
||||
@@ -157,6 +247,14 @@ namespace boost
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype(boost::forward<A0>(a0).*f)
|
||||
{
|
||||
return boost::forward<A0>(a0).*f;
|
||||
}
|
||||
|
||||
template <class Fp, class A0>
|
||||
inline
|
||||
@@ -166,6 +264,14 @@ namespace boost
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
template <class R, class Fp, class A0>
|
||||
inline
|
||||
auto
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A0) a0)
|
||||
-> decltype((*boost::forward<A0>(a0)).*f)
|
||||
{
|
||||
return (*boost::forward<A0>(a0)).*f;
|
||||
}
|
||||
|
||||
// bullet 5
|
||||
|
||||
@@ -178,7 +284,7 @@ namespace boost
|
||||
}
|
||||
template <class Fp, class A1>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) a1)
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
@@ -197,12 +303,43 @@ namespace boost
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
|
||||
|
||||
template <class R, class Fp>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
-> decltype(boost::forward<Fp>(f)())
|
||||
{
|
||||
return boost::forward<Fp>(f)();
|
||||
}
|
||||
template <class R, class Fp, class A1>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class R, class Fp, class A1, class A2>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class R, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
auto invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
-> decltype(boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3)))
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
|
||||
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
#elif ! defined(BOOST_NO_SFINAE_EXPR) && \
|
||||
! defined BOOST_NO_CXX11_HDR_FUNCTIONAL && \
|
||||
defined BOOST_MSVC
|
||||
|
||||
//#error
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
Ret invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
@@ -395,22 +532,28 @@ namespace boost
|
||||
// bullet 5
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return f(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class ...Args>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<Args>(args)...);
|
||||
}
|
||||
template <class Ret, class ...Args>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(Args... ), BOOST_THREAD_RV_REF(Args) ...args)
|
||||
{
|
||||
return f(boost::forward<Args>(args)...);
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<Args>(args)...);
|
||||
}
|
||||
#else // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
// bullet 1
|
||||
@@ -424,9 +567,34 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(), BOOST_THREAD_RV_REF(A0) a0)
|
||||
invoke(Ret (A::*f)(), A0& a0)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
return (a0.*f)();
|
||||
}
|
||||
template <class Ret, class A, class A0>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(), A0* a0)
|
||||
{
|
||||
return ((*a0).*f)();
|
||||
}
|
||||
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1),
|
||||
A0& a0, BOOST_THREAD_RV_REF(A1) a1
|
||||
)
|
||||
{
|
||||
return (a0.*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
@@ -435,21 +603,33 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), A0 a0, A1 a1)
|
||||
invoke(Ret (A::*f)(A1), A0& a0, A1 a1)
|
||||
{
|
||||
return (a0.*f)(a1);
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), A0* a0, BOOST_THREAD_RV_REF(A1) a1
|
||||
)
|
||||
{
|
||||
return (*(a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1), A0* a0, A1 a1)
|
||||
{
|
||||
return (*a0.*f)(a1);
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
@@ -458,10 +638,10 @@ namespace boost
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2),
|
||||
BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
return (a0.*f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2>
|
||||
inline
|
||||
@@ -470,9 +650,9 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2), A0 a0, A1 a1, A2 a2)
|
||||
invoke(Ret (A::*f)(A1, A2), A0* a0, A1 a1, A2 a2)
|
||||
{
|
||||
return (a0.*f)(a1, a2);
|
||||
return ((*a0).*f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2, class A3>
|
||||
inline
|
||||
@@ -482,9 +662,9 @@ namespace boost
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2, A3),
|
||||
BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
A0& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
return (a0.*f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1, class A2, class A3>
|
||||
inline
|
||||
@@ -493,9 +673,9 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2, A3), A0 a0, A1 a1, A2 a2, A3 a3)
|
||||
invoke(Ret (A::*f)(A1, A2, A3), A0* a0, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return (a0.*f)(a1, a2, a3);
|
||||
return ((*a0).*f)(a1, a2, a3);
|
||||
}
|
||||
|
||||
///
|
||||
@@ -506,9 +686,20 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)() const, BOOST_THREAD_RV_REF(A0) a0)
|
||||
invoke(Ret (A::*f)() const, A0 const& a0)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)();
|
||||
return (a0.*f)();
|
||||
}
|
||||
template <class Ret, class A, class A0>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)() const, A0 const* a0)
|
||||
{
|
||||
return ((*a0).*f)();
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
@@ -517,9 +708,9 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1) const, BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
invoke(Ret (A::*f)(A1) const, A0 const& a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1));
|
||||
return (a0.*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
@@ -528,7 +719,19 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1) const, A0 a0, A1 a1)
|
||||
invoke(Ret (A::*f)(A1) const, A0 const* a0, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return ((*a0).*f)(boost::forward<A1>(a1));
|
||||
}
|
||||
|
||||
template <class Ret, class A, class A0, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1) const, A0 const& a0, A1 a1)
|
||||
{
|
||||
return (a0.*f)(a1);
|
||||
}
|
||||
@@ -540,7 +743,7 @@ namespace boost
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2) const,
|
||||
BOOST_THREAD_RV_REF(A0) a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
A0 const& a0, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2
|
||||
)
|
||||
{
|
||||
return (boost::forward<A0>(a0).*f)(boost::forward<A1>(a1), boost::forward<A2>(a2)
|
||||
@@ -553,7 +756,7 @@ namespace boost
|
||||
is_base_of<A, typename remove_reference<A0>::type>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Ret (A::*f)(A1, A2) const, A0 a0, A1 a1, A2 a2)
|
||||
invoke(Ret (A::*f)(A1, A2) const, A0 const& a0, A1 a1, A2 a2)
|
||||
{
|
||||
return (a0.*f)(a1, a2);
|
||||
}
|
||||
@@ -1159,189 +1362,241 @@ namespace boost
|
||||
// f(t1, t2, ..., tN) in all other cases.
|
||||
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f)
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return boost::forward<Fp>(f)();
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
template <class Ret, class Fp>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f));
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_RV_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2, a3);
|
||||
}
|
||||
|
||||
///
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, A1 a1)
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1));
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
|
||||
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return f(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return f(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1, a2);
|
||||
}
|
||||
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::false_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::forward<Fp>(f)(a1, a2, a3);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline Ret do_invoke(mpl::true_, BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return f(a1, a2, a3);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(BOOST_THREAD_FWD_REF(Fp) f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return boost::detail::do_invoke<Ret>(boost::is_pointer<Fp>(), boost::forward<Fp>(f), a1, a2, a3);
|
||||
}
|
||||
|
||||
|
||||
///
|
||||
template <class Ret, class Fp>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp &f)
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class Fp, class A1>
|
||||
inline
|
||||
typename disable_if_c
|
||||
<
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp &f, A1 a1)
|
||||
{
|
||||
return f(a1);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, A1 a1, A2 a2)
|
||||
invoke(Fp &f, A1 a1, A2 a2)
|
||||
{
|
||||
return f(a1, a2);
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
invoke(Fp &f, BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
template <class Ret, class Fp, class A1, class A2, class A3>
|
||||
inline
|
||||
typename enable_if_c
|
||||
typename disable_if_c
|
||||
<
|
||||
! is_member_function_pointer<Fp>::value,
|
||||
is_member_function_pointer<Fp>::value,
|
||||
Ret
|
||||
>::type
|
||||
invoke(Fp const &f, A1 a1, A2 a2, A3 a3)
|
||||
invoke(Fp &f, A1 a1, A2 a2, A3 a3)
|
||||
{
|
||||
return f(a1, a2, a3);
|
||||
}
|
||||
///
|
||||
|
||||
template <class Ret>
|
||||
inline Ret
|
||||
invoke(Ret(*f)())
|
||||
{
|
||||
return f();
|
||||
}
|
||||
template <class Ret, class A1>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(A1), BOOST_THREAD_RV_REF(A1) a1)
|
||||
{
|
||||
return f(boost::forward<A1>(a1));
|
||||
}
|
||||
template <class Ret, class A1, class A2>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(A1, A2),
|
||||
BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2));
|
||||
}
|
||||
template <class Ret, class A1, class A2, class A3>
|
||||
inline Ret
|
||||
invoke(Ret(*f)(A1, A2, A3),
|
||||
BOOST_THREAD_RV_REF(A1) a1, BOOST_THREAD_RV_REF(A2) a2, BOOST_THREAD_RV_REF(A3) a3)
|
||||
{
|
||||
return f(boost::forward<A1>(a1), boost::forward<A2>(a2), boost::forward<A3>(a3));
|
||||
}
|
||||
#endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
#endif // all
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
// The async_func code is based on the one from libcxx.
|
||||
// The invoker code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
@@ -29,39 +29,40 @@
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#include <tuple>
|
||||
#else
|
||||
#include <boost/thread/csbl/tuple.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/variadic_header.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
template <class Fp, class ... Args>
|
||||
class async_func
|
||||
class invoker
|
||||
{
|
||||
std::tuple<Fp, Args...> f_;
|
||||
//typedef typename decay<Fp>::type Fpd;
|
||||
//typedef tuple<typename decay<Args>::type...> Argsd;
|
||||
|
||||
//csbl::tuple<Fpd, Argsd...> f_;
|
||||
csbl::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY( invoker)
|
||||
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
|
||||
typedef typename result_of<Fp(Args...)>::type result_type;
|
||||
|
||||
template <class F, class ... As>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args)... args)
|
||||
: f_(boost::move(f), boost::move(args)...)
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args)
|
||||
: f_(boost::forward<F>(f), boost::forward<As>(args)...)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f) : f_(boost::move(f.f_))
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f) : f_(boost::move(BOOST_THREAD_RV(f).f_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -74,24 +75,165 @@ namespace boost
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke(boost::move(std::get<0>(f_)), boost::move(std::get<Indices>(f_))...);
|
||||
return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) async_func<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
|
||||
template <class R, class Fp, class ... Args>
|
||||
class invoker_ret
|
||||
{
|
||||
//typedef typename decay<Fp>::type Fpd;
|
||||
//typedef tuple<typename decay<Args>::type...> Argsd;
|
||||
|
||||
//csbl::tuple<Fpd, Argsd...> f_;
|
||||
csbl::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( invoker_ret)
|
||||
typedef R result_type;
|
||||
|
||||
template <class F, class ... As>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker_ret(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(As)... args)
|
||||
: f_(boost::forward<F>(f), boost::forward<As>(args)...)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker_ret(BOOST_THREAD_RV_REF(invoker_ret) f) : f_(boost::move(BOOST_THREAD_RV(f).f_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index;
|
||||
return execute(Index());
|
||||
}
|
||||
private:
|
||||
template <size_t ...Indices>
|
||||
result_type
|
||||
execute(tuple_indices<Indices...>)
|
||||
{
|
||||
return invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
#else
|
||||
|
||||
#if ! defined BOOST_MSVC
|
||||
|
||||
#define BOOST_THREAD_RV_REF_ARG_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(Arg##n)
|
||||
#define BOOST_THREAD_RV_REF_A_T(z, n, unused) BOOST_PP_COMMA_IF(n) BOOST_THREAD_RV_REF(A##n)
|
||||
#define BOOST_THREAD_RV_REF_ARG(z, n, unused) , BOOST_THREAD_RV_REF(Arg##n) arg##n
|
||||
#define BOOST_THREAD_FWD_REF_A(z, n, unused) , BOOST_THREAD_FWD_REF(A##n) arg##n
|
||||
#define BOOST_THREAD_FWD_REF_ARG(z, n, unused) , BOOST_THREAD_FWD_REF(Arg##n) arg##n
|
||||
#define BOOST_THREAD_FWD_PARAM(z, n, unused) , boost::forward<Arg##n>(arg##n)
|
||||
#define BOOST_THREAD_FWD_PARAM_A(z, n, unused) , boost::forward<A##n>(arg##n)
|
||||
#define BOOST_THREAD_DCL(z, n, unused) Arg##n v##n;
|
||||
#define BOOST_THREAD_MOVE_PARAM(z, n, unused) , v##n(boost::move(arg##n))
|
||||
#define BOOST_THREAD_FORWARD_PARAM_A(z, n, unused) , v##n(boost::forward<A##n>(arg##n))
|
||||
#define BOOST_THREAD_MOVE_RHS_PARAM(z, n, unused) , v##n(boost::move(x.v##n))
|
||||
#define BOOST_THREAD_MOVE_DCL(z, n, unused) , boost::move(v##n)
|
||||
#define BOOST_THREAD_MOVE_DCL_T(z, n, unused) BOOST_PP_COMMA_IF(n) boost::move(v##n)
|
||||
#define BOOST_THREAD_ARG_DEF(z, n, unused) , class Arg##n = tuples::null_type
|
||||
|
||||
template <class Fp, class Arg = tuples::null_type
|
||||
BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ARG_DEF, ~)
|
||||
>
|
||||
class invoker;
|
||||
|
||||
#define BOOST_THREAD_ASYNC_FUNCT(z, n, unused) \
|
||||
template <class Fp BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg) > \
|
||||
class invoker<Fp BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Arg)> \
|
||||
{ \
|
||||
Fp fp_; \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
|
||||
public: \
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker) \
|
||||
typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \
|
||||
\
|
||||
template <class F BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(F) f \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \
|
||||
) \
|
||||
: fp_(boost::forward<F>(f)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \
|
||||
{} \
|
||||
\
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
|
||||
: fp_(boost::move(x.fp_)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
|
||||
{} \
|
||||
\
|
||||
result_type operator()() { \
|
||||
return invoke(boost::move(fp_) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \
|
||||
); \
|
||||
} \
|
||||
}; \
|
||||
\
|
||||
template <class R BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class Arg) > \
|
||||
class invoker<R(*)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)) BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, Arg)> \
|
||||
{ \
|
||||
typedef R(*Fp)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_ARG_T, ~)); \
|
||||
Fp fp_; \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
|
||||
public: \
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker) \
|
||||
typedef typename result_of<Fp(BOOST_PP_ENUM_PARAMS(n, Arg))>::type result_type; \
|
||||
\
|
||||
template <class R2 BOOST_PP_COMMA_IF(n) BOOST_PP_ENUM_PARAMS(n, class A) > \
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
explicit invoker(R2(*f)(BOOST_PP_REPEAT(n, BOOST_THREAD_RV_REF_A_T, ~)) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FWD_REF_A, ~) \
|
||||
) \
|
||||
: fp_(f) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_FORWARD_PARAM_A, ~) \
|
||||
{} \
|
||||
\
|
||||
BOOST_SYMBOL_VISIBLE \
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
|
||||
: fp_(x.fp_) \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
|
||||
{} \
|
||||
\
|
||||
result_type operator()() { \
|
||||
return fp_( \
|
||||
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL_T, ~) \
|
||||
); \
|
||||
} \
|
||||
};
|
||||
|
||||
BOOST_PP_REPEAT(BOOST_THREAD_MAX_ARGS, BOOST_THREAD_ASYNC_FUNCT, ~)
|
||||
|
||||
#undef BOOST_THREAD_RV_REF_ARG_T
|
||||
#undef BOOST_THREAD_RV_REF_ARG
|
||||
#undef BOOST_THREAD_FWD_REF_ARG
|
||||
#undef BOOST_THREAD_FWD_REF_A
|
||||
#undef BOOST_THREAD_FWD_PARAM
|
||||
#undef BOOST_THREAD_FWD_PARAM_A
|
||||
#undef BOOST_THREAD_DCL
|
||||
#undef BOOST_THREAD_MOVE_PARAM
|
||||
#undef BOOST_THREAD_MOVE_RHS_PARAM
|
||||
#undef BOOST_THREAD_MOVE_DCL
|
||||
#undef BOOST_THREAD_ARG_DEF
|
||||
#undef BOOST_THREAD_ASYNC_FUNCT
|
||||
|
||||
#else
|
||||
|
||||
template <class Fp,
|
||||
class T0 = tuples::null_type, class T1 = tuples::null_type, class T2 = tuples::null_type,
|
||||
class T3 = tuples::null_type, class T4 = tuples::null_type, class T5 = tuples::null_type,
|
||||
class T6 = tuples::null_type, class T7 = tuples::null_type, class T8 = tuples::null_type
|
||||
, class T9 = tuples::null_type
|
||||
>
|
||||
class async_func;
|
||||
class invoker;
|
||||
|
||||
template <class Fp,
|
||||
class T0 , class T1 , class T2 ,
|
||||
class T3 , class T4 , class T5 ,
|
||||
class T6 , class T7 , class T8 >
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -106,11 +248,11 @@ namespace boost
|
||||
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -134,17 +276,17 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
, v7_(boost::move(f.a7))
|
||||
, v8_(boost::move(f.a8))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
, v6_(boost::move(BOOST_THREAD_RV(f).v6_))
|
||||
, v7_(boost::move(BOOST_THREAD_RV(f).v7_))
|
||||
, v8_(boost::move(BOOST_THREAD_RV(f).v8_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -163,7 +305,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -175,11 +317,11 @@ namespace boost
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -201,16 +343,16 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
, v7_(boost::move(f.a7))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
, v6_(boost::move(BOOST_THREAD_RV(f).v6_))
|
||||
, v7_(boost::move(BOOST_THREAD_RV(f).v7_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -228,7 +370,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -239,11 +381,11 @@ namespace boost
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -263,15 +405,15 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
, v6_(boost::move(f.a6))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
, v6_(boost::move(BOOST_THREAD_RV(f).v6_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -288,7 +430,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4, T5>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -298,11 +440,11 @@ namespace boost
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -320,14 +462,14 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
, v5_(boost::move(f.a5))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
, v5_(boost::move(BOOST_THREAD_RV(f).v5_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -343,7 +485,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -352,11 +494,11 @@ namespace boost
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -372,13 +514,13 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
, v4_(boost::move(f.a4))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
, v4_(boost::move(BOOST_THREAD_RV(f).v4_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -393,7 +535,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3>
|
||||
class async_func<Fp, T0, T1, T2, T3>
|
||||
class invoker<Fp, T0, T1, T2, T3>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
@@ -401,11 +543,11 @@ namespace boost
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -419,12 +561,12 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
, v3_(boost::move(f.a3))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
, v3_(boost::move(BOOST_THREAD_RV(f).v3_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -438,18 +580,18 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2>
|
||||
class async_func<Fp, T0, T1, T2>
|
||||
class invoker<Fp, T0, T1, T2>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
@@ -461,11 +603,11 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
, v2_(boost::move(f.a2))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
, v2_(boost::move(BOOST_THREAD_RV(f).v2_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -478,17 +620,17 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1>
|
||||
class async_func<Fp, T0, T1>
|
||||
class invoker<Fp, T0, T1>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0, T1)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
)
|
||||
@@ -498,10 +640,10 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
, v1_(boost::move(f.a1))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
, v1_(boost::move(BOOST_THREAD_RV(f).v1_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -513,16 +655,16 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0>
|
||||
class async_func<Fp, T0>
|
||||
class invoker<Fp, T0>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
BOOST_THREAD_MOVABLE_ONLY(invoker)
|
||||
typedef typename result_of<Fp(T0)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
@@ -530,9 +672,9 @@ namespace boost
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
@@ -543,19 +685,19 @@ namespace boost
|
||||
}
|
||||
};
|
||||
template <class Fp>
|
||||
class async_func<Fp>
|
||||
class invoker<Fp>
|
||||
{
|
||||
Fp fp_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func)
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
: fp_(boost::move(f))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_FWD_REF(async_func) f)
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(boost::move(f.fp_))
|
||||
{}
|
||||
result_type operator()()
|
||||
@@ -563,9 +705,34 @@ namespace boost
|
||||
return fp_();
|
||||
}
|
||||
};
|
||||
template <class R>
|
||||
class invoker<R(*)()>
|
||||
{
|
||||
typedef R(*Fp)();
|
||||
Fp fp_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker(Fp f)
|
||||
: fp_(f)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_FWD_REF(invoker) f)
|
||||
: fp_(f.fp_)
|
||||
{}
|
||||
result_type operator()()
|
||||
{
|
||||
return fp_();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/thread/detail/variadic_footer.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -1,8 +1,9 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (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)
|
||||
// Copyright (C) 2011-2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (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)
|
||||
// Copyright (C) 2011-2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
@@ -12,14 +13,11 @@
|
||||
#define BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/container/allocator_traits.hpp>
|
||||
#include <boost/container/scoped_allocator.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/is_scalar.hpp>
|
||||
#include <boost/type_traits/is_pointer.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
#include <boost/thread/csbl/memory/pointer_traits.hpp>
|
||||
#include <boost/thread/csbl/memory/allocator_arg.hpp>
|
||||
#include <boost/thread/csbl/memory/allocator_traits.hpp>
|
||||
#include <boost/thread/csbl/memory/scoped_allocator.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -28,7 +26,7 @@ namespace boost
|
||||
template <class _Alloc>
|
||||
class allocator_destructor
|
||||
{
|
||||
typedef container::allocator_traits<_Alloc> alloc_traits;
|
||||
typedef csbl::allocator_traits<_Alloc> alloc_traits;
|
||||
public:
|
||||
typedef typename alloc_traits::pointer pointer;
|
||||
typedef typename alloc_traits::size_type size_type;
|
||||
@@ -46,111 +44,5 @@ namespace boost
|
||||
}
|
||||
};
|
||||
} //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>
|
||||
{
|
||||
};
|
||||
|
||||
template <class Ptr>
|
||||
struct pointer_traits
|
||||
{
|
||||
typedef Ptr pointer;
|
||||
// typedef <details> element_type;
|
||||
// typedef <details> difference_type;
|
||||
|
||||
// template <class U> using rebind = <details>;
|
||||
//
|
||||
// static pointer pointer_to(<details>);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct pointer_traits<T*>
|
||||
{
|
||||
typedef T* pointer;
|
||||
typedef T element_type;
|
||||
typedef ptrdiff_t difference_type;
|
||||
|
||||
// template <class U> using rebind = U*;
|
||||
//
|
||||
// static pointer pointer_to(<details>) noexcept;
|
||||
};
|
||||
|
||||
|
||||
namespace thread_detail {
|
||||
template <class _Ptr1, class _Ptr2,
|
||||
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
|
||||
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
|
||||
>::value
|
||||
>
|
||||
struct same_or_less_cv_qualified_imp
|
||||
: is_convertible<_Ptr1, _Ptr2> {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
|
||||
: false_type {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
|
||||
!is_pointer<_Ptr1>::value>
|
||||
struct same_or_less_cv_qualified
|
||||
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2> {};
|
||||
|
||||
template <class _Ptr1, class _Ptr2>
|
||||
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
|
||||
: false_type {};
|
||||
|
||||
}
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U>&,
|
||||
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (T* ptr) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete ptr;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
|
||||
{
|
||||
public:
|
||||
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() = default;
|
||||
#else
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
|
||||
#endif
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
default_delete(const default_delete<U[]>&,
|
||||
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
|
||||
template <class U>
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
void operator() (U* ptr,
|
||||
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
|
||||
delete [] ptr;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
|
||||
}
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
|
||||
@@ -9,18 +9,27 @@
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/core/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>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/remove_extent.hpp>
|
||||
#include <boost/type_traits/is_array.hpp>
|
||||
#include <boost/type_traits/is_function.hpp>
|
||||
#include <boost/type_traits/remove_cv.hpp>
|
||||
#include <boost/type_traits/add_pointer.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/move/utility.hpp>
|
||||
#include <boost/move/traits.hpp>
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#include <type_traits>
|
||||
#endif
|
||||
namespace boost
|
||||
{
|
||||
|
||||
@@ -237,8 +246,51 @@ namespace detail
|
||||
|
||||
|
||||
namespace boost
|
||||
{ namespace thread_detail
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class Tp>
|
||||
struct remove_reference : boost::remove_reference<Tp> {};
|
||||
template <class Tp>
|
||||
struct decay : boost::decay<Tp> {};
|
||||
#else
|
||||
template <class Tp>
|
||||
struct remove_reference
|
||||
{
|
||||
typedef Tp type;
|
||||
};
|
||||
template <class Tp>
|
||||
struct remove_reference<Tp&>
|
||||
{
|
||||
typedef Tp type;
|
||||
};
|
||||
template <class Tp>
|
||||
struct remove_reference< rv<Tp> > {
|
||||
typedef Tp type;
|
||||
};
|
||||
|
||||
template <class Tp>
|
||||
struct decay
|
||||
{
|
||||
private:
|
||||
typedef typename boost::move_detail::remove_rvalue_reference<Tp>::type Up0;
|
||||
typedef typename boost::remove_reference<Up0>::type Up;
|
||||
public:
|
||||
typedef typename conditional
|
||||
<
|
||||
is_array<Up>::value,
|
||||
typename remove_extent<Up>::type*,
|
||||
typename conditional
|
||||
<
|
||||
is_function<Up>::value,
|
||||
typename add_pointer<Up>::type,
|
||||
typename remove_cv<Up>::type
|
||||
>::type
|
||||
>::type type;
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template <class T>
|
||||
typename decay<T>::type
|
||||
|
||||
213
include/boost/thread/detail/nullary_function.hpp
Normal file
213
include/boost/thread/detail/nullary_function.hpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// Make use of Boost.Move
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP
|
||||
#define BOOST_THREAD_DETAIL_NULLARY_FUNCTION_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/thread/detail/memory.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/type_traits/decay.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename F>
|
||||
class nullary_function;
|
||||
template <>
|
||||
class nullary_function<void()>
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual void call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
shared_ptr<impl_base> impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
impl_type(F &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
#endif
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
struct impl_type_ptr: impl_base
|
||||
{
|
||||
void (*f)();
|
||||
impl_type_ptr(void (*f_)())
|
||||
: f(f_)
|
||||
{}
|
||||
void call()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE(nullary_function)
|
||||
|
||||
explicit nullary_function(void (*f)()):
|
||||
impl(new impl_type_ptr(f))
|
||||
{}
|
||||
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
explicit nullary_function(F& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
#endif
|
||||
template<typename F>
|
||||
nullary_function(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{}
|
||||
|
||||
nullary_function()
|
||||
: impl()
|
||||
{
|
||||
}
|
||||
nullary_function(nullary_function const& other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
}
|
||||
nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT :
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{ impl->call();}
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
class nullary_function<R()>
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual R call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
shared_ptr<impl_base> impl;
|
||||
template <typename F>
|
||||
struct impl_type: impl_base
|
||||
{
|
||||
F f;
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
impl_type(F &f_)
|
||||
: f(f_)
|
||||
{}
|
||||
#endif
|
||||
impl_type(BOOST_THREAD_RV_REF(F) f_)
|
||||
: f(boost::move(f_))
|
||||
{}
|
||||
|
||||
R call()
|
||||
{
|
||||
return f();
|
||||
}
|
||||
};
|
||||
struct impl_type_ptr: impl_base
|
||||
{
|
||||
R (*f)();
|
||||
impl_type_ptr(R (*f_)())
|
||||
: f(f_)
|
||||
{}
|
||||
|
||||
R call()
|
||||
{
|
||||
return f();
|
||||
}
|
||||
};
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE(nullary_function)
|
||||
|
||||
nullary_function(R (*f)()):
|
||||
impl(new impl_type_ptr(f))
|
||||
{}
|
||||
#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
template<typename F>
|
||||
nullary_function(F& f):
|
||||
impl(new impl_type<F>(f))
|
||||
{}
|
||||
#endif
|
||||
template<typename F>
|
||||
nullary_function(BOOST_THREAD_RV_REF(F) f):
|
||||
impl(new impl_type<typename decay<F>::type>(thread_detail::decay_copy(boost::forward<F>(f))))
|
||||
{}
|
||||
|
||||
nullary_function(nullary_function const& other) BOOST_NOEXCEPT :
|
||||
impl(other.impl)
|
||||
{
|
||||
}
|
||||
nullary_function(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT :
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
nullary_function()
|
||||
: impl()
|
||||
{
|
||||
}
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
return *this;
|
||||
}
|
||||
|
||||
R operator()()
|
||||
{ return impl->call();}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -4,7 +4,7 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-2010 Anthony Williams
|
||||
// (C) Copyright 20011-2012 Vicente J. Botet Escriba
|
||||
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
#include <boost/assert.hpp>
|
||||
#include <list>
|
||||
#include <algorithm>
|
||||
#include <boost/ref.hpp>
|
||||
#include <boost/core/ref.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <stdlib.h>
|
||||
#include <memory>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/core/enable_if.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
@@ -64,11 +64,9 @@ namespace boost
|
||||
{
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE(thread_data)
|
||||
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_):
|
||||
fp(boost::forward<F>(f_), boost::forward<ArgTypes>(args_)...)
|
||||
{}
|
||||
#endif
|
||||
template <std::size_t ...Indices>
|
||||
void run2(tuple_indices<Indices...>)
|
||||
{
|
||||
@@ -174,7 +172,7 @@ namespace boost
|
||||
private:
|
||||
bool start_thread_noexcept();
|
||||
bool start_thread_noexcept(const attributes& attr);
|
||||
public:
|
||||
//public:
|
||||
void start_thread()
|
||||
{
|
||||
if (!start_thread_noexcept())
|
||||
@@ -334,7 +332,7 @@ namespace boost
|
||||
start_thread(attrs);
|
||||
}
|
||||
#endif
|
||||
thread(BOOST_THREAD_RV_REF(thread) x)
|
||||
thread(BOOST_THREAD_RV_REF(thread) x) BOOST_NOEXCEPT
|
||||
{
|
||||
thread_info=BOOST_THREAD_RV(x).thread_info;
|
||||
BOOST_THREAD_RV(x).thread_info.reset();
|
||||
@@ -466,11 +464,20 @@ namespace boost
|
||||
inline void join();
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
chrono::milliseconds rel_time2= chrono::ceil<chrono::milliseconds>(rel_time);
|
||||
return do_try_join_until(rel_time2.count());
|
||||
}
|
||||
#else
|
||||
template <class Rep, class Period>
|
||||
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
return try_join_until(chrono::steady_clock::now() + rel_time);
|
||||
}
|
||||
#endif
|
||||
template <class Clock, class Duration>
|
||||
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
|
||||
{
|
||||
@@ -546,6 +553,7 @@ namespace boost
|
||||
void detach();
|
||||
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
|
||||
static unsigned physical_concurrency() BOOST_NOEXCEPT;
|
||||
|
||||
#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
|
||||
typedef detail::thread_data_base::native_handle_type native_handle_type;
|
||||
@@ -749,10 +757,10 @@ namespace boost
|
||||
#endif
|
||||
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"));
|
||||
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
|
||||
|
||||
BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(),
|
||||
thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")
|
||||
thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -763,7 +771,7 @@ namespace boost
|
||||
#endif
|
||||
{
|
||||
if (this_thread::get_id() == get_id())
|
||||
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
|
||||
boost::throw_exception(thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost thread: trying joining itself"));
|
||||
bool res;
|
||||
if (do_try_join_until_noexcept(timeout, res))
|
||||
{
|
||||
@@ -772,7 +780,7 @@ namespace boost
|
||||
else
|
||||
{
|
||||
BOOST_THREAD_THROW_ELSE_RETURN(
|
||||
(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")),
|
||||
(thread_resource_error(static_cast<int>(system::errc::invalid_argument), "boost thread: thread not joinable")),
|
||||
false
|
||||
);
|
||||
}
|
||||
@@ -826,6 +834,19 @@ namespace boost
|
||||
};
|
||||
|
||||
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
|
||||
struct shared_state_base;
|
||||
#if defined(BOOST_THREAD_PLATFORM_WIN32)
|
||||
inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
||||
{
|
||||
detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
|
||||
if(current_thread_data)
|
||||
{
|
||||
current_thread_data->make_ready_at_thread_exit(as);
|
||||
}
|
||||
}
|
||||
#else
|
||||
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace this_thread
|
||||
|
||||
@@ -85,7 +85,7 @@ namespace boost
|
||||
if(thrd)
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) ,
|
||||
thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying to add a duplicated thread")
|
||||
thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying to add a duplicated thread")
|
||||
);
|
||||
|
||||
boost::lock_guard<shared_mutex> guard(m);
|
||||
@@ -106,7 +106,7 @@ namespace boost
|
||||
void join_all()
|
||||
{
|
||||
BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() ,
|
||||
thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying joining itself")
|
||||
thread_resource_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost::thread_group: trying joining itself")
|
||||
);
|
||||
boost::shared_lock<shared_mutex> guard(m);
|
||||
|
||||
|
||||
10
include/boost/thread/detail/variadic_footer.hpp
Normal file
10
include/boost/thread/detail/variadic_footer.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
|
||||
#endif
|
||||
19
include/boost/thread/detail/variadic_header.hpp
Normal file
19
include/boost/thread/detail/variadic_header.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
//#if defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
|
||||
#include <boost/preprocessor/facilities/intercept.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
|
||||
#ifndef BOOST_THREAD_MAX_ARGS
|
||||
#define BOOST_THREAD_MAX_ARGS 9
|
||||
#endif
|
||||
|
||||
//#endif
|
||||
|
||||
23
include/boost/thread/detail/work.hpp
Normal file
23
include/boost/thread/detail/work.hpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_WORK_HPP
|
||||
#define BOOST_THREAD_DETAIL_WORK_HPP
|
||||
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
typedef detail::nullary_function<void()> work;
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP
|
||||
44
include/boost/thread/exceptional_ptr.hpp
Normal file
44
include/boost/thread/exceptional_ptr.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
// Distributed under the 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 2014 Vicente J. Botet Escriba
|
||||
|
||||
#ifndef BOOST_THREAD_EXCEPTIONAL_PTR_HPP
|
||||
#define BOOST_THREAD_EXCEPTIONAL_PTR_HPP
|
||||
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/exception_ptr.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
struct exceptional_ptr {
|
||||
exception_ptr ptr_;
|
||||
|
||||
exceptional_ptr() : ptr_() {}
|
||||
explicit exceptional_ptr(exception_ptr ex) : ptr_(ex) {}
|
||||
template <class E>
|
||||
explicit exceptional_ptr(BOOST_FWD_REF(E) ex) : ptr_(boost::copy_exception(boost::forward<E>(ex))) {}
|
||||
};
|
||||
|
||||
template <class E>
|
||||
inline exceptional_ptr make_exceptional(BOOST_FWD_REF(E) ex) {
|
||||
return exceptional_ptr(boost::forward<E>(ex));
|
||||
}
|
||||
|
||||
inline exceptional_ptr make_exceptional(exception_ptr ex)
|
||||
{
|
||||
return exceptional_ptr(ex);
|
||||
}
|
||||
|
||||
inline exceptional_ptr make_exceptional()
|
||||
{
|
||||
return exceptional_ptr();
|
||||
}
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -124,7 +124,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
thread_resource_error()
|
||||
: base_type(system::errc::resource_unavailable_try_again, "boost::thread_resource_error")
|
||||
: base_type(static_cast<int>(system::errc::resource_unavailable_try_again), "boost::thread_resource_error")
|
||||
{}
|
||||
|
||||
thread_resource_error( int ev )
|
||||
@@ -152,7 +152,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
unsupported_thread_option()
|
||||
: base_type(system::errc::invalid_argument, "boost::unsupported_thread_option")
|
||||
: base_type(static_cast<int>(system::errc::invalid_argument), "boost::unsupported_thread_option")
|
||||
{}
|
||||
|
||||
unsupported_thread_option( int ev )
|
||||
@@ -176,7 +176,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
invalid_thread_argument()
|
||||
: base_type(system::errc::invalid_argument, "boost::invalid_thread_argument")
|
||||
: base_type(static_cast<int>(system::errc::invalid_argument), "boost::invalid_thread_argument")
|
||||
{}
|
||||
|
||||
invalid_thread_argument( int ev )
|
||||
@@ -200,7 +200,7 @@ namespace boost
|
||||
typedef thread_exception base_type;
|
||||
public:
|
||||
thread_permission_error()
|
||||
: base_type(system::errc::permission_denied, "boost::thread_permission_error")
|
||||
: base_type(static_cast<int>(system::errc::permission_denied), "boost::thread_permission_error")
|
||||
{}
|
||||
|
||||
thread_permission_error( int ev )
|
||||
|
||||
15
include/boost/thread/executor.hpp
Normal file
15
include/boost/thread/executor.hpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/executors/executor_adaptor.hpp>
|
||||
|
||||
#endif
|
||||
326
include/boost/thread/executors/basic_thread_pool.hpp
Normal file
326
include/boost/thread/executors/basic_thread_pool.hpp
Normal file
@@ -0,0 +1,326 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
// first implementation of a simple pool thread using a vector of threads and a sync_queue.
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_BASIC_THREAD_POOL_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class basic_thread_pool
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the kind of stored threads are scoped threads to ensure that the threads are joined.
|
||||
/// A move aware vector type
|
||||
typedef scoped_thread<> thread_t;
|
||||
typedef csbl::vector<thread_t> thread_vector;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
/// A move aware vector
|
||||
thread_vector threads;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
private:
|
||||
|
||||
/**
|
||||
* The main loop of the worker threads
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread1(AtThreadEntry& at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
static void do_nothing_at_thread_entry(basic_thread_pool&) {}
|
||||
|
||||
public:
|
||||
/// basic_thread_pool is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(basic_thread_pool)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures on \c thread_count threads.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
#if 1
|
||||
thread th (&basic_thread_pool::worker_thread, this);
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
#else
|
||||
threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures on \c thread_count threads
|
||||
* and executes the at_thread_entry function at the entry of each created thread. .
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, AtThreadEntry& at_thread_entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread th (&basic_thread_pool::worker_thread1<AtThreadEntry>, this, at_thread_entry);
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
basic_thread_pool( unsigned const thread_count, void(*at_thread_entry)(basic_thread_pool&))
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread th (&basic_thread_pool::worker_thread2, this, at_thread_entry);
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <class AtThreadEntry>
|
||||
basic_thread_pool( unsigned const thread_count, BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||
{
|
||||
try
|
||||
{
|
||||
threads.reserve(thread_count);
|
||||
for (unsigned i = 0; i < thread_count; ++i)
|
||||
{
|
||||
thread th (&basic_thread_pool::worker_thread3<AtThreadEntry>, this, boost::forward<AtThreadEntry>(at_thread_entry));
|
||||
threads.push_back(thread_t(boost::move(th)));
|
||||
//threads.push_back(thread_t(&basic_thread_pool::worker_thread, this)); // do not compile
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c basic_thread_pool destructor.
|
||||
*/
|
||||
~basic_thread_pool()
|
||||
{
|
||||
// signal to all the worker threads that there will be no more submissions.
|
||||
close();
|
||||
// joins all the threads as the threads were scoped_threads
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c basic_thread_pool for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c basic_thread_pool will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
//work w ((closure));
|
||||
//work_queue.push_back(boost::move(w));
|
||||
work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
//work w ((closure));
|
||||
//work_queue.push_back(boost::move(w));
|
||||
work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
#else
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
#endif
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::basic_thread_pool;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
129
include/boost/thread/executors/executor.hpp
Normal file
129
include/boost/thread/executors/executor.hpp
Normal file
@@ -0,0 +1,129 @@
|
||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor)
|
||||
executor() {}
|
||||
|
||||
/**
|
||||
* \b Effects: Destroys the executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
virtual ~executor() {};
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
virtual bool closed() = 0;
|
||||
|
||||
/**
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
virtual void submit(BOOST_THREAD_RV_REF(work) closure) = 0;
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the thread pool will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w = boost::move(closure);
|
||||
submit(boost::move(w));
|
||||
}
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
virtual bool try_executing_one() = 0;
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
//schedule_one_or_yield();
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
using executors::executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
148
include/boost/thread/executors/executor_adaptor.hpp
Normal file
148
include/boost/thread/executors/executor_adaptor.hpp
Normal file
@@ -0,0 +1,148 @@
|
||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/09 Vicente J. Botet Escriba
|
||||
// Adapt to boost from CCIA C++11 implementation
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_EXECUTOR_ADAPTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
/**
|
||||
* Polymorphic adaptor of a model of Executor to an executor.
|
||||
*/
|
||||
template <typename Executor>
|
||||
class executor_adaptor : public executor
|
||||
{
|
||||
Executor ex;
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executor::work work;
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor_adaptor)
|
||||
|
||||
/**
|
||||
* executor_adaptor constructor
|
||||
*/
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <typename ...Args>
|
||||
executor_adaptor(BOOST_THREAD_RV_REF(Args) ... args) : ex(boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
/**
|
||||
* executor_adaptor constructor
|
||||
*/
|
||||
executor_adaptor() : ex() {}
|
||||
|
||||
template <typename A1>
|
||||
executor_adaptor(
|
||||
BOOST_THREAD_FWD_REF(A1) a1
|
||||
) :
|
||||
ex(
|
||||
boost::forward<A1>(a1)
|
||||
) {}
|
||||
template <typename A1, typename A2>
|
||||
executor_adaptor(
|
||||
BOOST_THREAD_FWD_REF(A1) a1,
|
||||
BOOST_THREAD_FWD_REF(A2) a2
|
||||
) :
|
||||
ex(
|
||||
boost::forward<A1>(a1),
|
||||
boost::forward<A2>(a2)
|
||||
) {}
|
||||
template <typename A1, typename A2, typename A3>
|
||||
executor_adaptor(
|
||||
BOOST_THREAD_FWD_REF(A1) a1,
|
||||
BOOST_THREAD_FWD_REF(A2) a2,
|
||||
BOOST_THREAD_FWD_REF(A3) a3
|
||||
) :
|
||||
ex(
|
||||
boost::forward<A1>(a1),
|
||||
boost::forward<A2>(a2),
|
||||
boost::forward<A3>(a3)
|
||||
) {}
|
||||
#endif
|
||||
Executor& underlying_executor() { return ex; }
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
void close() { ex.close(); }
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed() { return ex.closed(); }
|
||||
|
||||
/**
|
||||
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure) {
|
||||
return ex.submit(boost::move(closure));
|
||||
//return ex.submit(boost::forward<work>(closure));
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
submit(boost::move(w));
|
||||
//submit(work(closure));
|
||||
}
|
||||
|
||||
#if 0
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
submit(boost::move(w));
|
||||
}
|
||||
#else
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
submit(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one() { return ex.try_executing_one(); }
|
||||
|
||||
};
|
||||
}
|
||||
using executors::executor_adaptor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
131
include/boost/thread/executors/inline_executor.hpp
Normal file
131
include/boost/thread/executors/inline_executor.hpp
Normal file
@@ -0,0 +1,131 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple serial scheduler.
|
||||
|
||||
#ifndef BOOST_THREAD_INLINE_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_INLINE_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class inline_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
/// inline_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(inline_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a inline executor that runs closures immediately.
|
||||
*
|
||||
* \b Throws: Nothing.
|
||||
*/
|
||||
inline_executor()
|
||||
: closed_(false)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the inline executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c inline_executor destructor.
|
||||
*/
|
||||
~inline_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c inline_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c inline_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
closure();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::inline_executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
209
include/boost/thread/executors/loop_executor.hpp
Normal file
209
include/boost/thread/executors/loop_executor.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
// Copyright (C) 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple user scheduler.
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// rename loop_executor.
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_LOOP_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
class loop_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// loop_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(loop_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
loop_executor()
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c loop_executor destructor.
|
||||
*/
|
||||
~loop_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* loop
|
||||
*/
|
||||
void loop() { worker_thread(); }
|
||||
/**
|
||||
* \b Effects: close the \c loop_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c loop_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* run queued closures
|
||||
*/
|
||||
void run_queued_closures()
|
||||
{
|
||||
sync_queue<work>::underlying_queue_type q = work_queue.underlying_queue();
|
||||
while (q.empty())
|
||||
{
|
||||
work task = q.front();
|
||||
q.pop_front();
|
||||
task();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::loop_executor;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
213
include/boost/thread/executors/serial_executor.hpp
Normal file
213
include/boost/thread/executors/serial_executor.hpp
Normal file
@@ -0,0 +1,213 @@
|
||||
// Copyright (C) 2013 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2013/11 Vicente J. Botet Escriba
|
||||
// first implementation of a simple serial scheduler.
|
||||
|
||||
#ifndef BOOST_THREAD_SERIAL_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_SERIAL_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/sync_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
#include <boost/thread/scoped_thread.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class serial_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
private:
|
||||
typedef scoped_thread<> thread_t;
|
||||
|
||||
/// the thread safe work queue
|
||||
sync_queue<work > work_queue;
|
||||
executor& ex;
|
||||
thread_t thr;
|
||||
|
||||
struct try_executing_one_task {
|
||||
work& task;
|
||||
boost::promise<void> &p;
|
||||
try_executing_one_task(work& task, boost::promise<void> &p)
|
||||
: task(task), p(p) {}
|
||||
void operator()() {
|
||||
task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
p.set_value();
|
||||
}
|
||||
};
|
||||
public:
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
work task;
|
||||
try
|
||||
{
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
boost::promise<void> p;
|
||||
try_executing_one_task tmp(task,p);
|
||||
ex.submit(tmp);
|
||||
// ex.submit([&task, &p]()
|
||||
// {
|
||||
// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
|
||||
// p.set_value();
|
||||
// });
|
||||
p.get_future().wait();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (std::exception& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
private:
|
||||
/**
|
||||
* Effects: schedule one task or yields
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
void schedule_one_or_yield()
|
||||
{
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void worker_thread()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
/// serial_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(serial_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a thread pool that runs closures using one of its closure-executing methods.
|
||||
*
|
||||
* \b Throws: Whatever exception is thrown while initializing the needed resources.
|
||||
*/
|
||||
serial_executor(executor& ex)
|
||||
: ex(ex), thr(&serial_executor::worker_thread, this)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the thread pool.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c serial_executor destructor.
|
||||
*/
|
||||
~serial_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c serial_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
work_queue.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return work_queue.closed();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c serial_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work w ((closure));
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(closure)); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work w =boost::move(closure);
|
||||
work_queue.push_back(boost::move(w));
|
||||
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::serial_executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
136
include/boost/thread/executors/thread_executor.hpp
Normal file
136
include/boost/thread/executors/thread_executor.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// 2014/01 Vicente J. Botet Escriba
|
||||
// first implementation of a thread_executor.
|
||||
|
||||
#ifndef BOOST_THREAD_THREAD_EXECUTOR_HPP
|
||||
#define BOOST_THREAD_THREAD_EXECUTOR_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
#include <boost/thread/thread_only.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
class thread_executor
|
||||
{
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
bool closed_;
|
||||
/**
|
||||
* Effects: try to execute one task.
|
||||
* Returns: whether a task has been executed.
|
||||
* Throws: whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public:
|
||||
/// thread_executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(thread_executor)
|
||||
|
||||
/**
|
||||
* \b Effects: creates a inline executor that runs closures immediately.
|
||||
*
|
||||
* \b Throws: Nothing.
|
||||
*/
|
||||
thread_executor()
|
||||
: closed_(false)
|
||||
{
|
||||
}
|
||||
/**
|
||||
* \b Effects: Destroys the inline executor.
|
||||
*
|
||||
* \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor.
|
||||
*/
|
||||
~thread_executor()
|
||||
{
|
||||
// signal to all the worker thread that there will be no more submissions.
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c thread_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
void close()
|
||||
{
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed()
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \b Effects: The specified \c closure will be scheduled for execution at some point in the future.
|
||||
* If invoked closure throws an exception the \c thread_executor will call \c std::terminate, as is the case with threads.
|
||||
*
|
||||
* \b Synchronization: completion of \c closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \b Throws: \c sync_queue_is_closed if the thread pool is closed.
|
||||
* Whatever exception that can be throw while storing the closure.
|
||||
*/
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
if (closed()) return;
|
||||
thread th(closure);
|
||||
th.detach();
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
if (closed()) return;
|
||||
thread th(boost::forward<Closure>(closure));
|
||||
th.detach();
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: This must be called from an scheduled task.
|
||||
*
|
||||
* \b Effects: reschedule functions until pred()
|
||||
*/
|
||||
template <typename Pred>
|
||||
bool reschedule_until(Pred const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::thread_executor;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
21
include/boost/thread/executors/work.hpp
Normal file
21
include/boost/thread/executors/work.hpp
Normal file
@@ -0,0 +1,21 @@
|
||||
// (C) Copyright 2013,2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
|
||||
|
||||
#include <boost/thread/detail/nullary_function.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
typedef detail::nullary_function<void()> work;
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_THREAD_EXECUTORS_WORK_HPP
|
||||
@@ -18,7 +18,7 @@
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/utility/swap.hpp>
|
||||
#include <boost/core/swap.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace boost
|
||||
/// move assignment
|
||||
externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) // BOOST_NOEXCEPT
|
||||
{
|
||||
obj_=move(rhs.obj_);
|
||||
obj_=move(BOOST_THREAD_RV(rhs).obj_);
|
||||
mtx_=rhs.mtx_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
#define BOOST_THREAD_FUTURE_ERROR_CODE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/detail/scoped_enum_emulation.hpp>
|
||||
#include <boost/core/scoped_enum.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
@@ -29,11 +29,11 @@ namespace boost
|
||||
namespace system
|
||||
{
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type {};
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc> : public true_type {};
|
||||
|
||||
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
|
||||
template <>
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
|
||||
struct BOOST_SYMBOL_VISIBLE is_error_code_enum< ::boost::future_errc::enum_type> : public true_type { };
|
||||
#endif
|
||||
} // system
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace boost
|
||||
error_condition
|
||||
make_error_condition(future_errc e) BOOST_NOEXCEPT
|
||||
{
|
||||
return error_condition(underlying_cast<int>(e), future_category());
|
||||
return error_condition(underlying_cast<int>(e), boost::future_category());
|
||||
}
|
||||
} // system
|
||||
} // boost
|
||||
|
||||
@@ -23,28 +23,40 @@ namespace boost
|
||||
{
|
||||
class latch
|
||||
{
|
||||
/// @Requires: count_.value_ must be greater than 0
|
||||
/// Effect: Decrement the count. Unlocks the lock notify anyone waiting if we reached zero.
|
||||
/// Returns: true if count_.value_ reached the value 0.
|
||||
/// @Requires: count_ must be greater than 0
|
||||
/// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero.
|
||||
/// Returns: true if count_ reached the value 0.
|
||||
/// @ThreadSafe ensured by the @c lk parameter
|
||||
bool count_down(unique_lock<mutex> &lk)
|
||||
/// pre_condition (count_.value_ > 0)
|
||||
/// pre_condition (count_ > 0)
|
||||
{
|
||||
BOOST_ASSERT(count_.value_ > 0);
|
||||
if (--count_.value_ == 0)
|
||||
BOOST_ASSERT(count_ > 0);
|
||||
if (--count_ == 0)
|
||||
{
|
||||
count_.cond_.notify_all();
|
||||
++generation_;
|
||||
lk.unlock();
|
||||
cond_.notify_all();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// Effect: Decrement the count is > 0. Unlocks the lock notify anyone waiting if we reached zero.
|
||||
/// Returns: true if count_ is 0.
|
||||
/// @ThreadSafe ensured by the @c lk parameter
|
||||
bool try_count_down(unique_lock<mutex> &lk)
|
||||
{
|
||||
if (count_ > 0)
|
||||
{
|
||||
return count_down(lk);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
BOOST_THREAD_NO_COPYABLE( latch)
|
||||
|
||||
/// Constructs a latch with a given count.
|
||||
latch(std::size_t count) :
|
||||
count_(count)
|
||||
count_(count), generation_(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -60,7 +72,8 @@ namespace boost
|
||||
void wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
count_.cond_.wait(lk, detail::counter_is_zero(count_));
|
||||
std::size_t generation(generation_);
|
||||
cond_.wait(lk, detail::not_equal(generation, generation_));
|
||||
}
|
||||
|
||||
/// @return true if the internal counter is already 0, false otherwise
|
||||
@@ -76,7 +89,8 @@ namespace boost
|
||||
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
return count_.cond_.wait_for(lk, rel_time, detail::counter_is_zero(count_))
|
||||
std::size_t generation(generation_);
|
||||
return cond_.wait_for(lk, rel_time, detail::not_equal(generation, generation_))
|
||||
? cv_status::no_timeout
|
||||
: cv_status::timeout;
|
||||
}
|
||||
@@ -87,7 +101,8 @@ namespace boost
|
||||
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
return count_.cond_.wait_until(lk, abs_time, detail::counter_is_zero(count_))
|
||||
std::size_t generation(generation_);
|
||||
return cond_.wait_until(lk, abs_time, detail::not_equal(generation, generation_))
|
||||
? cv_status::no_timeout
|
||||
: cv_status::timeout;
|
||||
}
|
||||
@@ -99,6 +114,13 @@ namespace boost
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
count_down(lk);
|
||||
}
|
||||
/// Effect: Decrement the count if it is > 0 and notify anyone waiting if we reached zero.
|
||||
/// Returns: true if count_ was 0 or reached 0.
|
||||
bool try_count_down()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
return try_count_down(lk);
|
||||
}
|
||||
void signal()
|
||||
{
|
||||
count_down();
|
||||
@@ -110,11 +132,12 @@ namespace boost
|
||||
void count_down_and_wait()
|
||||
{
|
||||
boost::unique_lock<boost::mutex> lk(mutex_);
|
||||
std::size_t generation(generation_);
|
||||
if (count_down(lk))
|
||||
{
|
||||
return;
|
||||
}
|
||||
count_.cond_.wait(lk, detail::counter_is_zero(count_));
|
||||
cond_.wait(lk, detail::not_equal(generation, generation_));
|
||||
}
|
||||
void sync()
|
||||
{
|
||||
@@ -132,7 +155,9 @@ namespace boost
|
||||
|
||||
private:
|
||||
mutex mutex_;
|
||||
detail::counter count_;
|
||||
condition_variable cond_;
|
||||
std::size_t count_;
|
||||
std::size_t generation_;
|
||||
};
|
||||
|
||||
} // namespace boost
|
||||
|
||||
@@ -336,12 +336,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
m->lock();
|
||||
is_locked = true;
|
||||
@@ -351,12 +351,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked = m->try_lock();
|
||||
return is_locked;
|
||||
@@ -367,11 +367,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock(relative_time);
|
||||
return is_locked;
|
||||
@@ -381,11 +381,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
return is_locked;
|
||||
@@ -394,11 +394,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
return is_locked;
|
||||
@@ -411,11 +411,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_for(rel_time);
|
||||
return is_locked;
|
||||
@@ -425,11 +425,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost unique_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_until(abs_time);
|
||||
return is_locked;
|
||||
@@ -441,12 +441,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock has no mutex"));
|
||||
}
|
||||
if (!owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock doesn't own the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost unique_lock doesn't own the mutex"));
|
||||
}
|
||||
m->unlock();
|
||||
is_locked = false;
|
||||
@@ -636,11 +636,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
m->lock_shared();
|
||||
is_locked=true;
|
||||
@@ -649,11 +649,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_shared();
|
||||
return is_locked;
|
||||
@@ -663,11 +663,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock_shared(target_time);
|
||||
return is_locked;
|
||||
@@ -677,11 +677,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->timed_lock_shared(target_time);
|
||||
return is_locked;
|
||||
@@ -693,11 +693,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_shared_for(rel_time);
|
||||
return is_locked;
|
||||
@@ -707,11 +707,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_shared_until(abs_time);
|
||||
return is_locked;
|
||||
@@ -721,11 +721,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(!owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock doesn't own the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock doesn't own the mutex"));
|
||||
}
|
||||
m->unlock_shared();
|
||||
is_locked=false;
|
||||
@@ -934,12 +934,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex"));
|
||||
}
|
||||
m->lock_upgrade();
|
||||
is_locked = true;
|
||||
@@ -949,12 +949,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if (owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost upgrade_lock owns already the mutex"));
|
||||
}
|
||||
is_locked = m->try_lock_upgrade();
|
||||
return is_locked;
|
||||
@@ -964,12 +964,12 @@ namespace boost
|
||||
if (m == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if (!owns_lock())
|
||||
{
|
||||
boost::throw_exception(
|
||||
boost::lock_error(system::errc::operation_not_permitted, "boost upgrade_lock doesn't own the mutex"));
|
||||
boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost upgrade_lock doesn't own the mutex"));
|
||||
}
|
||||
m->unlock_upgrade();
|
||||
is_locked = false;
|
||||
@@ -980,11 +980,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_upgrade_for(rel_time);
|
||||
return is_locked;
|
||||
@@ -994,11 +994,11 @@ namespace boost
|
||||
{
|
||||
if(m==0)
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::operation_not_permitted), "boost shared_lock has no mutex"));
|
||||
}
|
||||
if(owns_lock())
|
||||
{
|
||||
boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex"));
|
||||
boost::throw_exception(boost::lock_error(static_cast<int>(system::errc::resource_deadlock_would_occur), "boost shared_lock owns already the mutex"));
|
||||
}
|
||||
is_locked=m->try_lock_upgrade_until(abs_time);
|
||||
return is_locked;
|
||||
@@ -1112,6 +1112,10 @@ namespace boost
|
||||
{
|
||||
return exclusive.owns_lock();
|
||||
}
|
||||
Mutex* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return exclusive.mutex();
|
||||
}
|
||||
};
|
||||
|
||||
BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock<Mutex> BOOST_THREAD_DCL_MOVABLE_END
|
||||
@@ -1187,7 +1191,7 @@ private unique_lock<Mutex>
|
||||
{
|
||||
return base::owns_lock();
|
||||
}
|
||||
Mutex* mutex() const
|
||||
Mutex* mutex() const BOOST_NOEXCEPT
|
||||
{
|
||||
return base::mutex();
|
||||
}
|
||||
|
||||
@@ -37,11 +37,11 @@ namespace boost
|
||||
basic_lockable_adapter()
|
||||
{}
|
||||
|
||||
void lock()
|
||||
void lock() const
|
||||
{
|
||||
lockable().lock();
|
||||
}
|
||||
void unlock()
|
||||
void unlock() const
|
||||
{
|
||||
lockable().unlock();
|
||||
}
|
||||
@@ -56,7 +56,7 @@ namespace boost
|
||||
public:
|
||||
typedef Lockable mutex_type;
|
||||
|
||||
bool try_lock()
|
||||
bool try_lock() const
|
||||
{
|
||||
return this->lockable().try_lock();
|
||||
}
|
||||
@@ -71,12 +71,12 @@ namespace boost
|
||||
typedef TimedLock mutex_type;
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_lock_for(rel_time);
|
||||
}
|
||||
@@ -91,26 +91,26 @@ namespace boost
|
||||
public:
|
||||
typedef SharableLock mutex_type;
|
||||
|
||||
void lock_shared()
|
||||
void lock_shared() const
|
||||
{
|
||||
this->lockable().lock_shared();
|
||||
}
|
||||
bool try_lock_shared()
|
||||
bool try_lock_shared() const
|
||||
{
|
||||
return this->lockable().try_lock_shared();
|
||||
}
|
||||
void unlock_shared()
|
||||
void unlock_shared() const
|
||||
{
|
||||
this->lockable().unlock_shared();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_lock_shared_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_lock_shared_for(rel_time);
|
||||
}
|
||||
@@ -126,95 +126,95 @@ namespace boost
|
||||
public:
|
||||
typedef UpgradableLock mutex_type;
|
||||
|
||||
void lock_upgrade()
|
||||
void lock_upgrade() const
|
||||
{
|
||||
this->lockable().lock_upgrade();
|
||||
}
|
||||
|
||||
bool try_lock_upgrade()
|
||||
bool try_lock_upgrade() const
|
||||
{
|
||||
return this->lockable().try_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade()
|
||||
void unlock_upgrade() const
|
||||
{
|
||||
this->lockable().unlock_upgrade();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_lock_upgrade_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock()
|
||||
bool try_unlock_shared_and_lock() const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
void unlock_and_lock_shared() const
|
||||
{
|
||||
this->lockable().unlock_and_lock_shared();
|
||||
}
|
||||
|
||||
bool try_unlock_shared_and_lock_upgrade()
|
||||
bool try_unlock_shared_and_lock_upgrade() const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade();
|
||||
}
|
||||
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_shared_and_lock_upgrade_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_and_lock_upgrade()
|
||||
void unlock_and_lock_upgrade() const
|
||||
{
|
||||
this->lockable().unlock_and_lock_upgrade();
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock()
|
||||
void unlock_upgrade_and_lock() const
|
||||
{
|
||||
this->lockable().unlock_upgrade_and_lock();
|
||||
}
|
||||
|
||||
bool try_unlock_upgrade_and_lock()
|
||||
bool try_unlock_upgrade_and_lock() const
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock();
|
||||
}
|
||||
template <typename Clock, typename Duration>
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
|
||||
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock_until(abs_time);
|
||||
}
|
||||
template <typename Rep, typename Period>
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
|
||||
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time) const
|
||||
{
|
||||
return this->lockable().try_unlock_upgrade_and_lock_for(rel_time);
|
||||
}
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
void unlock_upgrade_and_lock_shared() const
|
||||
{
|
||||
this->lockable().unlock_upgrade_and_lock_shared();
|
||||
}
|
||||
|
||||
45
include/boost/thread/ostream_buffer.hpp
Normal file
45
include/boost/thread/ostream_buffer.hpp
Normal file
@@ -0,0 +1,45 @@
|
||||
// (C) Copyright 2013 Vicente J. Botet Escriba
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_OSTREAM_BUFFER_HPP
|
||||
#define BOOST_THREAD_OSTREAM_BUFFER_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <sstream>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
template <typename OStream>
|
||||
class ostream_buffer
|
||||
{
|
||||
public:
|
||||
typedef std::basic_ostringstream<typename OStream::char_type, typename OStream::traits_type> stream_type;
|
||||
ostream_buffer(OStream& os) :
|
||||
os_(os)
|
||||
{
|
||||
}
|
||||
~ostream_buffer()
|
||||
{
|
||||
os_ << o_str_.str();
|
||||
}
|
||||
stream_type& stream()
|
||||
{
|
||||
return o_str_;
|
||||
}
|
||||
private:
|
||||
OStream& os_;
|
||||
stream_type o_str_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif // header
|
||||
@@ -200,15 +200,15 @@ namespace boost
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
bool timed_wait(lock_type& m,boost::system_time const& abs_time)
|
||||
{
|
||||
struct timespec const timeout=detail::to_timespec(wait_until);
|
||||
struct timespec const timeout=detail::to_timespec(abs_time);
|
||||
return do_wait_until(m, timeout);
|
||||
}
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until)
|
||||
bool timed_wait(lock_type& m,xtime const& abs_time)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
return timed_wait(m,system_time(abs_time));
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type>
|
||||
@@ -218,20 +218,20 @@ namespace boost
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
|
||||
bool timed_wait(lock_type& m,boost::system_time const& abs_time, predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
if(!timed_wait(m, abs_time))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename lock_type,typename predicate_type>
|
||||
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
|
||||
bool timed_wait(lock_type& m,xtime const& abs_time, predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
return timed_wait(m,system_time(abs_time),pred);
|
||||
}
|
||||
|
||||
template<typename lock_type,typename duration_type,typename predicate_type>
|
||||
|
||||
@@ -98,21 +98,21 @@ namespace boost
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
inline bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until)
|
||||
boost::system_time const& abs_time)
|
||||
{
|
||||
#if defined BOOST_THREAD_WAIT_BUG
|
||||
struct timespec const timeout=detail::to_timespec(wait_until + BOOST_THREAD_WAIT_BUG);
|
||||
struct timespec const timeout=detail::to_timespec(abs_time + BOOST_THREAD_WAIT_BUG);
|
||||
return do_wait_until(m, timeout);
|
||||
#else
|
||||
struct timespec const timeout=detail::to_timespec(wait_until);
|
||||
struct timespec const timeout=detail::to_timespec(abs_time);
|
||||
return do_wait_until(m, timeout);
|
||||
#endif
|
||||
}
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
xtime const& wait_until)
|
||||
xtime const& abs_time)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until));
|
||||
return timed_wait(m,system_time(abs_time));
|
||||
}
|
||||
|
||||
template<typename duration_type>
|
||||
@@ -126,11 +126,11 @@ namespace boost
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
boost::system_time const& wait_until,predicate_type pred)
|
||||
boost::system_time const& abs_time,predicate_type pred)
|
||||
{
|
||||
while (!pred())
|
||||
{
|
||||
if(!timed_wait(m, wait_until))
|
||||
if(!timed_wait(m, abs_time))
|
||||
return pred();
|
||||
}
|
||||
return true;
|
||||
@@ -139,9 +139,9 @@ namespace boost
|
||||
template<typename predicate_type>
|
||||
bool timed_wait(
|
||||
unique_lock<mutex>& m,
|
||||
xtime const& wait_until,predicate_type pred)
|
||||
xtime const& abs_time,predicate_type pred)
|
||||
{
|
||||
return timed_wait(m,system_time(wait_until),pred);
|
||||
return timed_wait(m,system_time(abs_time),pred);
|
||||
}
|
||||
|
||||
template<typename duration_type,typename predicate_type>
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
|
||||
#include <boost/thread/lock_types.hpp>
|
||||
@@ -105,7 +106,9 @@ namespace boost
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
BOOST_VERIFY(!posix::pthread_mutex_destroy(&m));
|
||||
int const res = posix::pthread_mutex_destroy(&m);
|
||||
boost::ignore_unused(res);
|
||||
BOOST_ASSERT(!res);
|
||||
}
|
||||
|
||||
void lock()
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
@@ -42,7 +42,7 @@ namespace boost
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
|
||||
#else
|
||||
@@ -65,7 +65,7 @@ namespace boost
|
||||
private:
|
||||
volatile thread_detail::uintmax_atomic_t epoch;
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template<typename Function, class ...ArgTypes>
|
||||
friend void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args);
|
||||
#else
|
||||
@@ -118,7 +118,7 @@ namespace boost
|
||||
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
|
||||
template<typename Function, class ...ArgTypes>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/detail/no_exceptions_support.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/atomic.hpp>
|
||||
|
||||
@@ -115,7 +115,7 @@ namespace boost
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
template<typename Function, class ...ArgTypes>
|
||||
inline void call_once(once_flag& flag, BOOST_THREAD_RV_REF(Function) f, BOOST_THREAD_RV_REF(ArgTypes)... args)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
@@ -82,7 +81,7 @@ namespace boost
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct future_object_base;
|
||||
struct shared_state_base;
|
||||
struct tss_cleanup_function;
|
||||
struct thread_exit_callback_node;
|
||||
struct tss_data_node
|
||||
@@ -121,7 +120,7 @@ namespace boost
|
||||
> notify_list_t;
|
||||
notify_list_t notify;
|
||||
|
||||
typedef std::vector<shared_ptr<future_object_base> > async_states_t;
|
||||
typedef std::vector<shared_ptr<shared_state_base> > async_states_t;
|
||||
async_states_t async_states_;
|
||||
|
||||
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
|
||||
@@ -154,7 +153,7 @@ namespace boost
|
||||
notify.push_back(std::pair<condition_variable*, mutex*>(cv, m));
|
||||
}
|
||||
|
||||
void make_ready_at_thread_exit(shared_ptr<future_object_base> as)
|
||||
void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
|
||||
{
|
||||
async_states_.push_back(as);
|
||||
}
|
||||
@@ -220,11 +219,11 @@ namespace boost
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
@@ -237,6 +236,27 @@ namespace boost
|
||||
#endif
|
||||
#endif // BOOST_THREAD_USES_CHRONO
|
||||
|
||||
namespace no_interruption_point
|
||||
{
|
||||
namespace hiden
|
||||
{
|
||||
void BOOST_THREAD_DECL sleep_for(const timespec& ts);
|
||||
void BOOST_THREAD_DECL sleep_until(const timespec& ts);
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_USES_CHRONO
|
||||
#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY
|
||||
|
||||
inline
|
||||
void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns)
|
||||
{
|
||||
return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns));
|
||||
}
|
||||
#endif
|
||||
#endif // BOOST_THREAD_USES_CHRONO
|
||||
|
||||
} // no_interruption_point
|
||||
|
||||
void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT;
|
||||
|
||||
#if defined BOOST_THREAD_USES_DATETIME
|
||||
|
||||
@@ -47,14 +47,13 @@ namespace boost
|
||||
*
|
||||
*/
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class F, class ...Args>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) :
|
||||
t_(boost::forward<F>(f)) {}
|
||||
template <class F, class A1>
|
||||
strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
|
||||
@@ -138,14 +137,13 @@ namespace boost
|
||||
*/
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template <class F, class ...Args>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
|
||||
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
|
||||
#else
|
||||
template <class F>
|
||||
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f,
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0) :
|
||||
typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) :
|
||||
t_(boost::forward<F>(f)) {}
|
||||
template <class F, class A1>
|
||||
scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
|
||||
@@ -179,7 +177,7 @@ namespace boost
|
||||
* Move constructor.
|
||||
*/
|
||||
scoped_thread(BOOST_RV_REF(scoped_thread) x) BOOST_NOEXCEPT :
|
||||
t_(boost::move(x.t_))
|
||||
t_(boost::move(BOOST_THREAD_RV(x).t_))
|
||||
{}
|
||||
|
||||
/**
|
||||
@@ -199,7 +197,7 @@ namespace boost
|
||||
*/
|
||||
scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x)
|
||||
{
|
||||
t_ = boost::move(x.t_);
|
||||
t_ = boost::move(BOOST_THREAD_RV(x).t_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -263,11 +261,17 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
static unsigned hardware_concurrency()BOOST_NOEXCEPT
|
||||
static unsigned hardware_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::hardware_concurrency();
|
||||
}
|
||||
|
||||
#ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY
|
||||
static unsigned physical_concurrency() BOOST_NOEXCEPT
|
||||
{
|
||||
return thread::physical_concurrency();
|
||||
}
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -16,9 +16,10 @@
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
@@ -28,10 +29,14 @@ namespace boost
|
||||
{ success = 0, empty, full, closed, busy }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
#endif
|
||||
|
||||
struct sync_queue_is_closed : std::exception {};
|
||||
struct sync_queue_is_closed : std::exception
|
||||
{
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
@@ -48,31 +53,49 @@ namespace boost
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
bool empty() const;
|
||||
bool full() const;
|
||||
size_type capacity() const;
|
||||
size_type size() const;
|
||||
bool closed() const;
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type capacity() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
void close();
|
||||
inline void close();
|
||||
|
||||
void push(const value_type& x);
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
bool try_push(const value_type& x);
|
||||
bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
bool try_push(no_block_tag, const value_type& x);
|
||||
bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
void pull(value_type&);
|
||||
void pull(ValueType& elem, bool & closed);
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull();
|
||||
shared_ptr<ValueType> ptr_pull();
|
||||
bool try_pull(value_type&);
|
||||
bool try_pull(no_block_tag,value_type&);
|
||||
shared_ptr<ValueType> try_pull();
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
@@ -86,42 +109,61 @@ namespace boost
|
||||
size_type capacity_;
|
||||
bool closed_;
|
||||
|
||||
size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
inline size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (idx + 1) % capacity_;
|
||||
}
|
||||
|
||||
bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity;
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return ((out_+capacity_-in_) % capacity_)-1;
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity_-1;
|
||||
}
|
||||
inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT
|
||||
{
|
||||
if (full(lk)) return capacity(lk);
|
||||
return ((out_+capacity(lk)-in_) % capacity(lk));
|
||||
}
|
||||
|
||||
void throw_if_closed(unique_lock<mutex>&);
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>&) const;
|
||||
|
||||
bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
@@ -130,7 +172,7 @@ namespace boost
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
inline void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_full_ > 0)
|
||||
{
|
||||
@@ -140,40 +182,59 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
|
||||
|
||||
void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
inline void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
in_ = in;
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = elem;
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = boost::move(elem);
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
@@ -233,6 +294,11 @@ namespace boost
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
@@ -261,7 +327,7 @@ namespace boost
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -283,53 +349,61 @@ namespace boost
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
@@ -364,70 +438,74 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk, closed);
|
||||
if (closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
// template <typename ValueType>
|
||||
// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
// {
|
||||
// unique_lock<mutex> lk(mtx_);
|
||||
// wait_until_not_empty(lk, closed);
|
||||
// if (closed) {return;}
|
||||
// pull(elem, lk);
|
||||
// }
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
value_type elem;
|
||||
pull(elem);
|
||||
return boost::move(elem);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -440,38 +518,67 @@ namespace boost
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
@@ -489,21 +596,22 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
@@ -520,70 +628,101 @@ namespace boost
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
try
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push(boost::forward<ValueType>(elem));
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push(elem);
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull(elem);
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user