mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 21:52:07 +00:00
Compare commits
825 Commits
boost-1.54
...
feature/ta
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8ad389bdd | ||
|
|
69c1d40750 | ||
|
|
58698f44f1 | ||
|
|
37afdd2e9a | ||
|
|
c87b24923a | ||
|
|
1210fc4859 | ||
|
|
d8b6ae6266 | ||
|
|
04e2223d5e | ||
|
|
579748e7a0 | ||
|
|
41c3914aaf | ||
|
|
8693eec4a4 | ||
|
|
3f699750a8 | ||
|
|
4f8243cf59 | ||
|
|
4f01891da7 | ||
|
|
efab5af918 | ||
|
|
4d03b410a8 | ||
|
|
c1925df81c | ||
|
|
cbf9fe8a5c | ||
|
|
6fd7dc0d94 | ||
|
|
a2f2924298 | ||
|
|
49d485f1aa | ||
|
|
d7251f223e | ||
|
|
20a6ef7de8 | ||
|
|
d5c41e4c4a | ||
|
|
b96b9904b7 | ||
|
|
304240b206 | ||
|
|
c61c139933 | ||
|
|
c3b98129e4 | ||
|
|
3891eeef52 | ||
|
|
f1370b1255 | ||
|
|
69f2a1df72 | ||
|
|
700301e382 | ||
|
|
952aa44a98 | ||
|
|
5fb51a74fe | ||
|
|
02bb6abef4 | ||
|
|
1a4bd71616 | ||
|
|
63dd439992 | ||
|
|
1029fa9c59 | ||
|
|
3e28ea806c | ||
|
|
07dc40a9ff | ||
|
|
6f91af2154 | ||
|
|
c3cff80557 | ||
|
|
729c8b63bb | ||
|
|
6fe7f44ea0 | ||
|
|
8fd4755e79 | ||
|
|
02b007a20e | ||
|
|
c0c78e87fc | ||
|
|
58cde5af05 | ||
|
|
c1f2c8a1f1 | ||
|
|
bacf5b52ec | ||
|
|
3babf7966e | ||
|
|
f3de7bf10f | ||
|
|
90154217cf | ||
|
|
ac0b2f9ba7 | ||
|
|
da739e680a | ||
|
|
b240b097c7 | ||
|
|
debe2fb0d1 | ||
|
|
b264ec8fc0 | ||
|
|
372f8fe10f | ||
|
|
e3c240df0a | ||
|
|
748ea5164e | ||
|
|
b44627f97d | ||
|
|
c8cd7d1d08 | ||
|
|
f0d0c0551b | ||
|
|
bb72eadbd8 | ||
|
|
f52f32afda | ||
|
|
b973e9b32e | ||
|
|
1ffef9ed2d | ||
|
|
f24ea524bd | ||
|
|
4111471ba5 | ||
|
|
5e970b987e | ||
|
|
c7b5729cf3 | ||
|
|
291ebded8e | ||
|
|
0c2c8ed3b8 | ||
|
|
5294dfa149 | ||
|
|
7f5dfb633d | ||
|
|
f381a7d591 | ||
|
|
aceabda609 | ||
|
|
dc4b619b57 | ||
|
|
abb3fc97e0 | ||
|
|
ec6ae7b9b4 | ||
|
|
8c5ba97d39 | ||
|
|
617b979214 | ||
|
|
96667cfcce | ||
|
|
a981650ce9 | ||
|
|
00b25853b2 | ||
|
|
ef04ce8bce | ||
|
|
5091ad705f | ||
|
|
b77f802c47 | ||
|
|
da945436c1 | ||
|
|
27befdf26f | ||
|
|
f73007910a | ||
|
|
8c3cfacf06 | ||
|
|
7d4392e157 | ||
|
|
aff3f424a9 | ||
|
|
546ca909c4 | ||
|
|
7dac51706c | ||
|
|
5ee0e27b5a | ||
|
|
b4fd7fdeb1 | ||
|
|
c75ea7db89 | ||
|
|
19294dc756 | ||
|
|
52a360775e | ||
|
|
c632b75db1 | ||
|
|
11e4c950ac | ||
|
|
8440e9a7d8 | ||
|
|
02bc292c20 | ||
|
|
6d68bac44b | ||
|
|
5d0d128cab | ||
|
|
ec542d3c8b | ||
|
|
6e3216643b | ||
|
|
016f5653cf | ||
|
|
ce46539183 | ||
|
|
e93035ce42 | ||
|
|
53a46593a8 | ||
|
|
c2426b8fad | ||
|
|
7d841f6337 | ||
|
|
556bbde8a7 | ||
|
|
a0c1462a6a | ||
|
|
234df13faf | ||
|
|
24983f0bce | ||
|
|
722997379b | ||
|
|
f36f5d6dbb | ||
|
|
9ee1044f92 | ||
|
|
ebeb36646c | ||
|
|
8ebf0e7f21 | ||
|
|
0dc2f69bc1 | ||
|
|
c3b549d947 | ||
|
|
6552cf64b5 | ||
|
|
d5f335b8a4 | ||
|
|
80591fb64d | ||
|
|
0543b522cb | ||
|
|
3dbc5d0664 | ||
|
|
2d0272345b | ||
|
|
f1a274b51c | ||
|
|
b7f1706ab8 | ||
|
|
f299fb8083 | ||
|
|
074dcbcbf5 | ||
|
|
af6f80a3c7 | ||
|
|
957253401f | ||
|
|
3195253230 | ||
|
|
4336a7bbe3 | ||
|
|
3b75d6dabc | ||
|
|
fc0d7e23b3 | ||
|
|
aeabda8d45 | ||
|
|
3bde7e103c | ||
|
|
ea0889485e | ||
|
|
d4d46c64dd | ||
|
|
f3fa80c866 | ||
|
|
7e21f24991 | ||
|
|
2037a64c51 | ||
|
|
8bfd1cea31 | ||
|
|
a26e7eb8c4 | ||
|
|
e47eba8751 | ||
|
|
8aef8000d9 | ||
|
|
0b2a61bca0 | ||
|
|
78f1044c68 | ||
|
|
26042ca26a | ||
|
|
74132067ba | ||
|
|
c4d42e6b6c | ||
|
|
59c504d5d8 | ||
|
|
b81a838a43 | ||
|
|
c6e70226ea | ||
|
|
5cdd807718 | ||
|
|
2a6948d74d | ||
|
|
a06dde3794 | ||
|
|
726a3faf19 | ||
|
|
590a3d99b0 | ||
|
|
c977c8d420 | ||
|
|
a1faacd7bb | ||
|
|
866b78cbd0 | ||
|
|
0861f81b05 | ||
|
|
6488028a22 | ||
|
|
14dfe49c50 | ||
|
|
08c4599fb6 | ||
|
|
ca14e6187d | ||
|
|
f263c6014e | ||
|
|
9e962e12e2 | ||
|
|
6e154d45a4 | ||
|
|
c54e519f72 | ||
|
|
5c61dced5e | ||
|
|
8a7f927be9 | ||
|
|
6074487b73 | ||
|
|
04c53415fd | ||
|
|
fe6daec2bc | ||
|
|
f75b2ca155 | ||
|
|
68be44ec06 | ||
|
|
817591b87c | ||
|
|
d7a3f124db | ||
|
|
c6817aeb1c | ||
|
|
9ceea9822f | ||
|
|
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 |
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
#mac
|
||||
.DS_Store
|
||||
|
||||
#projects
|
||||
.project
|
||||
|
||||
# Compiled Object files
|
||||
*.slo
|
||||
*.lo
|
||||
*.o
|
||||
*.obj
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Compiled Dynamic libraries
|
||||
*.so
|
||||
*.dylib
|
||||
*.dll
|
||||
|
||||
# Fortran module files
|
||||
*.mod
|
||||
|
||||
# Compiled Static libraries
|
||||
*.lai
|
||||
*.la
|
||||
*.a
|
||||
*.lib
|
||||
|
||||
# Executables
|
||||
bin/*
|
||||
test/bin/*
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
#doc
|
||||
|
||||
doc/html
|
||||
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
|
||||
@@ -77,19 +78,19 @@ project boost/thread
|
||||
<toolset>pathscale:<cxxflags>-pedantic
|
||||
|
||||
<toolset>clang:<cxxflags>-Wextra
|
||||
<toolset>clang:<cxxflags>-pedantic
|
||||
#<toolset>clang:<cxxflags>-ansi
|
||||
#<toolset>clang:<cxxflags>-fpermissive
|
||||
<toolset>clang:<cxxflags>-Wno-long-long
|
||||
<toolset>clang:<cxxflags>-Wunused-function
|
||||
<toolset>clang:<cxxflags>-Wno-variadic-macros
|
||||
<toolset>clang:<warnings>on
|
||||
|
||||
<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;
|
||||
}
|
||||
1215
doc/async_executors.qbk
Normal file
1215
doc/async_executors.qbk
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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]
|
||||
|
||||
228
doc/changes.qbk
228
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,205 @@
|
||||
|
||||
[section:changes History]
|
||||
|
||||
[/
|
||||
[heading Version 4.2.0 - boost 1.55]
|
||||
[heading Version 4.5.0 - boost 1.58]
|
||||
|
||||
[*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/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/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/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/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/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/10537 #10537] Application crash on throw exception
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
[*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,
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9600 #9600] Async: Add task_region
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10611 #10611] Add emplace promise::set_value and emplace make_ready_future
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
]
|
||||
|
||||
[heading Version 4.4.0 - boost 1.57]
|
||||
|
||||
[*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/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/9118 #9118] Seg fault on thread join when llvm and libc++ are used
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9309 #9309] test_latch fails often on clang-darwin-tot11
|
||||
* [@http://svn.boost.org/trac/boost/ticket/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/10537 #10537] Application crash on throw exception
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10651 #10651] boost::thread leaks memory when using the MinGW compiler
|
||||
|
||||
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
|
||||
|
||||
Please take a look at [@http://www.boost.org/development/tests/master/developer/thread.html thread trunk regression test] to see the last snapshot.
|
||||
|
||||
[*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,
|
||||
|
||||
[*New Experimental Features:]
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Synchro: Use of variadic templates on Generic Locking Algorithms on compilers providing them
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10298 #10298] Synchro: Added queue views.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10300 #10300] Async: Added generic_executor_ref.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10552 #10552] Add make_valid_future
|
||||
|
||||
[*Fixed Bugs:]
|
||||
|
||||
* [@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/6787 #6787] boost::thread::sleep() hangs if system time is rolled back
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7665 #7665] this_thread::sleep_for no longer uses steady_clock in thread
|
||||
* [@http://svn.boost.org/trac/boost/ticket/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/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
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9787 #9787] [windows] Small duration value passed down to basic_timed_mutex::try_lock_until and condition_variable::wait_until can cause infinite or near infinite wait for win32
|
||||
* [@http://svn.boost.org/trac/boost/ticket/9880 #9880] [windows] boost::condition_variable.timed_wait() exception if system time < 1970
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10159 #10159] GCC 4.4 error sorry, unimplemented
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10196 #10196] thread_specific_ptr does not support void*
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10296 #10296] Boost.Thread 1.56 rc1 does not compile on Mingw
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10297 #10297] Boost.Thread 1.56 rc1 hangs when built with clang on armhf
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10340 #10340] No boost::promise<T>::set_value(const T&) overload present in C++03 mode
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10425 #10425] Missing documentation for when_all/when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10426 #10426] Take in account the deferred futures in when_all.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10427 #10427] Take in account the deferred and ready futures in when_any.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10428 #10428] Adapt to new unique_ptr interface in Boost.Move
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10465 #10465] Missing implementation of when_all/when_any when the result is a tuple.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10476 #10476] classes using BOOST_THREAD_MOVABLE_ONLY<T> dont satisfy is_copy_constructible<T>::value == false
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10478 #10478] Data race in boost/thread/future.hpp
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10529 #10529] The pthread/condition_variable_any constructor reports incorrect error code for pthread_cond_init
|
||||
* [@http://svn.boost.org/trac/boost/ticket/10563 #10563] shared_future<R>::then should be const
|
||||
|
||||
|
||||
[heading Version 4.3.0 - boost 1.56]
|
||||
|
||||
[*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/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/master/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/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]
|
||||
|
||||
@@ -409,33 +591,15 @@ been moved to __thread_id__.
|
||||
|
||||
The following features will be included in next releases.
|
||||
|
||||
# Complete the C++11 missing features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
|
||||
|
||||
# Add some minor features, in particular
|
||||
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
|
||||
|
||||
# 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
|
||||
|
||||
* [@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
|
||||
@@ -102,12 +101,36 @@
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:cxx1y C++1y TS Concurrency - On going proposals]
|
||||
|
||||
[section:cxx1y C++14 TS Extensions for Concurrency V1 ]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4107.html N4107-Extensions for Concurrency]]
|
||||
|
||||
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[2.1] [ - ] [ - ] [ - ]]
|
||||
[[2.2] [Class template future] [Partial] [ - ]]
|
||||
[[2.2] [then] [ Partial ] [ without implicit unwrapping #10550 and blocking #10551 ]]
|
||||
[[2.2] [is_ready] [ Yes ] [ - ]]
|
||||
[[2.3] [Class template shared_future] [Partial] [ - ]]
|
||||
[[2.3] [then] [ Partial ] [ Without implicit unwrapping #10550 and blocking #10551 ]]
|
||||
[[2.3] [is_ready] [ Yes ] [ - ]]
|
||||
[[2.4] [Function template when_all] [Partial] [ interface not complete #10426 and blocking #10551 ]]
|
||||
[[2.5] [Function template when_any] [Partial] [ interface not complete #10427 and blocking #10551 ]]
|
||||
[[2.6] [Function template when_any_back] [No] [ #XXXX ]]
|
||||
[[2.7] [Function template make_ready_future] [Yes] [ - ]]
|
||||
]
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:cxx1y C++1z TS Concurrency - On going proposals]
|
||||
|
||||
[section:latch C++ Latches and Barriers]
|
||||
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html 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 +147,84 @@
|
||||
[[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]
|
||||
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3784.pdf N3784-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.]
|
||||
|
||||
[table Improvements to std::future<T> and related APIs]
|
||||
[table `async, future/shared_future::then`and Executors
|
||||
[[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.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.X] [Function template make_ready_future] [Yes] [ - ]]
|
||||
[[30.6.8] [Function template async ] [No] [ executor interface missing #7448 ]]
|
||||
[[30.6.6] [`future<T>::then`] [Yes] [ ]]
|
||||
[[30.6.7] [`shared_future<T>::then`] [Yes] [ ]]
|
||||
[[30.6.8] [`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 +234,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
|
||||
|
||||
1036
doc/future_ref.qbk
1036
doc/future_ref.qbk
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
|
||||
{
|
||||
|
||||
482
doc/parallel.qbk
Normal file
482
doc/parallel.qbk
Normal file
@@ -0,0 +1,482 @@
|
||||
[/
|
||||
/ Copyright (c) 2014 Vicente J. Botet Escriba
|
||||
/
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
/]
|
||||
|
||||
[//////////////////////////////////////////////////////////]
|
||||
[section:parallel Parallel - Fork-Join -- EXPERIMENTAL]
|
||||
|
||||
[section:fork_join Fork-Join]
|
||||
|
||||
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
|
||||
|
||||
[note These features are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4088.pdf [* n4088 - Task Region R3]] C++1y proposal from P. Halpern, A. Robison, A. Laksberg, H. Sutter, et al. The text that follows has been adapted from this paper to show the differences.]
|
||||
|
||||
The major difference respect to the standard proposal is that we are able to use a common executor for several task regions.
|
||||
|
||||
[note
|
||||
Up to now, Boost.Thread doesn't implement the parallel algorithms as defined in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4105.pdf [* n4105 - Information technology – Programming languages, their environments and system software interfaces – Technical Specification for C++ Extensions for Parallelism]].
|
||||
]
|
||||
|
||||
[////////////////////]
|
||||
[section Introduction]
|
||||
|
||||
|
||||
This module introduces a C++11/c++14 library function template `task_region` and a library class `task_region_handle`
|
||||
with member functions `run` and `wait` that together enable developers to write expressive and portable fork-join
|
||||
parallel code.
|
||||
|
||||
The working draft for the Parallelism TS [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4105.pdf [*N4105]] augments the STL algorithms with the inclusion of parallel execution policies. Programmers use these as a basis to write additional high-level algorithms that can be implemented in terms of the provided parallel algorithms. However, the scope of n4105 does not include lower-level mechanisms to express arbitrary fork-join parallelism
|
||||
|
||||
The `task_region`, `run` and the `wait` functions provided by this library are based on the `task_group` concept that is a part of the common subset of the PPL and the TBB libraries.
|
||||
|
||||
[endsect] [/ Introduction]
|
||||
|
||||
|
||||
[/////////////////////////]
|
||||
[section:tutorial Tutorial]
|
||||
|
||||
Consider an example of a parallel traversal of a tree, where a user-provided function compute is applied to each node of the tree, returning the sum of the results:
|
||||
|
||||
template<typename Func>
|
||||
int traverse(node *n, Func&& compute)
|
||||
{
|
||||
int left = 0, right = 0;
|
||||
task_region([&](task_region_handle& tr) {
|
||||
if (n->left)
|
||||
tr.run([&] { left = traverse(n->left, compute); });
|
||||
if (n->right)
|
||||
tr.run([&] { right = traverse(n->right, compute); });
|
||||
});
|
||||
return compute(n) + left + right;
|
||||
}
|
||||
|
||||
The example above demonstrates the use of two of the functions proposed in this paper, `task_region` and
|
||||
`task_region_handle::run`.
|
||||
The `task_region` function delineates a region in a program code potentially containing invocations of tasks
|
||||
spawned by the `run` member function of the `task_region_handle` class.
|
||||
|
||||
The run function spawns a task, a unit of work that is allowed to execute in parallel with respect to the caller.
|
||||
Any parallel tasks spawned by `run` within the `task_region` are joined back to a single thread of execution at
|
||||
the end of the `task_region`.
|
||||
|
||||
`run` takes a user-provided function object `f` and starts it asynchronously - i.e. it may return before the
|
||||
execution of `f` completes. The implementation's scheduler may choose to run `f` immediately or delay running
|
||||
`f` until compute resources become available.
|
||||
|
||||
A `task_region_handle` can be constructed only by `task_region` because it has no public constructors.
|
||||
Thus, `run` can be invoked (directly or indirectly) only from a user-provided function passed to `task_region`:
|
||||
|
||||
void g();
|
||||
void f(task_region_handle& tr)
|
||||
{
|
||||
tr.run(g); // OK, invoked from within task_region in h
|
||||
}
|
||||
void h()
|
||||
{
|
||||
task_region(f);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
task_region_handle tr; // Error: no public constructor
|
||||
tr.run(g); // No way to call run outside of a task_region
|
||||
return 0;
|
||||
}
|
||||
|
||||
[endsect] [/ Tutorial]
|
||||
|
||||
[////////////////]
|
||||
[section:examples Examples]
|
||||
|
||||
[section:fib Parallel Fibonacci]
|
||||
|
||||
|
||||
This is surely the worst implementation of the Fibonacci function. Anyway, here it is, as it is simple and shows the fork-join structure clearly. `Fibonacci(n) = Fibonacci(n-1) + Fibonacci(n-2)`, so the task decomposition is trivial.
|
||||
|
||||
int fib_task_region(int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region(i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
[endsect] [/ Fib]
|
||||
[section:fibex Parallel Fibonacci - Specific executor]
|
||||
|
||||
The previous example make use of an implementation defined way to spawn the tasks. Often the user wants to master how the task must be spawned. There is an overload of `task_region` that accept an additional `Executor` parameter and a function that takes as parameter a `task_region_handle_gen<Executor>`. `task_region_handle_gen<Executor>` run uses this executor to spawn the tasks.
|
||||
|
||||
template <class Ex>
|
||||
int fib_task_region_gen( Ex& ex, int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle_gen;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region(ex, [&](task_region_handle_gen<Ex>& trh) // (2)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::basic_thread_pool tp; // (1)
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region_gen(tp,i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
The specific executor is declared in line (1) and it is used in line (2).
|
||||
|
||||
[endsect] [/ Fib ex]
|
||||
|
||||
|
||||
|
||||
|
||||
[section:quick_sort Parallel Accumulate]
|
||||
|
||||
|
||||
[endsect] [/ Accumulate]
|
||||
|
||||
[section:quick_sort Parallel Quick Sort]
|
||||
|
||||
|
||||
|
||||
[endsect] [/ QuickSort]
|
||||
[endsect] [/ Examples]
|
||||
|
||||
|
||||
[////////////////////////]
|
||||
[section:rationale Design Rationale]
|
||||
|
||||
|
||||
[endsect] [/ Design Rationale]
|
||||
[endsect] [/ Fork-Join]
|
||||
|
||||
[/////////////////////]
|
||||
[section:ref Reference -- EXPERIMENTAL]
|
||||
|
||||
[/////////////////////////]
|
||||
[section:v1 Parallel V1]
|
||||
|
||||
[section:exception_list Header `<experimental/exception_list.hpp>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
|
||||
class exception_list;
|
||||
|
||||
} // v1
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[/////////////////////////]
|
||||
[section:exception_list Class `exception_list`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v1
|
||||
{
|
||||
|
||||
class exception_list: public std::exception
|
||||
{
|
||||
public:
|
||||
typedef 'implementation defined' const_iterator;
|
||||
|
||||
~exception_list() noexcept {}
|
||||
|
||||
void add(exception_ptr const& e);
|
||||
size_t size() const noexcept;
|
||||
const_iterator begin() const noexcept;
|
||||
const_iterator end() const noexcept;
|
||||
const char* what() const noexcept;
|
||||
|
||||
};
|
||||
|
||||
} // v1
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[endsect] [/ exception_list]
|
||||
|
||||
[endsect] [/ exception_list.hpp]
|
||||
|
||||
[endsect] [/ Parallel V1]
|
||||
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:v2 Parallel V2]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:concepts Concepts]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:regionCallable Concept `Region_Callable`]
|
||||
|
||||
[endsect] [/ Region_Callable]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:taskCallable Concept `Task_Callable`]
|
||||
|
||||
|
||||
[endsect] [/ Task_Callable]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[endsect] [/ Concepts]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region Header `<experimental/task_region.hpp>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_canceled_exception;
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen;
|
||||
|
||||
using default_executor = 'implementation defined';
|
||||
|
||||
class task_region_handle;
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region_final(F&& f);
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_canceled_exception Class `task_canceled_exception `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_canceled_exception: public std::exception
|
||||
{
|
||||
public:
|
||||
task_canceled_exception() noexcept;
|
||||
task_canceled_exception(const task_canceled_exception&) noexcept;
|
||||
task_canceled_exception& operator=(const task_canceled_exception&) noexcept;
|
||||
virtual const char* what() const noexcept;
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_canceled_exception]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_handle_gen Template Class `task_region_handle_gen<>`]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <class Executor>
|
||||
class task_region_handle_gen
|
||||
{
|
||||
protected:
|
||||
task_region_handle_gen(Executor& ex);
|
||||
|
||||
~task_region_handle_gen();
|
||||
|
||||
public:
|
||||
task_region_handle_gen(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen& operator=(const task_region_handle_gen&) = delete;
|
||||
task_region_handle_gen* operator&() const = delete;
|
||||
|
||||
template<typename F>
|
||||
void run(F&& f);
|
||||
|
||||
void wait();
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_handle_gen]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:default_executor Class `default_executor `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
using default_executor = 'implementation defined';
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ default_executor]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_handle Class `task_region_handle `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
class task_region_handle :
|
||||
public task_region_handle_gen<default_executor>
|
||||
{
|
||||
protected:
|
||||
task_region_handle();
|
||||
task_region_handle(const task_region_handle&) = delete;
|
||||
task_region_handle& operator=(const task_region_handle&) = delete;
|
||||
task_region_handle* operator&() const = delete;
|
||||
|
||||
};
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_handle]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region_final Template Function `task_region_final `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region_final(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region_final(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region_final]
|
||||
[////////////////////////////////////////////////////////////////////]
|
||||
[section:task_region Template Function `task_region `]
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace experimental
|
||||
{
|
||||
namespace parallel
|
||||
{
|
||||
inline namespace v2
|
||||
{
|
||||
|
||||
template <typename Executor, typename F>
|
||||
void task_region(Executor& ex, F&& f);
|
||||
template <typename F>
|
||||
void task_region(F&& f);
|
||||
|
||||
} // v2
|
||||
} // parallel
|
||||
} // experimental
|
||||
} // boost
|
||||
|
||||
[endsect] [/ task_region]
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect] [/ task_region.hpp]
|
||||
[endsect] [/ Parallel V2]
|
||||
[endsect] [/ Reference]
|
||||
|
||||
[endsect] [/ Parallel]
|
||||
@@ -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;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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.4.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,20 +239,21 @@
|
||||
[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]
|
||||
|
||||
|
||||
[include tss.qbk]
|
||||
|
||||
[section:sds Synchronized Data Structures]
|
||||
[include synchronized_value.qbk]
|
||||
[/include sync_queues_ref.qbk]
|
||||
[include sync_queues_ref.qbk]
|
||||
[/include sync_streams.qbk]
|
||||
[endsect]
|
||||
|
||||
[include parallel.qbk]
|
||||
|
||||
[include time.qbk]
|
||||
|
||||
[include emulations.qbk]
|
||||
|
||||
@@ -26,7 +26,13 @@
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
|
||||
namespace no_interruption_point // EXTENSION
|
||||
{
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
}
|
||||
template<typename Callable>
|
||||
void at_thread_exit(Callable func); // EXTENSION
|
||||
|
||||
@@ -470,6 +476,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 +539,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 +565,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 +592,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 +620,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 +647,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 +676,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 +703,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.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -768,7 +758,7 @@ corresponding successful `join()` return. ]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or `this->get_id() == boost::this_thread::get_id()`.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED` is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED` is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -794,8 +784,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.
|
||||
]
|
||||
|
||||
@@ -819,7 +807,7 @@ unchanged.]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -859,7 +847,7 @@ unchanged.]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -899,7 +887,7 @@ unchanged.]]
|
||||
|
||||
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
|
||||
[/
|
||||
@@ -935,7 +923,7 @@ unchanged.]]
|
||||
|
||||
[*no_such_process]: if the thread is not valid.
|
||||
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined.
|
||||
|
||||
]]
|
||||
|
||||
@@ -991,6 +979,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 +1017,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 +1037,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 +1055,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 +1078,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 +1469,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.
|
||||
]
|
||||
|
||||
@@ -1502,6 +1495,11 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
{
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
namespace no_interruption_point
|
||||
{
|
||||
template <class Clock, class Duration>
|
||||
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
|
||||
}
|
||||
}
|
||||
|
||||
[variablelist
|
||||
@@ -1513,6 +1511,7 @@ specified by `rel_time` has elapsed or the time point specified by
|
||||
do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted. ]]
|
||||
|
||||
[[Notes:] [`sleep_until()` is one of the predefined __interruption_points__.]]
|
||||
[[Notes:] [`no_interruption_point::sleep_until()` is NOT one of the __interruption_points__.]]
|
||||
|
||||
]
|
||||
|
||||
@@ -1526,6 +1525,11 @@ do not throw exceptions. __thread_interrupted__ if the current thread of executi
|
||||
{
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
namespace no_interruption_point
|
||||
{
|
||||
template <class Rep, class Period>
|
||||
void sleep_for(const chrono::duration<Rep, Period>& rel_time);
|
||||
}
|
||||
}
|
||||
|
||||
[variablelist
|
||||
@@ -1536,6 +1540,7 @@ by `rel_time` has elapsed.]]
|
||||
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted.]]
|
||||
|
||||
[[Notes:] [`sleep_for()` is one of the predefined __interruption_points__.]]
|
||||
[[Notes:] [`no_interruption_point:: sleep_for()` is NOT one of the __interruption_points__.]]
|
||||
|
||||
]
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
150
example/executor.cpp
Normal file
150
example/executor.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// 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
|
||||
|
||||
#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 test_executor_adaptor()
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
return test_executor_adaptor();
|
||||
}
|
||||
91
example/fib_task_region.cpp
Normal file
91
example/fib_task_region.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
// Copyright (C) 2012 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
|
||||
#include <boost/thread/experimental/task_region.hpp>
|
||||
#include <iostream>
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR && ! defined BOOST_NO_CXX11_LAMBDAS
|
||||
|
||||
int fib_task_region(int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region([&](task_region_handle& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
template <class Ex>
|
||||
int fib_task_region_gen( Ex& ex, int n)
|
||||
{
|
||||
using boost::experimental::parallel::task_region;
|
||||
using boost::experimental::parallel::task_region_handle_gen;
|
||||
|
||||
if (n == 0) return 0;
|
||||
if (n == 1) return 1;
|
||||
|
||||
int n1;
|
||||
int n2;
|
||||
|
||||
task_region(ex, [&](task_region_handle_gen<Ex>& trh)
|
||||
{
|
||||
trh.run([&]
|
||||
{
|
||||
n1 = fib_task_region(n - 1);
|
||||
});
|
||||
|
||||
n2 = fib_task_region(n - 2);
|
||||
});
|
||||
|
||||
return n1 + n2;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region(i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
|
||||
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
boost::basic_thread_pool tp;
|
||||
for (int i = 0; i<10; ++i) {
|
||||
std::cout << fib_task_region_gen(tp,i) << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
103
example/future_fallback_to.cpp
Normal file
103
example/future_fallback_to.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
// 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
|
||||
|
||||
#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,14 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_USES_LOG
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
@@ -19,15 +25,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);
|
||||
}
|
||||
@@ -37,26 +44,81 @@ int p2(boost::future<int>& f)
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
70
example/future_unwrap.cpp
Normal file
70
example/future_unwrap.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
// 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
|
||||
|
||||
#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
|
||||
323
example/future_when_all.cpp
Normal file
323
example/future_when_all.cpp
Normal file
@@ -0,0 +1,323 @@
|
||||
// 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
|
||||
|
||||
|
||||
#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_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::tuple<> > all0 = boost::when_all();
|
||||
BOOST_THREAD_LOG
|
||||
<< BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_all(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_all(boost::move(f1));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::make_ready_future(1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_all(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<std::string> f2 = boost::make_ready_future(std::string("nnnnnnn"));;
|
||||
boost::future<boost::csbl::tuple<boost::future<int>, boost::future<std::string> > > all = boost::when_all(boost::move(f1), boost::move(f2));
|
||||
//(void) all.wait();
|
||||
boost::csbl::tuple<boost::future<int>, boost::future<std::string> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::vector<boost::future<int> > v;
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1b));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_all(v.begin(), v.end());
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
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_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::tuple<> > all0 = boost::when_any();
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_any(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
boost::future<boost::csbl::tuple<boost::future<int> > > all = boost::when_any(boost::move(f1));
|
||||
boost::csbl::tuple<boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::make_ready_future(1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<std::string> f1 = boost::make_ready_future(std::string("aaaa"));
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<std::string>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<std::string>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f2 = boost::make_ready_future(1);
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
|
||||
boost::future<int> f2 = boost::async(boost::launch::deferred, &p1b);
|
||||
boost::future<boost::csbl::tuple<boost::future<int>,boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
|
||||
boost::csbl::tuple<boost::future<int>,boost::future<int> > res = all.get();
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<0>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
BOOST_THREAD_LOG
|
||||
<< boost::csbl::get<1>(res).get() <<" " << BOOST_THREAD_END_LOG;
|
||||
}
|
||||
#endif
|
||||
{
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::csbl::vector<boost::future<int> > v;
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
v.push_back(boost::async(boost::launch::async, &p1b));
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_any(v.begin(), v.end());
|
||||
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
|
||||
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
|
||||
) {
|
||||
}
|
||||
int main()
|
||||
{
|
||||
boost::csbl::vector<future<int> > vec;
|
||||
f(vec, make_ready_future(0));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
153
example/generic_executor_ref.cpp
Normal file
153
example/generic_executor_ref.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_PROVIDES_EXECUTORS
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
|
||||
#include <boost/thread/caller_context.hpp>
|
||||
#include <boost/thread/executors/basic_thread_pool.hpp>
|
||||
#include <boost/thread/executors/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::generic_executor_ref 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 test_generic_executor_ref()
|
||||
{
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
try
|
||||
{
|
||||
{
|
||||
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::loop_executor ea2;
|
||||
submit_some( ea2);
|
||||
ea2.run_queued_closures();
|
||||
}
|
||||
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::basic_thread_pool ea1(4);
|
||||
boost::serial_executor ea2(ea1);
|
||||
submit_some(ea2);
|
||||
}
|
||||
#endif
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
boost::inline_executor ea1;
|
||||
submit_some(ea1);
|
||||
}
|
||||
// std::cout << BOOST_CONTEXTOF << std::endl;
|
||||
{
|
||||
//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;
|
||||
}
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
return test_generic_executor_ref();
|
||||
|
||||
|
||||
}
|
||||
@@ -8,22 +8,27 @@
|
||||
#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
|
||||
#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 +38,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;
|
||||
}
|
||||
|
||||
102
example/parallel_accumulate.cpp
Normal file
102
example/parallel_accumulate.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright (C) 2014 Vicente Botet
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#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
|
||||
110
example/parallel_quick_sort.cpp
Normal file
110
example/parallel_quick_sort.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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>
|
||||
|
||||
#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>
|
||||
#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;
|
||||
|
||||
@@ -6,22 +6,33 @@
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#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 +46,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 +71,36 @@ 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));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer3(the_ostream &mos, boost::sync_queue<int> & sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status res = sbq.wait_pull_front(r);
|
||||
if (res==queue_op_status::closed) break;
|
||||
mos << i << " wait_pull_front(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
@@ -76,43 +109,30 @@ 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)
|
||||
//{
|
||||
// using namespace boost;
|
||||
// bool closed=false;
|
||||
// try {
|
||||
// for(int i=0; ;++i)
|
||||
// {
|
||||
// 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";
|
||||
// this_thread::sleep_for(chrono::milliseconds(250));
|
||||
// }
|
||||
// }
|
||||
// catch(...)
|
||||
// {
|
||||
// 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_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));
|
||||
|
||||
|
||||
150
example/producer_consumer2.cpp
Normal file
150
example/producer_consumer2.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
// (C) Copyright 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)
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#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>
|
||||
#include <boost/thread/concurrent_queues/queue_adaptor.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_views.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits.hpp>
|
||||
|
||||
void producer(the_ostream &mos, boost::queue_back<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
sbq.push(i);
|
||||
//sbq << i;
|
||||
mos << "push(" << i << ") " << sbq.size() <<"\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(200));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
|
||||
void consumer(
|
||||
the_ostream &mos,
|
||||
boost::queue_front<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";
|
||||
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(sync_queue_is_closed&)
|
||||
{
|
||||
mos << "closed !!!\n";
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer2(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status st = sbq.try_pull(r);
|
||||
if (queue_op_status::closed == st) break;
|
||||
if (queue_op_status::success == st) {
|
||||
mos << i << " try_pull(" << r << ")\n";
|
||||
}
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
mos << "exception !!!\n";
|
||||
}
|
||||
}
|
||||
void consumer3(the_ostream &mos, boost::queue_front<int> sbq)
|
||||
{
|
||||
using namespace boost;
|
||||
try {
|
||||
for(int i=0; ;++i)
|
||||
{
|
||||
int r;
|
||||
queue_op_status res = sbq.wait_pull(r);
|
||||
if (res==queue_op_status::closed) break;
|
||||
mos << i << " wait_pull(" << r << ")\n";
|
||||
this_thread::sleep_for(chrono::milliseconds(250));
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
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
|
||||
|
||||
queue_adaptor<sync_queue<int> > sbq;
|
||||
|
||||
{
|
||||
mcout << "begin of main" << std::endl;
|
||||
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), concurrent::queue_back<int>(sbq)));
|
||||
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), concurrent::queue_back<int>(sbq)));
|
||||
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), concurrent::queue_front<int>(sbq)));
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
mcout << "closed()" << std::endl;
|
||||
sbq.close();
|
||||
mcout << "closed()" << std::endl;
|
||||
|
||||
} // all threads joined here.
|
||||
mcout << "end of main" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,77 +6,92 @@
|
||||
|
||||
// adapted from the example given by Howard Hinnant in
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
#define BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
//#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 +101,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>
|
||||
|
||||
73
example/thread_pool.cpp
Normal file
73
example/thread_pool.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>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#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/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;
|
||||
}
|
||||
75
example/user_scheduler.cpp
Normal file
75
example/user_scheduler.cpp
Normal file
@@ -0,0 +1,75 @@
|
||||
// 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)
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#define BOOST_THREAD_VERSION 4
|
||||
//#define BOOST_THREAD_USES_LOG
|
||||
#define BOOST_THREAD_USES_LOG_THREAD_ID
|
||||
#if ! defined BOOST_NO_CXX11_DECLTYPE
|
||||
#define BOOST_RESULT_OF_USE_DECLTYPE
|
||||
#endif
|
||||
#include <boost/thread/detail/log.hpp>
|
||||
#include <boost/thread/executors/loop_executor.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/thread/thread_only.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,236 @@
|
||||
#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)
|
||||
//BOOST_THREAD_COPYABLE_AND_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)
|
||||
//BOOST_THREAD_COPYABLE_AND_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_)
|
||||
//size_(BOOST_THREAD_RV(other).size_), fct_(boost::move(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)
|
||||
//BOOST_THREAD_COPYABLE_AND_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_;
|
||||
}
|
||||
};
|
||||
}
|
||||
//BOOST_THREAD_DCL_MOVABLE(thread_detail::default_barrier_reseter)
|
||||
//BOOST_THREAD_DCL_MOVABLE(thread_detail::void_functor_barrier_reseter)
|
||||
//BOOST_THREAD_DCL_MOVABLE(thread_detail::void_fct_ptr_barrier_reseter)
|
||||
|
||||
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()
|
||||
{
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_DETAIL_SYNC_QUEUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
class sync_queue_base
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef Queue underlying_queue_type;
|
||||
typedef std::size_t size_type;
|
||||
typedef queue_op_status op_status;
|
||||
|
||||
typedef typename chrono::steady_clock clock;
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue_base)
|
||||
inline sync_queue_base();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue_base();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
inline underlying_queue_type underlying_queue() {
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return boost::move(data_);
|
||||
}
|
||||
|
||||
protected:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
underlying_queue_type data_;
|
||||
bool closed_;
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.empty();
|
||||
}
|
||||
|
||||
inline size_type size(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return data_.size();
|
||||
}
|
||||
inline bool closed(unique_lock<mutex>& lk) const;
|
||||
inline bool closed(lock_guard<mutex>& lk) const;
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline void throw_if_closed(lock_guard<mutex>&);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline bool wait_until_not_empty_or_closed(unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&);
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
inline void notify_not_empty_if_needed(lock_guard<mutex>& )
|
||||
{
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_queue_base<ValueType, Queue>::sync_queue_base() :
|
||||
data_(), closed_(false)
|
||||
{
|
||||
BOOST_ASSERT(data_.empty());
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
sync_queue_base<ValueType, Queue>::~sync_queue_base()
|
||||
{
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed(unique_lock<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::closed(lock_guard<mutex>&) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::full() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
typename sync_queue_base<ValueType, Queue>::size_type sync_queue_base<ValueType, Queue>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::throw_if_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::throw_if_closed(lock_guard<mutex>& lk)
|
||||
{
|
||||
if (closed(lk))
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
void sync_queue_base<ValueType, Queue>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
throw_if_closed(lk);
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <class ValueType, class Queue>
|
||||
bool sync_queue_base<ValueType, Queue>::wait_until_not_empty_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) break;
|
||||
if (closed(lk)) return true;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <class ValueType, class Queue>
|
||||
queue_op_status sync_queue_base<ValueType, Queue>::wait_until_not_empty_until(unique_lock<mutex>& lk, time_point const&tp)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (! empty(lk)) return queue_op_status::success;
|
||||
throw_if_closed(lk);
|
||||
if (not_empty_.wait_until(lk, tp) == cv_status::timeout ) return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // detail
|
||||
} // concurrent
|
||||
} // boost
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
209
include/boost/thread/concurrent_queues/queue_adaptor.hpp
Normal file
209
include/boost/thread/concurrent_queues/queue_adaptor.hpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_ADAPTOR_HPP
|
||||
#define BOOST_THREAD_QUEUE_ADAPTOR_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_base.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor_copyable_only :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_adaptor_copyable_only() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
};
|
||||
template <typename Queue>
|
||||
class queue_adaptor_movable_only :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
queue_adaptor_movable_only() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor_copyable_and_movable :
|
||||
public boost::queue_base<typename Queue::value_type>
|
||||
{
|
||||
Queue queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
|
||||
queue_adaptor_copyable_and_movable() {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue.empty(); }
|
||||
bool full() const { return queue.full(); }
|
||||
size_type size() const { return queue.size(); }
|
||||
bool closed() const { return queue.closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue.close(); }
|
||||
|
||||
|
||||
void push_back(const value_type& x) { queue.push_back(x); }
|
||||
|
||||
void pull_front(value_type& x) { queue.pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull_front() { return queue.pull_front(); }
|
||||
|
||||
queue_op_status try_push_back(const value_type& x) { return queue.try_push_back(x); }
|
||||
queue_op_status try_pull_front(value_type& x) { return queue.try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push_back(const value_type& x) { return queue.nonblocking_push_back(x); }
|
||||
queue_op_status nonblocking_pull_front(value_type& x) { return queue.nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push_back(const value_type& x) { return queue.wait_push_back(x); }
|
||||
queue_op_status wait_pull_front(value_type& x) { return queue.wait_pull_front(x); }
|
||||
|
||||
void push_back(BOOST_THREAD_RV_REF(value_type) x) { queue.push_back(boost::move(x)); }
|
||||
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) { return queue.wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
|
||||
template <class Q, class T,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // __GNUC__
|
||||
#elif defined _MSC_VER
|
||||
#if _MSC_VER < 1700
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif
|
||||
#else
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = has_move_emulation_enabled<T>::value
|
||||
#endif
|
||||
>
|
||||
struct queue_adaptor;
|
||||
|
||||
template <class Q, class T>
|
||||
struct queue_adaptor<Q, T, true, true> {
|
||||
typedef queue_adaptor_copyable_and_movable<Q> type;
|
||||
};
|
||||
template <class Q, class T>
|
||||
struct queue_adaptor<Q, T, true, false> {
|
||||
typedef queue_adaptor_copyable_only<Q> type;
|
||||
};
|
||||
template <class Q, class T>
|
||||
struct queue_adaptor<Q, T, false, true> {
|
||||
typedef queue_adaptor_movable_only<Q> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename Queue>
|
||||
class queue_adaptor :
|
||||
public detail::queue_adaptor<Queue, typename Queue::value_type>::type
|
||||
{
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_adaptor() {};
|
||||
};
|
||||
}
|
||||
using concurrent::queue_adaptor;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
202
include/boost/thread/concurrent_queues/queue_base.hpp
Executable file
202
include/boost/thread/concurrent_queues/queue_base.hpp
Executable file
@@ -0,0 +1,202 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_BASE_HPP
|
||||
#define BOOST_THREAD_QUEUE_BASE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/type_traits/conditional.hpp>
|
||||
#include <boost/type_traits/is_copy_constructible.hpp>
|
||||
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base_copyable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_copyable_only() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base_movable_only
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_movable_only() {};
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
// enable_if is_nothrow_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base_copyable_and_movable
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base_copyable_and_movable() {};
|
||||
|
||||
|
||||
// Observers
|
||||
virtual bool empty() const = 0;
|
||||
virtual bool full() const = 0;
|
||||
virtual size_type size() const = 0;
|
||||
virtual bool closed() const = 0;
|
||||
|
||||
// Modifiers
|
||||
virtual void close() = 0;
|
||||
|
||||
virtual void push_back(const value_type& x) = 0;
|
||||
|
||||
virtual void pull_front(value_type&) = 0;
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
virtual value_type pull_front() = 0;
|
||||
|
||||
virtual queue_op_status try_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status try_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status nonblocking_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status nonblocking_pull_front(value_type&) = 0;
|
||||
|
||||
virtual queue_op_status wait_push_back(const value_type& x) = 0;
|
||||
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
|
||||
|
||||
virtual void push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
virtual queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
|
||||
};
|
||||
|
||||
template <class T,
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#if defined __GNUC__
|
||||
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5) || !defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // __GNUC__
|
||||
#elif defined _MSC_VER
|
||||
#if _MSC_VER < 1700
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = true
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif // _MSC_VER
|
||||
#else
|
||||
bool Copyable = std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
|
||||
bool Movable = std::is_move_constructible<T>::value && std::is_move_assignable<T>::value
|
||||
#endif
|
||||
#else
|
||||
bool Copyable = is_copy_constructible<T>::value,
|
||||
bool Movable = has_move_emulation_enabled<T>::value
|
||||
#endif
|
||||
>
|
||||
struct queue_base;
|
||||
|
||||
template <class T>
|
||||
struct queue_base<T, true, true> {
|
||||
typedef queue_base_copyable_and_movable<T> type;
|
||||
};
|
||||
template <class T>
|
||||
struct queue_base<T, true, false> {
|
||||
typedef queue_base_copyable_only<T> type;
|
||||
};
|
||||
template <class T>
|
||||
struct queue_base<T, false, true> {
|
||||
typedef queue_base_movable_only<T> type;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
class queue_base :
|
||||
public detail::queue_base<ValueType>::type
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
// Constructors/Assignment/Destructors
|
||||
virtual ~queue_base() {};
|
||||
};
|
||||
|
||||
}
|
||||
using concurrent::queue_base;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
46
include/boost/thread/concurrent_queues/queue_op_status.hpp
Normal file
46
include/boost/thread/concurrent_queues/queue_op_status.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_OP_STATUS_HPP
|
||||
#define BOOST_THREAD_QUEUE_OP_STATUS_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
|
||||
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
|
||||
{ success = 0, empty, full, closed, busy, timeout, not_ready }
|
||||
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
|
||||
|
||||
struct sync_queue_is_closed : std::exception
|
||||
{
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
struct no_block_tag{};
|
||||
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
|
||||
#endif
|
||||
|
||||
using concurrent::queue_op_status;
|
||||
using concurrent::sync_queue_is_closed;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
165
include/boost/thread/concurrent_queues/queue_views.hpp
Normal file
165
include/boost/thread/concurrent_queues/queue_views.hpp
Normal file
@@ -0,0 +1,165 @@
|
||||
#ifndef BOOST_THREAD_QUEUE_VIEWS_HPP
|
||||
#define BOOST_THREAD_QUEUE_VIEWS_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_base.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
|
||||
template <typename Queue>
|
||||
class queue_back_view
|
||||
{
|
||||
Queue* queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_back_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue->empty(); }
|
||||
bool full() const { return queue->full(); }
|
||||
size_type size() const { return queue->size(); }
|
||||
bool closed() const { return queue->closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_back(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_back(x); }
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_back(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_back(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_back(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_back(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_back(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_back(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_back(x); }
|
||||
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_back(boost::move(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_back(boost::move(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_back(boost::move(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_back(boost::move(x)); }
|
||||
};
|
||||
|
||||
template <typename Queue>
|
||||
class queue_front_view
|
||||
{
|
||||
Queue* queue;
|
||||
public:
|
||||
typedef typename Queue::value_type value_type;
|
||||
typedef typename Queue::size_type size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
queue_front_view(Queue& q) BOOST_NOEXCEPT : queue(&q) {}
|
||||
|
||||
// Observers
|
||||
bool empty() const { return queue->empty(); }
|
||||
bool full() const { return queue->full(); }
|
||||
size_type size() const { return queue->size(); }
|
||||
bool closed() const { return queue->closed(); }
|
||||
|
||||
// Modifiers
|
||||
void close() { queue->close(); }
|
||||
|
||||
void push(const value_type& x) { queue->push_front(x); }
|
||||
|
||||
void pull(value_type& x) { queue->pull_front(x); };
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
value_type pull() { return queue->pull_front(); }
|
||||
|
||||
queue_op_status try_push(const value_type& x) { return queue->try_push_front(x); }
|
||||
|
||||
queue_op_status try_pull(value_type& x) { return queue->try_pull_front(x); }
|
||||
|
||||
queue_op_status nonblocking_push(const value_type& x) { return queue->nonblocking_push_front(x); }
|
||||
|
||||
queue_op_status nonblocking_pull(value_type& x) { return queue->nonblocking_pull_front(x); }
|
||||
|
||||
queue_op_status wait_push(const value_type& x) { return queue->wait_push_front(x); }
|
||||
queue_op_status wait_pull(value_type& x) { return queue->wait_pull_front(x); }
|
||||
void push(BOOST_THREAD_RV_REF(value_type) x) { queue->push_front(forward<value_type>(x)); }
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->try_push_front(forward<value_type>(x)); }
|
||||
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->nonblocking_push_front(forward<value_type>(x)); }
|
||||
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x) { return queue->wait_push_front(forward<value_type>(x)); }
|
||||
|
||||
};
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_TEMPLATE_ALIASES
|
||||
|
||||
template <class T>
|
||||
using queue_back = queue_back_view<queue_base<T> > ;
|
||||
template <class T>
|
||||
using queue_front = queue_front_view<queue_base<T> > ;
|
||||
|
||||
#else
|
||||
|
||||
template <class T>
|
||||
struct queue_back : queue_back_view<queue_base<T> >
|
||||
{
|
||||
typedef queue_back_view<queue_base<T> > base_type;
|
||||
queue_back(queue_base<T>& q) BOOST_NOEXCEPT : base_type(q) {}
|
||||
};
|
||||
template <class T>
|
||||
struct queue_front : queue_front_view<queue_base<T> >
|
||||
{
|
||||
typedef queue_front_view<queue_base<T> > base_type;
|
||||
queue_front(queue_base<T>& q) BOOST_NOEXCEPT : base_type(q) {}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
// template <class Queue>
|
||||
// queue_back_view<Queue> back(Queue & q) { return queue_back_view<Queue>(q); }
|
||||
// template <class Queue>
|
||||
// queue_front_view<Queue> front(Queue & q) { return queue_front_view<Queue>(q); }
|
||||
//#if 0
|
||||
// template <class T>
|
||||
// queue_back<T> back(queue_base<T> & q) { return queue_back<T>(q); }
|
||||
// template <class T>
|
||||
// queue_front<T> front(queue_base<T> & q) { return queue_front<T>(q); }
|
||||
//#else
|
||||
// template <class T>
|
||||
// typename queue_back<T>::type back(queue_base<T> & q) { return typename queue_back<T>::type(q); }
|
||||
// template <class T>
|
||||
// typename queue_front<T>::type front(queue_base<T> & q) { return typename queue_front<T>::type(q); }
|
||||
//#endif
|
||||
}
|
||||
|
||||
using concurrent::queue_back_view;
|
||||
using concurrent::queue_front_view;
|
||||
using concurrent::queue_back;
|
||||
using concurrent::queue_front;
|
||||
//using concurrent::back;
|
||||
//using concurrent::front;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
725
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
725
include/boost/thread/concurrent_queues/sync_bounded_queue.hpp
Normal file
@@ -0,0 +1,725 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_BOUNDED_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
#endif
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_bounded_queue
|
||||
{
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
typedef std::size_t size_type;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_bounded_queue)
|
||||
explicit sync_bounded_queue(size_type max_elems);
|
||||
template <typename Range>
|
||||
sync_bounded_queue(size_type max_elems, Range range);
|
||||
~sync_bounded_queue();
|
||||
|
||||
// Observers
|
||||
inline bool empty() const;
|
||||
inline bool full() const;
|
||||
inline size_type capacity() const;
|
||||
inline size_type size() const;
|
||||
inline bool closed() const;
|
||||
|
||||
// Modifiers
|
||||
inline void close();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline bool try_push(no_block_tag, BOOST_THREAD_RV_REF(value_type) x);
|
||||
#endif
|
||||
inline void push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
inline queue_op_status try_pull_front(value_type&);
|
||||
inline queue_op_status nonblocking_pull_front(value_type&);
|
||||
|
||||
inline queue_op_status wait_pull_front(ValueType& elem);
|
||||
|
||||
private:
|
||||
mutable mutex mtx_;
|
||||
condition_variable not_empty_;
|
||||
condition_variable not_full_;
|
||||
size_type waiting_full_;
|
||||
size_type waiting_empty_;
|
||||
value_type* data_;
|
||||
size_type in_;
|
||||
size_type out_;
|
||||
size_type capacity_;
|
||||
bool closed_;
|
||||
|
||||
inline size_type inc(size_type idx) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (idx + 1) % capacity_;
|
||||
}
|
||||
|
||||
inline bool empty(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool empty(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return in_ == out_;
|
||||
}
|
||||
inline bool full(unique_lock<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline bool full(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return (inc(in_) == out_);
|
||||
}
|
||||
inline size_type capacity(lock_guard<mutex>& ) const BOOST_NOEXCEPT
|
||||
{
|
||||
return capacity_-1;
|
||||
}
|
||||
inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT
|
||||
{
|
||||
if (full(lk)) return capacity(lk);
|
||||
return ((out_+capacity(lk)-in_) % capacity(lk));
|
||||
}
|
||||
|
||||
inline void throw_if_closed(unique_lock<mutex>&);
|
||||
inline bool closed(unique_lock<mutex>&) const;
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, unique_lock<mutex>& lk);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
inline bool try_push(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk);
|
||||
inline void wait_until_not_empty(unique_lock<mutex>& lk, bool&);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk);
|
||||
inline size_type wait_until_not_full(unique_lock<mutex>& lk, bool&);
|
||||
|
||||
|
||||
inline void notify_not_empty_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_empty_ > 0)
|
||||
{
|
||||
--waiting_empty_;
|
||||
lk.unlock();
|
||||
not_empty_.notify_one();
|
||||
}
|
||||
}
|
||||
inline void notify_not_full_if_needed(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (waiting_full_ > 0)
|
||||
{
|
||||
--waiting_full_;
|
||||
lk.unlock();
|
||||
not_full_.notify_one();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(data_[out_]));
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& lk)
|
||||
{
|
||||
value_type elem = boost::move(data_[out_]);
|
||||
out_ = inc(out_);
|
||||
notify_not_full_if_needed(lk);
|
||||
return boost::move(elem);
|
||||
}
|
||||
|
||||
inline void set_in(size_type in, unique_lock<mutex>& lk)
|
||||
{
|
||||
in_ = in;
|
||||
notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_at(const value_type& elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = elem;
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
|
||||
inline void push_at(BOOST_THREAD_RV_REF(value_type) elem, size_type in_p_1, unique_lock<mutex>& lk)
|
||||
{
|
||||
data_[in_] = boost::move(elem);
|
||||
set_in(in_p_1, lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::sync_bounded_queue(typename sync_bounded_queue<ValueType>::size_type max_elems) :
|
||||
waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
closed_(false)
|
||||
{
|
||||
BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// sync_bounded_queue<ValueType>::sync_bounded_queue(size_type max_elems, Range range) :
|
||||
// waiting_full_(0), waiting_empty_(0), data_(new value_type[max_elems + 1]), in_(0), out_(0), capacity_(max_elems + 1),
|
||||
// closed_(false)
|
||||
// {
|
||||
// BOOST_ASSERT_MSG(max_elems >= 1, "number of elements must be > 1");
|
||||
// BOOST_ASSERT_MSG(max_elems == size(range), "number of elements must match range's size");
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// size_type in = 0;
|
||||
// for (iterator_t cur = first; cur != end; ++cur, ++in)
|
||||
// {
|
||||
// data_[in] = *cur;
|
||||
// }
|
||||
// set_in(in);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>::~sync_bounded_queue()
|
||||
{
|
||||
delete[] data_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::close()
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
not_empty_.notify_all();
|
||||
not_full_.notify_all();
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed_;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::closed(unique_lock<mutex>& ) const
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::empty() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return empty(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::full() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return full(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::capacity() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return capacity(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::size() const
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return size(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk))
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
|
||||
{
|
||||
if (closed_)
|
||||
{
|
||||
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
throw_if_closed(lk);
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (out_ != in_) break;
|
||||
if (closed_) {closed=true; return;}
|
||||
++waiting_empty_;
|
||||
not_empty_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
// template <typename ValueType>
|
||||
// void sync_bounded_queue<ValueType>::pull(ValueType& elem, bool & closed)
|
||||
// {
|
||||
// unique_lock<mutex> lk(mtx_);
|
||||
// wait_until_not_empty(lk, closed);
|
||||
// if (closed) {return;}
|
||||
// pull(elem, lk);
|
||||
// }
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_bounded_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_bounded_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
|
||||
wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(elem, in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
typename sync_bounded_queue<ValueType>::size_type sync_bounded_queue<ValueType>::wait_until_not_full(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 != out_) // ! full()
|
||||
{
|
||||
return in_p_1;
|
||||
}
|
||||
++waiting_full_;
|
||||
not_full_.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(elem, wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
throw_if_closed(lk);
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
size_type in_p_1 = inc(in_);
|
||||
if (in_p_1 == out_) // full()
|
||||
{
|
||||
return queue_op_status::full;
|
||||
}
|
||||
push_at(boost::move(elem), in_p_1, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (closed(lk)) return queue_op_status::closed;
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_bounded_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_bounded_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
void sync_bounded_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(mtx_);
|
||||
push_at(boost::move(elem), wait_until_not_full(lk), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
}
|
||||
using concurrent::sync_bounded_queue;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
362
include/boost/thread/concurrent_queues/sync_priority_queue.hpp
Normal file
362
include/boost/thread/concurrent_queues/sync_priority_queue.hpp
Normal file
@@ -0,0 +1,362 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_SYNC_PRIORITY_QUEUE
|
||||
#define BOOST_THREAD_SYNC_PRIORITY_QUEUE
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/vector.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
|
||||
#include <exception>
|
||||
#include <queue>
|
||||
#include <utility>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail {
|
||||
|
||||
template <
|
||||
class Type,
|
||||
class Container = csbl::vector<Type>,
|
||||
class Compare = std::less<Type>
|
||||
>
|
||||
class priority_queue
|
||||
{
|
||||
private:
|
||||
std::vector<Type> _elements;
|
||||
Compare _compare;
|
||||
public:
|
||||
explicit priority_queue(const Compare& compare = Compare())
|
||||
: _elements(), _compare(compare)
|
||||
{ }
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return _elements.size();
|
||||
}
|
||||
|
||||
bool empty() const
|
||||
{
|
||||
return _elements.empty();
|
||||
}
|
||||
|
||||
void push(Type const& element)
|
||||
{
|
||||
_elements.push_back(element);
|
||||
std::push_heap(_elements.begin(), _elements.end(), _compare);
|
||||
}
|
||||
void push(BOOST_RV_REF(Type) element)
|
||||
{
|
||||
_elements.push_back(boost::move(element));
|
||||
std::push_heap(_elements.begin(), _elements.end(), _compare);
|
||||
}
|
||||
|
||||
Type pull()
|
||||
{
|
||||
std::pop_heap(_elements.begin(), _elements.end(), _compare);
|
||||
Type result = boost::move(_elements.back());
|
||||
_elements.pop_back();
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
Type const& top()
|
||||
{
|
||||
return _elements.back();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace concurrent
|
||||
{
|
||||
template <class ValueType,
|
||||
class Container = csbl::vector<ValueType>,
|
||||
class Compare = std::less<typename Container::value_type> >
|
||||
class sync_priority_queue
|
||||
: public detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, boost::detail::priority_queue<ValueType,Container,Compare> > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
typedef chrono::steady_clock clock;
|
||||
protected:
|
||||
|
||||
public:
|
||||
sync_priority_queue() {}
|
||||
|
||||
~sync_priority_queue()
|
||||
{
|
||||
if(!super::closed())
|
||||
{
|
||||
super::close();
|
||||
}
|
||||
}
|
||||
|
||||
void push(const ValueType& elem);
|
||||
void push(BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
queue_op_status try_push(const ValueType& elem);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
ValueType pull();
|
||||
|
||||
void pull(ValueType&);
|
||||
|
||||
queue_op_status pull_until(const clock::time_point&, ValueType&);
|
||||
queue_op_status pull_for(const clock::duration&, ValueType&);
|
||||
|
||||
queue_op_status try_pull(ValueType& elem);
|
||||
queue_op_status wait_pull(ValueType& elem);
|
||||
queue_op_status nonblocking_pull(ValueType&);
|
||||
|
||||
private:
|
||||
void push(unique_lock<mutex>&, const ValueType& elem);
|
||||
void push(lock_guard<mutex>&, const ValueType& elem);
|
||||
void push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
void push(lock_guard<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
queue_op_status try_push(unique_lock<mutex>&, const ValueType& elem);
|
||||
queue_op_status try_push(unique_lock<mutex>&, BOOST_THREAD_RV_REF(ValueType) elem);
|
||||
|
||||
ValueType pull(unique_lock<mutex>&);
|
||||
ValueType pull(lock_guard<mutex>&);
|
||||
|
||||
void pull(unique_lock<mutex>&, ValueType&);
|
||||
void pull(lock_guard<mutex>&, ValueType&);
|
||||
|
||||
queue_op_status try_pull(lock_guard<mutex>& lk, ValueType& elem);
|
||||
queue_op_status try_pull(unique_lock<mutex>& lk, ValueType& elem);
|
||||
|
||||
queue_op_status wait_pull(unique_lock<mutex>& lk, ValueType& elem);
|
||||
|
||||
queue_op_status nonblocking_pull(unique_lock<mutex>& lk, ValueType&);
|
||||
|
||||
sync_priority_queue(const sync_priority_queue&);
|
||||
sync_priority_queue& operator= (const sync_priority_queue&);
|
||||
sync_priority_queue(BOOST_THREAD_RV_REF(sync_priority_queue));
|
||||
sync_priority_queue& operator= (BOOST_THREAD_RV_REF(sync_priority_queue));
|
||||
}; //end class
|
||||
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, const T& elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, const T& elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(const T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
push(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(unique_lock<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(lock_guard<mutex>& lk, BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::data_.push(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
template <class T, class Container,class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::push(BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
push(lk, boost::move(elem));
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(const T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::try_push(BOOST_THREAD_RV_REF(T) elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push(lk, boost::move(elem));
|
||||
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&)
|
||||
{
|
||||
return super::data_.pull();
|
||||
}
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&)
|
||||
{
|
||||
return super::data_.pull();
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
T sync_priority_queue<T,Container,Cmp>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(unique_lock<mutex>&, T& elem)
|
||||
{
|
||||
elem = super::data_.pull();
|
||||
}
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(lock_guard<mutex>&, T& elem)
|
||||
{
|
||||
elem = super::data_.pull();
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
void sync_priority_queue<T,Container,Cmp>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_until(const clock::time_point& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
|
||||
return queue_op_status::timeout;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Cont,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Cont,Cmp>::pull_for(const clock::duration& dura, T& elem)
|
||||
{
|
||||
return pull_until(clock::now() + dura, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T, class Container,class Cmp>
|
||||
queue_op_status
|
||||
sync_priority_queue<T,Container,Cmp>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
|
||||
template <class T,class Container, class Cmp>
|
||||
queue_op_status sync_priority_queue<T,Container,Cmp>::nonblocking_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
} //end concurrent namespace
|
||||
|
||||
using concurrent::sync_priority_queue;
|
||||
|
||||
} //end boost namespace
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
544
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
544
include/boost/thread/concurrent_queues/sync_queue.hpp
Normal file
@@ -0,0 +1,544 @@
|
||||
#ifndef BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP
|
||||
#define BOOST_THREAD_CONCURRENT_QUEUES_SYNC_QUEUE_HPP
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// (C) Copyright Vicente J. Botet Escriba 2013-2014. Distributed under the Boost
|
||||
// Software License, Version 1.0. (See accompanying file
|
||||
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
// See http://www.boost.org/libs/thread for documentation.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#include <boost/thread/concurrent_queues/detail/sync_queue_base.hpp>
|
||||
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
|
||||
#include <boost/thread/condition_variable.hpp>
|
||||
#include <boost/thread/csbl/deque.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/mutex.hpp>
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
template <typename ValueType>
|
||||
class sync_queue
|
||||
: public detail::sync_queue_base<ValueType, csbl::deque<ValueType> >
|
||||
{
|
||||
typedef detail::sync_queue_base<ValueType, csbl::deque<ValueType> > super;
|
||||
|
||||
public:
|
||||
typedef ValueType value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
// Constructors/Assignment/Destructors
|
||||
BOOST_THREAD_NO_COPYABLE(sync_queue)
|
||||
inline sync_queue();
|
||||
//template <typename Range>
|
||||
//inline explicit sync_queue(Range range);
|
||||
inline ~sync_queue();
|
||||
|
||||
// Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& x);
|
||||
inline bool try_push(const value_type& x);
|
||||
inline bool try_push(no_block_tag, const value_type& x);
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline bool try_push(BOOST_THREAD_RV_REF(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 queue_op_status try_push_back(const value_type& x);
|
||||
inline queue_op_status nonblocking_push_back(const value_type& x);
|
||||
inline queue_op_status wait_push_back(const value_type& x);
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
|
||||
|
||||
// Observers/Modifiers
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type&);
|
||||
inline void pull(ValueType& elem, bool & closed);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull();
|
||||
inline shared_ptr<ValueType> ptr_pull();
|
||||
#endif
|
||||
inline void pull_front(value_type&);
|
||||
// enable_if is_nothrow_copy_movable<value_type>
|
||||
inline value_type pull_front();
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type&);
|
||||
inline bool try_pull(no_block_tag,value_type&);
|
||||
inline shared_ptr<ValueType> try_pull();
|
||||
#endif
|
||||
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:
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline bool try_pull(value_type& x, 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);
|
||||
inline shared_ptr<value_type> try_pull(unique_lock<mutex>& lk);
|
||||
#endif
|
||||
inline queue_op_status try_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_pull_front(value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(const value_type& x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
inline queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x, unique_lock<mutex>& lk);
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void pull(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
}
|
||||
inline value_type pull(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
inline boost::shared_ptr<value_type> ptr_pull(unique_lock<mutex>& )
|
||||
{
|
||||
shared_ptr<value_type> res = make_shared<value_type>(boost::move(super::data_.front()));
|
||||
super::data_.pop_front();
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
inline void pull_front(value_type& elem, unique_lock<mutex>& )
|
||||
{
|
||||
elem = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
}
|
||||
inline value_type pull_front(unique_lock<mutex>& )
|
||||
{
|
||||
value_type e = boost::move(super::data_.front());
|
||||
super::data_.pop_front();
|
||||
return boost::move(e);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
inline void push(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
#endif
|
||||
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(elem);
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
|
||||
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::data_.push_back(boost::move(elem));
|
||||
super::notify_not_empty_if_needed(lk);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::sync_queue() :
|
||||
super()
|
||||
{
|
||||
}
|
||||
|
||||
// template <typename ValueType>
|
||||
// template <typename Range>
|
||||
// explicit sync_queue<ValueType>::sync_queue(Range range) :
|
||||
// data_(), closed_(false)
|
||||
// {
|
||||
// try
|
||||
// {
|
||||
// typedef typename Range::iterator iterator_t;
|
||||
// iterator_t first = boost::begin(range);
|
||||
// iterator_t end = boost::end(range);
|
||||
// for (iterator_t cur = first; cur != end; ++cur)
|
||||
// {
|
||||
// data_.push(boost::move(*cur));;
|
||||
// }
|
||||
// notify_not_empty_if_needed(lk);
|
||||
// }
|
||||
// catch (...)
|
||||
// {
|
||||
// delete[] data_;
|
||||
// }
|
||||
// }
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>::~sync_queue()
|
||||
{
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
return false;
|
||||
}
|
||||
pull(elem, lk);
|
||||
return true;
|
||||
}
|
||||
template <typename ValueType>
|
||||
shared_ptr<ValueType> sync_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
return shared_ptr<ValueType>();
|
||||
}
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull_front(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_pull(no_block_tag,ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::try_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_pull(lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_pull_front(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull(elem, lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull(ValueType& elem, bool & has_been_closed)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
if (has_been_closed) {return;}
|
||||
pull(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull(lk);
|
||||
}
|
||||
template <typename ValueType>
|
||||
boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return ptr_pull(lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::pull_front(ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
pull_front(elem, lk);
|
||||
}
|
||||
|
||||
// enable if ValueType is nothrow movable
|
||||
template <typename ValueType>
|
||||
ValueType sync_queue<ValueType>::pull_front()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull_front(lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(elem, lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return false;
|
||||
return try_push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push(elem, lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(const ValueType& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push_back(elem, lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::try_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem, unique_lock<mutex>& lk)
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
push_back(boost::move(elem), lk);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::wait_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
bool sync_queue<ValueType>::try_push(no_block_tag, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return try_push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
queue_op_status sync_queue<ValueType>::nonblocking_push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (!lk.owns_lock())
|
||||
{
|
||||
return queue_op_status::busy;
|
||||
}
|
||||
return try_push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push(boost::move(elem), lk);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename ValueType>
|
||||
void sync_queue<ValueType>::push_back(BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::throw_if_closed(lk);
|
||||
push_back(boost::move(elem), lk);
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, BOOST_THREAD_RV_REF(ValueType) elem)
|
||||
{
|
||||
sbq.push_back(boost::move(elem));
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem)
|
||||
{
|
||||
sbq.push_back(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem)
|
||||
{
|
||||
sbq.pull_front(elem);
|
||||
return sbq;
|
||||
}
|
||||
|
||||
}
|
||||
using concurrent::sync_queue;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
431
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
431
include/boost/thread/concurrent_queues/sync_timed_queue.hpp
Normal file
@@ -0,0 +1,431 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_SYNC_TIMED_QUEUE_HPP
|
||||
#define BOOST_THREAD_SYNC_TIMED_QUEUE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/concurrent_queues/sync_priority_queue.hpp>
|
||||
#include <boost/chrono/duration.hpp>
|
||||
#include <boost/chrono/time_point.hpp>
|
||||
#include <boost/chrono/system_clocks.hpp>
|
||||
#include <boost/chrono/chrono_io.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace concurrent
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
template <class T>
|
||||
struct scheduled_type
|
||||
{
|
||||
typedef typename chrono::steady_clock clock;
|
||||
typedef chrono::steady_clock::time_point time_point;
|
||||
T data;
|
||||
time_point time;
|
||||
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(scheduled_type)
|
||||
|
||||
scheduled_type(T const& pdata, time_point tp) : data(pdata), time(tp) {}
|
||||
scheduled_type(BOOST_THREAD_RV_REF(T) pdata, time_point tp) : data(boost::move(pdata)), time(tp) {}
|
||||
|
||||
scheduled_type(scheduled_type const& other) : data(other.data), time(other.time) {}
|
||||
scheduled_type& operator=(BOOST_THREAD_COPY_ASSIGN_REF(scheduled_type) other) {
|
||||
data = other.data;
|
||||
time = other.time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
scheduled_type(BOOST_THREAD_RV_REF(scheduled_type) other) : data(boost::move(other.data)), time(other.time) {}
|
||||
scheduled_type& operator=(BOOST_THREAD_RV_REF(scheduled_type) other) {
|
||||
data = boost::move(other.data);
|
||||
time = other.time;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool time_not_reached() const
|
||||
{
|
||||
return time > clock::now();
|
||||
}
|
||||
|
||||
bool operator <(const scheduled_type<T> other) const
|
||||
{
|
||||
return this->time > other.time;
|
||||
}
|
||||
}; //end struct
|
||||
|
||||
} //end detail namespace
|
||||
|
||||
template <class T>
|
||||
class sync_timed_queue
|
||||
: private sync_priority_queue<detail::scheduled_type<T> >
|
||||
{
|
||||
typedef detail::scheduled_type<T> stype;
|
||||
typedef sync_priority_queue<stype> super;
|
||||
public:
|
||||
//typedef typename stype::clock clock; // fixme
|
||||
typedef typename chrono::steady_clock clock;
|
||||
|
||||
typedef typename clock::duration duration;
|
||||
typedef typename clock::time_point time_point;
|
||||
typedef T value_type;
|
||||
//typedef typename super::value_type value_type; // fixme
|
||||
typedef typename super::underlying_queue_type underlying_queue_type;
|
||||
typedef typename super::size_type size_type;
|
||||
typedef typename super::op_status op_status;
|
||||
|
||||
sync_timed_queue() : super() {};
|
||||
~sync_timed_queue() {}
|
||||
|
||||
using super::size;
|
||||
using super::empty;
|
||||
using super::full;
|
||||
using super::close;
|
||||
using super::closed;
|
||||
|
||||
T pull();
|
||||
void pull(T& elem);
|
||||
|
||||
queue_op_status pull_until(const clock::time_point& tp, T& elem);
|
||||
queue_op_status pull_for(const clock::duration& dura, T& elem);
|
||||
|
||||
queue_op_status try_pull(T& elem);
|
||||
queue_op_status wait_pull(T& elem);
|
||||
queue_op_status nonblocking_pull(T& elem);
|
||||
|
||||
void push(const T& elem, const time_point& tp);
|
||||
void push(const T& elem, const duration& dura);
|
||||
|
||||
queue_op_status try_push(const T& elem, const time_point& tp);
|
||||
queue_op_status try_push(const T& elem, const duration& dura);
|
||||
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, const time_point& tp);
|
||||
queue_op_status try_push(BOOST_THREAD_RV_REF(T) elem, const duration& dura);
|
||||
|
||||
private:
|
||||
T pull(unique_lock<mutex>&);
|
||||
T pull(lock_guard<mutex>&);
|
||||
|
||||
void pull(unique_lock<mutex>&, T& elem);
|
||||
void pull(lock_guard<mutex>&, T& elem);
|
||||
|
||||
queue_op_status try_pull(unique_lock<mutex>&, T& elem);
|
||||
queue_op_status try_pull(lock_guard<mutex>&, T& elem);
|
||||
|
||||
queue_op_status wait_pull(unique_lock<mutex>& lk, T& elem);
|
||||
|
||||
//queue_op_status nonblocking_pull(unique_lock<mutex>& lk, T& elem);
|
||||
|
||||
bool wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>&);
|
||||
T pull_when_time_reached(unique_lock<mutex>&);
|
||||
queue_op_status pull_when_time_reached_until(unique_lock<mutex>&, const clock::time_point& tp, T& elem);
|
||||
bool time_not_reached(unique_lock<mutex>&);
|
||||
bool time_not_reached(lock_guard<mutex>&);
|
||||
bool empty_or_time_not_reached(unique_lock<mutex>&);
|
||||
bool empty_or_time_not_reached(lock_guard<mutex>&);
|
||||
|
||||
sync_timed_queue(const sync_timed_queue&);
|
||||
sync_timed_queue& operator=(const sync_timed_queue&);
|
||||
sync_timed_queue(BOOST_THREAD_RV_REF(sync_timed_queue));
|
||||
sync_timed_queue& operator=(BOOST_THREAD_RV_REF(sync_timed_queue));
|
||||
}; //end class
|
||||
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::push(const T& elem, const time_point& tp)
|
||||
{
|
||||
super::push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::push(const T& elem, const duration& dura)
|
||||
{
|
||||
push(elem, clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(const T& elem, const time_point& tp)
|
||||
{
|
||||
return super::try_push(stype(elem,tp));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(const T& elem, const duration& dura)
|
||||
{
|
||||
return try_push(elem,clock::now() + dura);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(BOOST_THREAD_RV_REF(T) elem, const time_point& tp)
|
||||
{
|
||||
return super::try_push(stype(boost::move(elem), tp));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_push(BOOST_THREAD_RV_REF(T) elem, const duration& dura)
|
||||
{
|
||||
return try_push(boost::move(elem), clock::now() + dura);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::time_not_reached(unique_lock<mutex>&)
|
||||
{
|
||||
return super::data_.top().time_not_reached();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::time_not_reached(lock_guard<mutex>&)
|
||||
{
|
||||
return super::data_.top().time_not_reached();
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::wait_until_not_empty_time_reached_or_closed(unique_lock<mutex>& lk)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
if (super::closed(lk)) return true;
|
||||
while (! super::empty(lk)) {
|
||||
if (! time_not_reached(lk)) return false;
|
||||
super::not_empty_.wait_until(lk, super::data_.top().time);
|
||||
if (super::closed(lk)) return true;
|
||||
}
|
||||
if (super::closed(lk)) return true;
|
||||
super::not_empty_.wait(lk);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull_when_time_reached(unique_lock<mutex>& lk)
|
||||
{
|
||||
while (time_not_reached(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
super::not_empty_.wait_until(lk,super::data_.top().time);
|
||||
super::wait_until_not_empty(lk);
|
||||
}
|
||||
return pull(lk);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status
|
||||
sync_timed_queue<T>::pull_when_time_reached_until(unique_lock<mutex>& lk, const clock::time_point& tp, T& elem)
|
||||
{
|
||||
clock::time_point tpmin = (tp < super::data_.top().time) ? tp : super::data_.top().time;
|
||||
while (time_not_reached(lk))
|
||||
{
|
||||
super::throw_if_closed(lk);
|
||||
if (queue_op_status::timeout == super::not_empty_.wait_until(lk, tpmin)) {
|
||||
if (time_not_reached(lk)) return queue_op_status::not_ready;
|
||||
return queue_op_status::timeout;
|
||||
}
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::empty_or_time_not_reached(unique_lock<mutex>& lk)
|
||||
{
|
||||
if ( super::empty(lk) ) return true;
|
||||
if ( time_not_reached(lk) ) return true;
|
||||
return false;
|
||||
}
|
||||
template <class T>
|
||||
bool sync_timed_queue<T>::empty_or_time_not_reached(lock_guard<mutex>& lk)
|
||||
{
|
||||
if ( super::empty(lk) ) return true;
|
||||
if ( time_not_reached(lk) ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull(unique_lock<mutex>&)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
return boost::move(super::data_.pull().data);
|
||||
#else
|
||||
return super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull(lock_guard<mutex>&)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
return boost::move(super::data_.pull().data);
|
||||
#else
|
||||
return super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
template <class T>
|
||||
T sync_timed_queue<T>::pull()
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
return pull_when_time_reached(lk);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::pull(unique_lock<mutex>&, T& elem)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
elem = boost::move(super::data_.pull().data);
|
||||
#else
|
||||
elem = super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::pull(lock_guard<mutex>&, T& elem)
|
||||
{
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
elem = boost::move(super::data_.pull().data);
|
||||
#else
|
||||
elem = super::data_.pull().data;
|
||||
#endif
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void sync_timed_queue<T>::pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
super::wait_until_not_empty(lk);
|
||||
elem = pull_when_time_reached(lk);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T>
|
||||
queue_op_status
|
||||
sync_timed_queue<T>::pull_until(const clock::time_point& tp, T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
|
||||
if (queue_op_status::timeout == super::wait_until_not_empty_until(lk, tp))
|
||||
return queue_op_status::timeout;
|
||||
return pull_when_time_reached_until(lk, tp, elem);
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
template <class T>
|
||||
queue_op_status
|
||||
sync_timed_queue<T>::pull_for(const clock::duration& dura, T& elem)
|
||||
{
|
||||
return pull_until(clock::now() + dura, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if ( super::empty(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
if ( time_not_reached(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_pull(lock_guard<mutex>& lk, T& elem)
|
||||
{
|
||||
if ( super::empty(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::empty;
|
||||
}
|
||||
if ( time_not_reached(lk) )
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
return queue_op_status::not_ready;
|
||||
}
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::try_pull(T& elem)
|
||||
{
|
||||
lock_guard<mutex> lk(super::mtx_);
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::wait_pull(unique_lock<mutex>& lk, T& elem)
|
||||
{
|
||||
if (super::empty(lk))
|
||||
{
|
||||
if (super::closed(lk)) return queue_op_status::closed;
|
||||
}
|
||||
bool has_been_closed = wait_until_not_empty_time_reached_or_closed(lk);
|
||||
if (has_been_closed) return queue_op_status::closed;
|
||||
pull(lk, elem);
|
||||
return queue_op_status::success;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::wait_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_);
|
||||
return wait_pull(lk, elem);
|
||||
}
|
||||
|
||||
// ///////////////////////////
|
||||
// template <class T>
|
||||
// queue_op_status sync_timed_queue<T>::wait_pull(unique_lock<mutex> &lk, T& elem)
|
||||
// {
|
||||
// if (super::empty(lk))
|
||||
// {
|
||||
// if (super::closed(lk)) return queue_op_status::closed;
|
||||
// }
|
||||
// bool has_been_closed = super::wait_until_not_empty_or_closed(lk);
|
||||
// if (has_been_closed) return queue_op_status::closed;
|
||||
// pull(lk, elem);
|
||||
// return queue_op_status::success;
|
||||
// }
|
||||
// template <class T>
|
||||
// queue_op_status sync_timed_queue<T>::wait_pull(T& elem)
|
||||
// {
|
||||
// unique_lock<mutex> lk(super::mtx_);
|
||||
// return wait_pull(lk, elem);
|
||||
// }
|
||||
|
||||
///////////////////////////
|
||||
template <class T>
|
||||
queue_op_status sync_timed_queue<T>::nonblocking_pull(T& elem)
|
||||
{
|
||||
unique_lock<mutex> lk(super::mtx_, try_to_lock);
|
||||
if (! lk.owns_lock()) return queue_op_status::busy;
|
||||
return try_pull(lk, elem);
|
||||
}
|
||||
|
||||
} //end concurrent namespace
|
||||
|
||||
using concurrent::sync_timed_queue;
|
||||
|
||||
} //end boost namespace
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
45
include/boost/thread/csbl/deque.hpp
Normal file
45
include/boost/thread/csbl/deque.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_DEQUE_HPP
|
||||
#define BOOST_CSBL_DEQUE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
// MSVC has some trouble instantiating a non_copyable type
|
||||
//C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(606) : error C2248: 'non_copyable::non_copyable' : cannot access private member declared in class 'non_copyable'
|
||||
// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(24) : see declaration of 'non_copyable::non_copyable'
|
||||
// ..\libs\thread\test\sync\mutual_exclusion\queue_views\single_thread_pass.cpp(23) : see declaration of 'non_copyable'
|
||||
// C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\INCLUDE\xmemory0(605) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
|
||||
// with
|
||||
// [
|
||||
// _Ty=non_copyable
|
||||
// ]
|
||||
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES || (defined _MSC_VER && _MSC_FULL_VER < 180020827)
|
||||
#ifndef BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#define BOOST_THREAD_USES_BOOST_DEQUE
|
||||
#endif
|
||||
#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
|
||||
41
include/boost/thread/csbl/memory/default_delete.hpp
Normal file
41
include/boost/thread/csbl/memory/default_delete.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_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/move/unique_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::movelib::default_delete;
|
||||
}
|
||||
}
|
||||
#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
|
||||
42
include/boost/thread/csbl/memory/shared_ptr.hpp
Normal file
42
include/boost/thread/csbl/memory/shared_ptr.hpp
Normal file
@@ -0,0 +1,42 @@
|
||||
// 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/10 Vicente J. Botet Escriba
|
||||
// Creation.
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_SHARED_PTR_HPP
|
||||
#define BOOST_CSBL_MEMORY_SHARED_PTR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
|
||||
#include <boost/smart_ptr/shared_ptr.hpp>
|
||||
#include <boost/smart_ptr/make_shared.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::shared_ptr;
|
||||
using ::boost::make_shared;
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using std::shared_ptr;
|
||||
using std::make_shared;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif // header
|
||||
28
include/boost/thread/csbl/memory/unique_ptr.hpp
Normal file
28
include/boost/thread/csbl/memory/unique_ptr.hpp
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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/10 Vicente J. Botet Escriba
|
||||
// Creation using interprocess::unique_ptr.
|
||||
// 2014/09 Vicente J. Botet Escriba
|
||||
// Adaptation to movelib::unique_ptr
|
||||
|
||||
#ifndef BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
#define BOOST_CSBL_MEMORY_UNIQUE_PTR_HPP
|
||||
|
||||
#include <boost/thread/csbl/memory/config.hpp>
|
||||
|
||||
#include <boost/move/unique_ptr.hpp>
|
||||
#include <boost/move/make_unique.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace csbl
|
||||
{
|
||||
using ::boost::movelib::unique_ptr;
|
||||
using ::boost::movelib::make_unique;
|
||||
|
||||
}
|
||||
}
|
||||
#endif // header
|
||||
49
include/boost/thread/csbl/tuple.hpp
Normal file
49
include/boost/thread/csbl/tuple.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_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;
|
||||
using ::boost::make_tuple;
|
||||
//using ::boost::tuple_size;
|
||||
#else
|
||||
// 20.4.2, class template tuple:
|
||||
using ::std::tuple;
|
||||
using ::std::get;
|
||||
using ::std::make_tuple;
|
||||
using ::std::tuple_size;
|
||||
// 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
|
||||
{
|
||||
|
||||
@@ -1,571 +0,0 @@
|
||||
// Copyright (C) 2012 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// 2013/04 Vicente J. Botet Escriba
|
||||
// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined.
|
||||
// Make use of Boost.Move
|
||||
// Make use of Boost.Tuple (movable)
|
||||
// 2012/11 Vicente J. Botet Escriba
|
||||
// Adapt to boost libc++ implementation
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// 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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
#define BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/utility/result_of.hpp>
|
||||
#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/tuple/tuple.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
template <class Fp, class ... Args>
|
||||
class async_func
|
||||
{
|
||||
std::tuple<Fp, Args...> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY( async_func)
|
||||
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
|
||||
typedef typename result_of<Fp(Args...)>::type result_type;
|
||||
|
||||
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)...)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f) : f_(boost::move(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(boost::move(std::get<0>(f_)), boost::move(std::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(X) async_func<Fp> BOOST_THREAD_DCL_MOVABLE_END
|
||||
#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;
|
||||
|
||||
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>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
T8 v8_;
|
||||
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
, BOOST_THREAD_RV_REF(T7) a7
|
||||
, BOOST_THREAD_RV_REF(T8) a8
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
, v7_(boost::move(a7))
|
||||
, v8_(boost::move(a8))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
, boost::move(v7_)
|
||||
, boost::move(v8_)
|
||||
);
|
||||
}
|
||||
};
|
||||
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>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
, BOOST_THREAD_RV_REF(T7) a7
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
, v7_(boost::move(a7))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
, boost::move(v7_)
|
||||
);
|
||||
}
|
||||
};
|
||||
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>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
);
|
||||
}
|
||||
};
|
||||
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>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4>
|
||||
class async_func<Fp, T0, T1, T2, T3, T4>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3>
|
||||
class async_func<Fp, T0, T1, T2, T3>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2>
|
||||
class async_func<Fp, T0, T1, T2>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
, BOOST_THREAD_RV_REF(T2) a2
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1>
|
||||
class async_func<Fp, T0, T1>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0, T1)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
{}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0>
|
||||
class async_func<Fp, T0>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
public:
|
||||
BOOST_THREAD_MOVABLE_ONLY(async_func)
|
||||
typedef typename result_of<Fp(T0)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_RV_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp))
|
||||
, v0_(boost::move(f.a0))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp>
|
||||
class async_func<Fp>
|
||||
{
|
||||
Fp fp_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func)
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit async_func(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
: fp_(boost::move(f))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
async_func(BOOST_THREAD_FWD_REF(async_func) f)
|
||||
: fp_(boost::move(f.fp_))
|
||||
{}
|
||||
result_type operator()()
|
||||
{
|
||||
return fp_();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -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,7 @@
|
||||
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE) && \
|
||||
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
|
||||
! defined(BOOST_NO_CXX11_AUTO) && \
|
||||
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
|
||||
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
@@ -248,6 +247,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 +279,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
|
||||
@@ -333,6 +353,12 @@
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_THREAD_USES_MOVE
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#define BOOST_THREAD_FUTURE_USES_OPTIONAL
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
# pragma warn -8008 // Condition always true/false
|
||||
# pragma warn -8080 // Identifier declared but never used
|
||||
@@ -358,7 +384,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,7 +15,8 @@
|
||||
* BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or
|
||||
* makes it private.
|
||||
*/
|
||||
#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_DELETED_FUNCTIONS && ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#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()
|
||||
{
|
||||
if (impl) 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,10 @@ 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_NO_CXX11_TRAILING_RESULT_TYPES)
|
||||
|
||||
#define BOOST_THREAD_PROVIDES_INVOKE
|
||||
|
||||
@@ -58,6 +61,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 +76,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 +102,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 +146,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 +195,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 +246,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 +263,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 +283,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,6 +302,36 @@ 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) && \
|
||||
@@ -395,22 +530,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 +565,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 +601,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 +636,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 +648,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 +660,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 +671,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 +684,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 +706,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 +717,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 +741,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 +754,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 +1360,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
|
||||
|
||||
754
include/boost/thread/detail/invoker.hpp
Normal file
754
include/boost/thread/detail/invoker.hpp
Normal file
@@ -0,0 +1,754 @@
|
||||
// Copyright (C) 2012 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
// 2013/04 Vicente J. Botet Escriba
|
||||
// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined.
|
||||
// Make use of Boost.Move
|
||||
// Make use of Boost.Tuple (movable)
|
||||
// 2012/11 Vicente J. Botet Escriba
|
||||
// Adapt to boost libc++ implementation
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
// The invoker code is based on the one from libcxx.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef BOOST_THREAD_DETAIL_INVOKER_HPP
|
||||
#define BOOST_THREAD_DETAIL_INVOKER_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#include <boost/utility/result_of.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/detail/invoke.hpp>
|
||||
#include <boost/thread/detail/make_tuple_indices.hpp>
|
||||
#include <boost/thread/csbl/tuple.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
#include <boost/thread/detail/variadic_header.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
|
||||
#if defined(BOOST_THREAD_PROVIDES_INVOKE) && ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && ! defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
|
||||
template <class Fp, class ... Args>
|
||||
class invoker
|
||||
{
|
||||
//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_COPYABLE_AND_MOVABLE( 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 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
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f) : f_(boost::move(BOOST_THREAD_RV(f).f_))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker( const invoker& f) : f_(f.f_)
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker& operator=(BOOST_THREAD_RV_REF(invoker) f)
|
||||
{
|
||||
f_ = boost::move(BOOST_THREAD_RV(f).f_);
|
||||
}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker& operator=( BOOST_THREAD_COPY_ASSIGN_REF(invoker) f)
|
||||
{
|
||||
f_ = 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(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
|
||||
}
|
||||
};
|
||||
|
||||
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_COPYABLE_AND_MOVABLE( 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_COPYABLE_AND_MOVABLE(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_RV_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_COPYABLE_AND_MOVABLE(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_RV_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 invoker;
|
||||
|
||||
template <class Fp,
|
||||
class T0 , class T1 , class T2 ,
|
||||
class T3 , class T4 , class T5 ,
|
||||
class T6 , class T7 , class T8 >
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
T8 v8_;
|
||||
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
|
||||
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
, BOOST_THREAD_RV_REF(T7) a7
|
||||
, BOOST_THREAD_RV_REF(T8) a8
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
, v7_(boost::move(a7))
|
||||
, v8_(boost::move(a8))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
, boost::move(v7_)
|
||||
, boost::move(v8_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
T7 v7_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
, BOOST_THREAD_RV_REF(T7) a7
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
, v7_(boost::move(a7))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
, boost::move(v7_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5, T6>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
T6 v6_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
, BOOST_THREAD_RV_REF(T6) a6
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
, v6_(boost::move(a6))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
, boost::move(v6_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4, T5>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
T5 v5_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
, BOOST_THREAD_RV_REF(T5) a5
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
, v5_(boost::move(a5))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
, boost::move(v5_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3, class T4>
|
||||
class invoker<Fp, T0, T1, T2, T3, T4>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
T4 v4_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
, BOOST_THREAD_RV_REF(T4) a4
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
, v4_(boost::move(a4))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
, boost::move(v4_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2, class T3>
|
||||
class invoker<Fp, T0, T1, T2, T3>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
T3 v3_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
, BOOST_THREAD_RV_REF(T3) a3
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
, v3_(boost::move(a3))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
, boost::move(v3_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1, class T2>
|
||||
class invoker<Fp, T0, T1, T2>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
T2 v2_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
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
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
, v2_(boost::move(a2))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
, boost::move(v2_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0, class T1>
|
||||
class invoker<Fp, T0, T1>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
T1 v1_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0, T1)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
, BOOST_THREAD_RV_REF(T1) a1
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
, v1_(boost::move(a1))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_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()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
, boost::move(v1_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp, class T0>
|
||||
class invoker<Fp, T0>
|
||||
{
|
||||
Fp fp_;
|
||||
T0 v0_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp(T0)>::type result_type;
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f
|
||||
, BOOST_THREAD_RV_REF(T0) a0
|
||||
)
|
||||
: fp_(boost::move(f))
|
||||
, v0_(boost::move(a0))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
|
||||
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
|
||||
{}
|
||||
|
||||
result_type operator()()
|
||||
{
|
||||
return invoke(boost::move(fp_)
|
||||
, boost::move(v0_)
|
||||
);
|
||||
}
|
||||
};
|
||||
template <class Fp>
|
||||
class invoker<Fp>
|
||||
{
|
||||
Fp fp_;
|
||||
public:
|
||||
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
|
||||
typedef typename result_of<Fp()>::type result_type;
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
explicit invoker(BOOST_THREAD_FWD_REF(Fp) f)
|
||||
: fp_(boost::move(f))
|
||||
{}
|
||||
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
invoker(BOOST_THREAD_RV_REF(invoker) f)
|
||||
: fp_(boost::move(f.fp_))
|
||||
{}
|
||||
result_type operator()()
|
||||
{
|
||||
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_RV_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
|
||||
{
|
||||
|
||||
@@ -71,6 +80,7 @@ namespace boost
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
@@ -91,6 +101,7 @@ namespace boost
|
||||
|
||||
#elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_MSVC
|
||||
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
@@ -112,6 +123,7 @@ namespace boost
|
||||
#else
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) BOOST_COPY_ASSIGN_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
|
||||
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
|
||||
@@ -131,6 +143,7 @@ namespace boost
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_COPY_ASSIGN_REF(TYPE) const TYPE&
|
||||
#define BOOST_THREAD_RV_REF(TYPE) boost::detail::thread_move_t< TYPE >
|
||||
#define BOOST_THREAD_RV_REF_BEG boost::detail::thread_move_t<
|
||||
#define BOOST_THREAD_RV_REF_END >
|
||||
@@ -189,6 +202,8 @@ namespace detail
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE)
|
||||
|
||||
#define BOOST_THREAD_COPYABLE(TYPE)
|
||||
|
||||
#else
|
||||
|
||||
#if defined BOOST_THREAD_USES_MOVE
|
||||
@@ -211,6 +226,11 @@ namespace detail
|
||||
return *static_cast<const ::boost::rv<TYPE>* >(this); \
|
||||
}\
|
||||
|
||||
#define BOOST_THREAD_COPYABLE(TYPE) \
|
||||
TYPE& operator=(TYPE &t)\
|
||||
{ this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_THREAD_MOVABLE(TYPE) \
|
||||
@@ -224,21 +244,94 @@ namespace detail
|
||||
return x; \
|
||||
} \
|
||||
|
||||
#define BOOST_THREAD_COPYABLE(TYPE)
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define BOOST_THREAD_MOVABLE_ONLY(TYPE) \
|
||||
BOOST_THREAD_NO_COPYABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
typedef int boost_move_no_copy_constructor_or_assign; \
|
||||
|
||||
|
||||
#define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
BOOST_THREAD_COPYABLE(TYPE) \
|
||||
BOOST_THREAD_MOVABLE(TYPE) \
|
||||
|
||||
|
||||
|
||||
namespace boost
|
||||
{ namespace thread_detail
|
||||
{
|
||||
namespace thread_detail
|
||||
{
|
||||
|
||||
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
|
||||
#elif defined BOOST_THREAD_USES_MOVE
|
||||
template <class T>
|
||||
struct is_rv
|
||||
: ::boost::move_detail::is_rv<T>
|
||||
{};
|
||||
|
||||
#else
|
||||
template <class T>
|
||||
struct is_rv
|
||||
: ::boost::integral_constant<bool, false>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct is_rv< ::boost::detail::thread_move_t<T> >
|
||||
: ::boost::integral_constant<bool, true>
|
||||
{};
|
||||
|
||||
template <class T>
|
||||
struct is_rv< const ::boost::detail::thread_move_t<T> >
|
||||
: ::boost::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
234
include/boost/thread/detail/nullary_function.hpp
Normal file
234
include/boost/thread/detail/nullary_function.hpp
Normal file
@@ -0,0 +1,234 @@
|
||||
// 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/thread/csbl/memory/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()
|
||||
{
|
||||
}
|
||||
};
|
||||
csbl::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_COPYABLE_AND_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 :
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
#else
|
||||
impl(boost::move(other.impl))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
#else
|
||||
impl = boost::move(other.impl);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
void operator()()
|
||||
{ if (impl) impl->call();}
|
||||
|
||||
};
|
||||
|
||||
template <typename R>
|
||||
class nullary_function<R()>
|
||||
{
|
||||
struct impl_base
|
||||
{
|
||||
virtual R call()=0;
|
||||
virtual ~impl_base()
|
||||
{
|
||||
}
|
||||
};
|
||||
csbl::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_COPYABLE_AND_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 :
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl(BOOST_THREAD_RV(other).impl)
|
||||
{
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
}
|
||||
#else
|
||||
impl(boost::move(other.impl))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
nullary_function()
|
||||
: impl()
|
||||
{
|
||||
}
|
||||
~nullary_function()
|
||||
{
|
||||
}
|
||||
|
||||
nullary_function& operator=(BOOST_THREAD_COPY_ASSIGN_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
impl=other.impl;
|
||||
return *this;
|
||||
}
|
||||
nullary_function& operator=(BOOST_THREAD_RV_REF(nullary_function) other) BOOST_NOEXCEPT
|
||||
{
|
||||
#if defined BOOST_NO_CXX11_SMART_PTR
|
||||
impl=BOOST_THREAD_RV(other).impl;
|
||||
BOOST_THREAD_RV(other).impl.reset();
|
||||
#else
|
||||
impl = boost::move(other.impl);
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
|
||||
R operator()()
|
||||
{ if (impl) return impl->call(); else return R();}
|
||||
|
||||
};
|
||||
}
|
||||
//BOOST_THREAD_DCL_MOVABLE_BEG(F) detail::nullary_function<F> BOOST_THREAD_DCL_MOVABLE_END
|
||||
}
|
||||
|
||||
#endif // header
|
||||
@@ -4,9 +4,10 @@
|
||||
// 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>
|
||||
#include <boost/predef/platform.h>
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
@@ -24,12 +25,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 +65,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 +173,7 @@ namespace boost
|
||||
private:
|
||||
bool start_thread_noexcept();
|
||||
bool start_thread_noexcept(const attributes& attr);
|
||||
public:
|
||||
//public:
|
||||
void start_thread()
|
||||
{
|
||||
if (!start_thread_noexcept())
|
||||
@@ -293,7 +292,8 @@ namespace boost
|
||||
template <class F>
|
||||
explicit thread(F f
|
||||
, typename disable_if_c<
|
||||
boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
|
||||
boost::thread_detail::is_rv<F>::value // todo ass a thread_detail::is_rv
|
||||
//boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
|
||||
//|| is_same<typename decay<F>::type, thread>::value
|
||||
, dummy* >::type=0
|
||||
):
|
||||
@@ -303,7 +303,8 @@ namespace boost
|
||||
}
|
||||
template <class F>
|
||||
thread(attributes const& attrs, F f
|
||||
, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
|
||||
, typename disable_if<boost::thread_detail::is_rv<F>, dummy* >::type=0
|
||||
//, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
|
||||
):
|
||||
thread_info(make_thread_info(f))
|
||||
{
|
||||
@@ -334,7 +335,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 +467,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 +556,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 +760,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 +774,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 +783,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 +837,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
|
||||
311
include/boost/thread/executors/basic_thread_pool.hpp
Normal file
311
include/boost/thread/executors/basic_thread_pool.hpp
Normal file
@@ -0,0 +1,311 @@
|
||||
// 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
|
||||
// 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
|
||||
concurrent::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()
|
||||
{
|
||||
try
|
||||
{
|
||||
work task;
|
||||
if (work_queue.try_pull_front(task) == queue_op_status::success)
|
||||
{
|
||||
task();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
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()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = work_queue.wait_pull_front(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread1(AtThreadEntry& at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
worker_thread();
|
||||
}
|
||||
#endif
|
||||
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
worker_thread();
|
||||
}
|
||||
template <class AtThreadEntry>
|
||||
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
|
||||
{
|
||||
at_thread_entry(*this);
|
||||
worker_thread();
|
||||
}
|
||||
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()+1)
|
||||
{
|
||||
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: join all the threads.
|
||||
*/
|
||||
void join()
|
||||
{
|
||||
for (unsigned i = 0; i < threads.size(); ++i)
|
||||
{
|
||||
threads[i].join();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \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_queue.push_back(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(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& pred)
|
||||
{
|
||||
do {
|
||||
if ( ! try_executing_one())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} while (! pred());
|
||||
return true;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::basic_thread_pool;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
// Copyright (C) 2014 Ian Forbed
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef SCHEDULED_EXECUTOR_HPP
|
||||
#define SCHEDULED_EXECUTOR_HPP
|
||||
|
||||
#include <boost/atomic.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/concurrent_queues/sync_timed_queue.hpp>
|
||||
#include <boost/thread/executors/work.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
class scheduled_executor_base
|
||||
{
|
||||
public:
|
||||
typedef boost::function<void()> work;
|
||||
//typedef executors::work work;
|
||||
typedef chrono::steady_clock clock;
|
||||
typedef clock::duration duration;
|
||||
typedef clock::time_point time_point;
|
||||
protected:
|
||||
concurrent::sync_timed_queue<work> _workq;
|
||||
|
||||
scheduled_executor_base() {}
|
||||
public:
|
||||
|
||||
~scheduled_executor_base()
|
||||
{
|
||||
if(!closed())
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
}
|
||||
|
||||
void close()
|
||||
{
|
||||
_workq.close();
|
||||
}
|
||||
|
||||
bool closed()
|
||||
{
|
||||
return _workq.closed();
|
||||
}
|
||||
|
||||
void submit(work w)
|
||||
{
|
||||
_workq.push(w, clock::now());
|
||||
}
|
||||
|
||||
void submit_at(work w, const time_point& tp)
|
||||
{
|
||||
_workq.push(w, tp);
|
||||
}
|
||||
|
||||
void submit_after(work w, const duration& dura)
|
||||
{
|
||||
_workq.push(w, dura);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
try
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
work task;
|
||||
queue_op_status st = _workq.wait_pull(task);
|
||||
if (st == queue_op_status::closed) return;
|
||||
task();
|
||||
}
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}; //end class
|
||||
|
||||
} //end detail namespace
|
||||
} //end executors namespace
|
||||
} //end boost namespace
|
||||
#endif
|
||||
147
include/boost/thread/executors/executor.hpp
Normal file
147
include/boost/thread/executors/executor.hpp
Normal file
@@ -0,0 +1,147 @@
|
||||
// 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() {}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Destroys the executor.
|
||||
*
|
||||
* \par Synchronization
|
||||
* The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
virtual ~executor() {};
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
virtual void close() = 0;
|
||||
|
||||
/**
|
||||
* \par Returns
|
||||
* Whether the pool is closed for submissions.
|
||||
*/
|
||||
virtual bool closed() = 0;
|
||||
|
||||
/**
|
||||
* \par 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.
|
||||
*
|
||||
* \par Synchronization
|
||||
* Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \par 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;
|
||||
// virtual void submit(work& closure) = 0;
|
||||
|
||||
/**
|
||||
* \par Requires
|
||||
* \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \par 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.
|
||||
*
|
||||
* \par Synchronization
|
||||
* Completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \par 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Try to execute one task.
|
||||
*
|
||||
* \par Returns
|
||||
* Whether a task has been executed.
|
||||
*
|
||||
* \par Throws
|
||||
* Whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
virtual bool try_executing_one() = 0;
|
||||
|
||||
/**
|
||||
* \par Requires
|
||||
* This must be called from an scheduled task.
|
||||
*
|
||||
* \par 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
|
||||
137
include/boost/thread/executors/executor_adaptor.hpp
Normal file
137
include/boost/thread/executors/executor_adaptor.hpp
Normal file
@@ -0,0 +1,137 @@
|
||||
// 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));
|
||||
}
|
||||
// void submit(work & closure) {
|
||||
// return ex.submit(closure);
|
||||
// }
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
template <typename Closure>
|
||||
void submit(Closure & closure)
|
||||
{
|
||||
submit(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
submit(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
submit(work(boost::forward<Closure>(closure)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
211
include/boost/thread/executors/generic_executor_ref.hpp
Normal file
211
include/boost/thread/executors/generic_executor_ref.hpp
Normal file
@@ -0,0 +1,211 @@
|
||||
// Copyright (C) 2014 Vicente J. Botet Escriba
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
//
|
||||
|
||||
#ifndef BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP
|
||||
#define BOOST_THREAD_EXECUTORS_GENERIC_EXECUTOR_REF_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
|
||||
#include <boost/thread/detail/delete.hpp>
|
||||
#include <boost/thread/detail/move.hpp>
|
||||
#include <boost/thread/executors/executor.hpp>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace executors
|
||||
{
|
||||
|
||||
template <class Executor>
|
||||
class executor_ref : public executor
|
||||
{
|
||||
Executor& ex;
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
|
||||
/// executor is not copyable.
|
||||
BOOST_THREAD_NO_COPYABLE(executor_ref)
|
||||
executor_ref(Executor& ex) : ex(ex) {}
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Destroys the executor.
|
||||
*
|
||||
* \par Synchronization
|
||||
* The completion of all the closures happen before the completion of the executor destructor.
|
||||
*/
|
||||
~executor_ref() {};
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
void close() { ex.close(); }
|
||||
|
||||
/**
|
||||
* \par Returns
|
||||
* Whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed() { return ex.closed(); }
|
||||
|
||||
/**
|
||||
* \par 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.
|
||||
*
|
||||
* \par Synchronization
|
||||
* Ccompletion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \par 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) {
|
||||
ex.submit(boost::move(closure));
|
||||
}
|
||||
// void submit(work& closure) {
|
||||
// ex.submit(closure);
|
||||
// }
|
||||
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Try to execute one task.
|
||||
*
|
||||
* \par Returns
|
||||
* Whether a task has been executed.
|
||||
*
|
||||
* \par Throws
|
||||
* Whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one() { return ex.try_executing_one(); }
|
||||
|
||||
};
|
||||
|
||||
class generic_executor_ref
|
||||
{
|
||||
shared_ptr<executor> ex;
|
||||
public:
|
||||
/// type-erasure to store the works to do
|
||||
typedef executors::work work;
|
||||
|
||||
template<typename Executor>
|
||||
generic_executor_ref(Executor& ex)
|
||||
//: ex(make_shared<executor_ref<Executor> >(ex)) // todo check why this doesn't works with C++03
|
||||
: ex( new executor_ref<Executor>(ex) )
|
||||
{
|
||||
}
|
||||
|
||||
//generic_executor_ref(generic_executor_ref const& other) noexcept {}
|
||||
//generic_executor_ref& operator=(generic_executor_ref const& other) noexcept {}
|
||||
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Close the \c executor for submissions.
|
||||
* The worker threads will work until there is no more closures to run.
|
||||
*/
|
||||
void close() { ex->close(); }
|
||||
|
||||
/**
|
||||
* \par Returns
|
||||
* Whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed() { return ex->closed(); }
|
||||
|
||||
void submit(BOOST_THREAD_RV_REF(work) closure)
|
||||
{
|
||||
ex->submit(boost::forward<work>(closure));
|
||||
}
|
||||
|
||||
/**
|
||||
* \par Requires
|
||||
* \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \par 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.
|
||||
*
|
||||
* \par Synchronization
|
||||
* Completion of closure on a particular thread happens before destruction of thread's thread local variables.
|
||||
*
|
||||
* \par 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));
|
||||
}
|
||||
|
||||
// size_t num_pending_closures() const
|
||||
// {
|
||||
// return ex->num_pending_closures();
|
||||
// }
|
||||
|
||||
/**
|
||||
* \par Effects
|
||||
* Try to execute one task.
|
||||
*
|
||||
* \par Returns
|
||||
* Whether a task has been executed.
|
||||
*
|
||||
* \par Throws
|
||||
* Whatever the current task constructor throws or the task() throws.
|
||||
*/
|
||||
bool try_executing_one() { return ex->try_executing_one(); }
|
||||
|
||||
/**
|
||||
* \par Requires
|
||||
* This must be called from an scheduled task.
|
||||
*
|
||||
* \par 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_ref;
|
||||
using executors::generic_executor_ref;
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
171
include/boost/thread/executors/inline_executor.hpp
Normal file
171
include/boost/thread/executors/inline_executor.hpp
Normal file
@@ -0,0 +1,171 @@
|
||||
// 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_;
|
||||
mutable mutex mtx_;
|
||||
/**
|
||||
* 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()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
closed_ = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Returns: whether the pool is closed for submissions.
|
||||
*/
|
||||
bool closed(lock_guard<mutex>& )
|
||||
{
|
||||
return closed_;
|
||||
}
|
||||
bool closed()
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
return closed(lk);
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
|
||||
*
|
||||
* \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)
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lk(mtx_);
|
||||
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
|
||||
}
|
||||
try
|
||||
{
|
||||
closure();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::terminate();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \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
|
||||
199
include/boost/thread/executors/loop_executor.hpp
Normal file
199
include/boost/thread/executors/loop_executor.hpp
Normal file
@@ -0,0 +1,199 @@
|
||||
// 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
|
||||
concurrent::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::terminate();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* The main loop of the worker thread
|
||||
*/
|
||||
void loop()
|
||||
{
|
||||
while (!closed())
|
||||
{
|
||||
schedule_one_or_yield();
|
||||
}
|
||||
while (try_executing_one())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* \b Effects: close the \c loop_executor for submissions.
|
||||
* The loop will work until there is no more closures to run.
|
||||
*/
|
||||
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_queue.push_back(work(closure));
|
||||
}
|
||||
#endif
|
||||
void submit(void (*closure)())
|
||||
{
|
||||
work_queue.push_back(work(closure));
|
||||
}
|
||||
|
||||
template <typename Closure>
|
||||
void submit(BOOST_THREAD_RV_REF(Closure) closure)
|
||||
{
|
||||
work_queue.push_back(work(boost::forward<Closure>(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& 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();
|
||||
task();
|
||||
q.pop_front();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
using executors::loop_executor;
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user