2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 09:42:16 +00:00

Compare commits

..

168 Commits

Author SHA1 Message Date
Vicente J. Botet Escriba
a8ad389bdd Merge branch 'develop' into feature/task_region 2014-11-06 07:42:36 +01:00
Vicente J. Botet Escriba
69c1d40750 Merge branch 'develop' into feature/promise_set_value_emplace 2014-11-05 23:43:02 +01:00
Vicente J. Botet Escriba
58698f44f1 More renamming and added some comments on scheduler.hpp. 2014-11-05 19:41:56 +01:00
Vicente J. Botet Escriba
37afdd2e9a Moved test_scheduler_p to a explicit test_suite. 2014-11-05 01:03:44 +01:00
Vicente J. Botet Escriba
c87b24923a Added scheduler at/after/on executor factory helper functions. 2014-11-05 00:41:29 +01:00
Vicente J. Botet Escriba
1210fc4859 Add missing include file. 2014-11-05 00:38:21 +01:00
Vicente J. Botet Escriba
d8b6ae6266 Ensure that the numbers of pools is at least 1. 2014-11-05 00:37:52 +01:00
Vicente J. Botet Escriba
04e2223d5e Minor renamming. 2014-11-04 22:51:25 +01:00
Vicente J. Botet Escriba
579748e7a0 Avoid locking while doing callback. 2014-11-04 22:48:57 +01:00
Vicente J. Botet Escriba
41c3914aaf Don't try-catch on try_executing_one_task. 2014-11-02 19:42:18 +01:00
Vicente J. Botet Escriba
8693eec4a4 Make submit strong-thread safe. 2014-11-02 19:41:57 +01:00
Vicente J. Botet Escriba
3f699750a8 Avoid locking while doing callback. 2014-11-02 19:41:42 +01:00
Vicente J. Botet Escriba
4f8243cf59 Remove waiting_empty_. 2014-11-02 19:41:25 +01:00
Vicente J. Botet Escriba
4f01891da7 Added not_ready and timeout queue_op_status. Make sync_timed_queue and sync_priority_queue conform to the sync_queue interface. Aapt the test to the new interface. 2014-11-02 15:13:37 +01:00
Vicente J. Botet Escriba
efab5af918 Fix inspection issue. 2014-11-02 15:11:28 +01:00
Vicente J. Botet Escriba
4d03b410a8 Update executors doc adding thread executor. 2014-11-02 15:10:15 +01:00
Vicente J. Botet Escriba
c1925df81c Fix task exception silently ignored. Make submit throw if closed. join the threads created by the thread_executor 2014-11-02 15:09:11 +01:00
Vicente J. Botet Escriba
cbf9fe8a5c Fix inspection issues. 2014-11-02 15:08:44 +01:00
Vicente J. Botet Escriba
6fd7dc0d94 Added move semantics for C++11 compilers. Need of a detail::priority_queue. Tried to do it for C++98, but heap_push/heap_pop algorithms are not move aware:(. 2014-11-01 22:18:32 +01:00
Vicente J. Botet Escriba
a2f2924298 Added missing file sync_queue_base and refactor the concurrent queues to make use of this class. 2014-11-01 22:18:09 +01:00
Vicente J. Botet Escriba
49d485f1aa Removed BOOST_THREAD_QUEUE_DEPRECATE_OLD for priority and timed queues. 2014-11-01 11:21:09 +01:00
Vicente J. Botet Escriba
d7251f223e Added sync_queue_base and refactor the concurrent queues to make use of this class. Make other refactor on priority and timed queues. 2014-11-01 11:02:18 +01:00
Vicente J. Botet Escriba
20a6ef7de8 Added wait_until_not_empty, wait_until_not_empty_or_closed. Rename _q_qempty to _not_empty. 2014-11-01 01:14:41 +01:00
Vicente J. Botet Escriba
d5c41e4c4a Added tyy_pus returning queue_op_status. Rename is_closed to closed. 2014-10-31 23:49:34 +01:00
Vicente J. Botet Escriba
b96b9904b7 move scheduled_executor_base.hpp and declare scheduled_thread_pool::worker_loop inline. 2014-10-31 08:21:27 +01:00
Vicente J. Botet Escriba
304240b206 Move priority/timed queues to concurrent name space and scheduled executors to executors name spapce. 2014-10-31 08:03:15 +01:00
Vicente J. Botet Escriba
c61c139933 merged scheduled executors GSOC project from Ian Forbed. 2014-10-31 00:19:10 +01:00
Vicente J. Botet Escriba
c3b98129e4 Added task_region documentation. 2014-10-26 19:44:32 +01:00
Vicente J. Botet Escriba
3891eeef52 fix issue with C++98 exception library. 2014-10-26 19:43:47 +01:00
Vicente J. Botet Escriba
f1370b1255 Added a task_region_handle_gen that referes to an existing executor, so that we don't create one each time. 2014-10-26 15:17:25 +01:00
Vicente J. Botet Escriba
69f2a1df72 Added fib_task_region example and allows to work without executors. 2014-10-26 13:21:25 +01:00
Vicente J. Botet Escriba
700301e382 Added exception_list and task_region. 2014-10-26 11:27:18 +01:00
Vicente J. Botet Escriba
952aa44a98 Added promise::emplace and variadic make_ready_future. 2014-10-25 23:31:09 +02:00
Vicente J. Botet Escriba
5fb51a74fe remove thread_was_interrupted and fix wait_internal pending issue. 2014-10-24 18:43:26 +02:00
Vicente J. Botet Escriba
02bb6abef4 Merge pull request #29 from awulkiew/patch-1
Change members order in win32 thread_data_base to match ctor initializer...
2014-10-23 00:39:04 +02:00
Adam Wulkiewicz
1a4bd71616 Change members order in win32 thread_data_base to match ctor initializer list. 2014-10-23 00:01:37 +02:00
Vicente J. Botet Escriba
63dd439992 update history. 2014-10-12 16:28:29 +02:00
Vicente J. Botet Escriba
1029fa9c59 take in account deferred/ready futures on variadic when_all/when_any. 2014-10-12 15:47:16 +02:00
Vicente J. Botet Escriba
3e28ea806c Added deferred then tests. 2014-10-11 07:33:57 +02:00
Vicente J. Botet Escriba
07dc40a9ff Added missing boost/config.hpp file when checking for BOOST_NO_CXX11_DECLTYPE. 2014-10-09 06:51:02 +02:00
Vicente J. Botet Escriba
6f91af2154 Try to address #9569. 2014-10-05 09:11:58 +02:00
Vicente J. Botet Escriba
c3cff80557 Merge branch 'develop' of github.com:boostorg/thread into develop 2014-10-05 09:07:18 +02:00
Vicente J. Botet Escriba
729c8b63bb added missing file. 2014-10-05 09:06:52 +02:00
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com)
6fe7f44ea0 Clarified issue #6782 which can now be closed. 2014-10-04 19:47:48 +01:00
Vicente J. Botet Escriba
8fd4755e79 Added shared_future::then executor. 2014-10-04 10:36:57 +02:00
Vicente J. Botet Escriba
02b007a20e Make nullary_function copyable and movable following Boost.Move. Make use of std::shared_ptr when available. 2014-10-04 10:36:44 +02:00
Vicente J. Botet Escriba
c0c78e87fc Make invoker copyable and movable following Boost.Move. 2014-10-04 10:36:31 +02:00
Vicente J. Botet Escriba
58cde5af05 Trying to use std::function for executors::work. This doesn't works yet. 2014-10-03 21:46:57 +02:00
Vicente J. Botet Escriba
c1f2c8a1f1 Added shared_ptr.hpp. 2014-10-03 21:43:50 +02:00
Vicente J. Botet Escriba
bacf5b52ec The added commented lines should work, but don't. 2014-10-03 21:42:42 +02:00
Vicente J. Botet Escriba
3babf7966e update doc for future/shared_future::then(Executor, Fct). 2014-10-02 22:34:47 +02:00
Vicente J. Botet Escriba
f3de7bf10f Add fuutre::then(ex, fct). 2014-10-02 07:36:52 +02:00
Vicente J. Botet Escriba
90154217cf Added const to shred_future::then(). 2014-10-01 08:34:34 +02:00
Vicente J. Botet Escriba
ac0b2f9ba7 minor changes to unwrap. 2014-10-01 07:55:36 +02:00
Vicente J. Botet Escriba
da739e680a Merge pull request #27 from Lastique/patch-4
Fix GCC warnings about initialization order
2014-09-30 23:54:06 +02:00
Andrey Semashev
b240b097c7 Fix GCC warnings about initialization order 2014-09-30 22:42:13 +04:00
Vicente J. Botet Escriba
debe2fb0d1 Merge pull request #26 from Lastique/patch-3
Fix compilation with BOOST_USE_WINDOWS_H defined
2014-09-30 20:38:35 +02:00
Andrey Semashev
b264ec8fc0 Fix compilation with BOOST_USE_WINDOWS_H defined
Don't use macros defined only in Windows SDK 6.0 and later as this breaks compilation with MinGW and older MSVC.
2014-09-30 22:17:44 +04:00
Vicente J. Botet Escriba
372f8fe10f Merge branch 'develop' of github.com:boostorg/thread into develop 2014-09-29 23:22:16 +02:00
Vicente J. Botet Escriba
e3c240df0a shared_future<R>::then() should be const. 2014-09-29 23:22:03 +02:00
Niall Douglas
748ea5164e Merge pull request #25 from MarcelRaad/patch-1
Fix GetTickCount return type
2014-09-29 19:18:38 +01:00
Vicente J. Botet Escriba
b44627f97d don't use std::queue with MSVC 11. 2014-09-29 00:19:35 +02:00
Vicente J. Botet Escriba
c8cd7d1d08 don't check for is_ready on all the futures when using when_wny. 2014-09-29 00:19:18 +02:00
Vicente J. Botet Escriba
f0d0c0551b rollback to not define BOOST_RESULT_OF_USE_DECLTYPE. 2014-09-29 00:00:49 +02:00
Vicente J. Botet Escriba
bb72eadbd8 Added validation of invalid inner future in wrap. 2014-09-29 00:00:06 +02:00
Marcel Raad
f52f32afda Fix GetTickCount return type
int as a return type results in a signed/unsigned mismatch warning with MSVC (although disabled by default), and it doesn't even compile with clang-cl if the definiton from the Windows header was included before.
2014-09-28 21:25:36 +02:00
Vicente J. Botet Escriba
b973e9b32e remove BOOST_THREAD_NO_CXX11_DECLTYPE_N3276. 2014-09-28 13:46:21 +02:00
Vicente J. Botet Escriba
1ffef9ed2d Add missing invoke.hpp include. 2014-09-28 13:40:16 +02:00
Vicente J. Botet Escriba
f24ea524bd Remove confusing may be remark and replace T by FutTypes. 2014-09-28 11:55:35 +02:00
Vicente J. Botet Escriba
4111471ba5 fix typo on file guard. 2014-09-28 09:19:42 +02:00
Vicente J. Botet Escriba
5e970b987e remove warning. 2014-09-28 00:34:15 +02:00
Vicente J. Botet Escriba
c7b5729cf3 Avoid the use fo invoke if not available, even if the semantics is not the same. 2014-09-27 19:59:25 +02:00
Vicente J. Botet Escriba
291ebded8e update changes and compliance with last fixed issues. 2014-09-27 19:58:17 +02:00
Vicente J. Botet Escriba
0c2c8ed3b8 Update doc with last modifications from Concurrent TS. 2014-09-27 19:57:33 +02:00
Vicente J. Botet Escriba
5294dfa149 Update doc with last modifications from Concurrent TS. 2014-09-27 16:45:39 +02:00
Vicente J. Botet Escriba
7f5dfb633d MSVC 10 doesn't provide std::is_copy_constructible. Make use of the boost version. 2014-09-26 06:48:40 +02:00
Vicente J. Botet Escriba
f381a7d591 Don't delete copy constructor when rvalue references are disabled. 2014-09-25 07:25:39 +02:00
Vicente J. Botet Escriba
aceabda609 try to avoid to unlock prematurely to see if this is the cause of the test_latch spourious failure. 2014-09-24 08:09:40 +02:00
Vicente J. Botet Escriba
dc4b619b57 Don't delete copy constructor when rvalue references are disabled. 2014-09-23 23:34:42 +02:00
Vicente J. Botet Escriba
abb3fc97e0 fix reported error. 2014-09-23 23:30:26 +02:00
Vicente J. Botet Escriba
ec6ae7b9b4 Take in account small durations. 2014-09-23 23:29:38 +02:00
Vicente J. Botet Escriba
8c5ba97d39 Don't use lambdas on test if not available. 2014-09-21 18:59:08 +02:00
Vicente J. Botet Escriba
617b979214 try a workaround with MSVC for error C3520: 'T' : parameter pack must be expanded in this context. 2014-09-21 18:58:41 +02:00
Vicente J. Botet Escriba
96667cfcce MSVC 10 doesn't provide std::is_move_constructible. Let as if all classes were movable in this case. 2014-09-21 18:58:23 +02:00
Vicente J. Botet Escriba
a981650ce9 cleanup. 2014-09-20 16:11:03 +02:00
Vicente J. Botet Escriba
00b25853b2 Added when_all/when_any iterators tests. 2014-09-20 16:05:19 +02:00
Vicente J. Botet Escriba
ef04ce8bce enable disabled test. 2014-09-20 14:53:06 +02:00
Vicente J. Botet Escriba
5091ad705f Added when_any/variadic_pass.cpp. 2014-09-20 14:37:47 +02:00
Vicente J. Botet Escriba
b77f802c47 variadic when_all/when_any must retur tuple instead of vector even when all the types are the same.. 2014-09-20 13:25:50 +02:00
Vicente J. Botet Escriba
da945436c1 avoid call to boost::get_system_time() when relative is true. 2014-09-14 21:51:01 +02:00
Vicente J. Botet Escriba
27befdf26f Added test for threads_specific_ptr<void>. 2014-09-14 21:49:31 +02:00
Vicente J. Botet Escriba
f73007910a replace unique_ptr<T> by optional<T> on shared_state when rvalue references are supported by the compiler, as optional<T> doesn't use Boost.Move. 2014-09-14 21:12:44 +02:00
Vicente J. Botet Escriba
8c3cfacf06 emulate template alias queue views. 2014-09-14 21:00:27 +02:00
Vicente J. Botet Escriba
7d4392e157 try to get rid of missing std::is_copy_constructible < gcc-4.5. 2014-09-14 09:09:59 +02:00
Vicente J. Botet Escriba
aff3f424a9 move sync_queue_closed to concurrent directory. 2014-09-13 22:17:19 +02:00
Vicente J. Botet Escriba
546ca909c4 try to avoid issue with < gcc-4.5 - error: 'is_copy_constructible' is not a member of 'std'. 2014-09-13 22:16:57 +02:00
Vicente J. Botet Escriba
7dac51706c Merge branch 'develop' 2014-09-12 23:40:30 +02:00
Vicente J. Botet Escriba
5ee0e27b5a add more try catch to trac the source of the error. 2014-09-12 22:50:56 +02:00
Vicente J. Botet Escriba
b4fd7fdeb1 fail test when exception cautch instead of rethrow it. 2014-09-11 13:33:43 +02:00
Vicente J. Botet Escriba
c75ea7db89 force the use of lambdas when available on multi_thread_pass test. 2014-09-11 13:32:11 +02:00
Vicente J. Botet Escriba
19294dc756 Change ref by ptr on queue fields of queue_views so that the default constructors can be generated on MSVC. 2014-09-11 13:30:48 +02:00
Vicente J. Botet Escriba
52a360775e cleanup. 2014-09-11 07:32:40 +02:00
Vicente J. Botet Escriba
c632b75db1 fix uninitialized variable. 2014-09-11 07:29:53 +02:00
Vicente J. Botet Escriba
11e4c950ac fix 10478 data race in boost/thread/future.hpp 2014-09-10 13:44:44 +02:00
Vicente J. Botet Escriba
8440e9a7d8 add tests on non_intettuption_point::sleep_... 2014-09-10 13:42:15 +02:00
Vicente J. Botet Escriba
02bc292c20 document non_intettuption_point::sleep_... 2014-09-10 13:41:11 +02:00
Vicente J. Botet Escriba
6d68bac44b fix move semantic issues on promise::set_value. Prepare the use of unique_ptr<T,D> to fix allocator issue. 2014-09-09 13:21:01 +02:00
Vicente J. Botet Escriba
5d0d128cab let movelib do the std adaptation. 2014-09-09 13:15:51 +02:00
Vicente J. Botet Escriba
ec542d3c8b remove commented code. 2014-09-08 05:49:10 +02:00
Vicente J. Botet Escriba
6e3216643b Remove future_traits<> as there are always an specialization. 2014-09-07 19:46:02 +02:00
Vicente J. Botet Escriba
016f5653cf Added when_all().then() tests. 2014-09-07 09:04:00 +02:00
Vicente J. Botet Escriba
ce46539183 Added when_all/when_any/queue_views tests. 2014-09-06 23:30:50 +02:00
Vicente J. Botet Escriba
e93035ce42 Added run_if_is_deferred to shared_future. 2014-09-06 23:30:36 +02:00
Vicente J. Botet Escriba
53a46593a8 make classes using BOOST_THREAD_MOVABLE_ONLY<T> satisfy is_copy_constructible<T>::value == false. 2014-09-06 14:20:59 +02:00
Vicente J. Botet Escriba
c2426b8fad fix missin common virtual function in queue_base_copyable_only. 2014-09-06 14:19:37 +02:00
Vicente J. Botet Escriba
7d841f6337 fix typo. 2014-09-06 14:18:36 +02:00
Vicente J. Botet Escriba
556bbde8a7 Implemented when_all/when_any when a tuple is returned. 2014-09-04 20:00:03 +02:00
Vicente J. Botet Escriba
a0c1462a6a merge from develop. 2014-09-02 21:41:59 +02:00
Vicente J. Botet Escriba
234df13faf remove BOOST_THREAD_USES_LOG. 2014-09-01 19:59:30 +02:00
Vicente J. Botet Escriba
24983f0bce Let the deferred tests be executed when BOOST_THREAD_PROVIDES_VARIADIC_THREAD is defined. 2014-08-31 20:05:43 +02:00
Vicente J. Botet Escriba
722997379b Added thread pool join function. 2014-08-31 18:16:49 +02:00
Vicente J. Botet Escriba
f36f5d6dbb Added more async deferred tests. 2014-08-31 18:16:14 +02:00
Vicente J. Botet Escriba
9ee1044f92 Merge branch 'develop' of github.com:boostorg/thread into develop 2014-08-31 09:00:04 +02:00
Vicente J. Botet Escriba
ebeb36646c Add test for issue #10340. 2014-08-31 08:59:40 +02:00
Vicente J. Botet Escriba
8ebf0e7f21 take in account ready tasks on when_all/when_any. 2014-08-31 08:57:27 +02:00
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com)
0dc2f69bc1 Fixed typo in just made merge for WinRT support. 2014-08-30 18:58:43 +01:00
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com)
c3b549d947 Merge branch 'MSOpenTech-winrt2' into develop 2014-08-30 18:24:46 +01:00
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com)
6552cf64b5 Fixed up WinRT support patch not compiling on WinRT. 2014-08-30 18:24:13 +01:00
Niall Douglas (s [underscore] sourceforge {at} nedprod [dot] com)
d5f335b8a4 Merge branch 'winrt2' of https://github.com/MSOpenTech/thread into MSOpenTech-winrt2 2014-08-30 17:16:17 +01:00
Vicente J. Botet Escriba
80591fb64d try to fix 10428 for uinque_ptr issues. 2014-08-30 17:57:12 +02:00
Vicente J. Botet Escriba
0543b522cb try to fix 10340. 2014-08-30 17:54:12 +02:00
Vicente J. Botet Escriba
3dbc5d0664 Added when_all/when_any documentation. 2014-08-30 13:43:42 +02:00
Vicente J. Botet Escriba
2d0272345b update doc cith generic executor and queue views. 2014-08-30 10:07:08 +02:00
Vicente J. Botet Escriba
f1a274b51c make it possible to have polymorphic queue copyable_only/movable_only/copyable_and_movable. 2014-08-29 21:06:15 +02:00
Vicente J. Botet Escriba
b7f1706ab8 Add test won when_all iterators for c++98 compilers. 2014-08-29 21:04:33 +02:00
Vicente J. Botet Escriba
f299fb8083 fix typo. 2014-08-29 12:51:42 +02:00
Vicente J. Botet Escriba
074dcbcbf5 make polymorphic queues move operations only available if C++11 RVALE supported. 2014-08-28 22:26:02 +02:00
Vicente J. Botet Escriba
af6f80a3c7 Added generic_executor_ref.cpp tp regression tests. 2014-08-27 13:36:58 +02:00
Vicente J. Botet Escriba
957253401f Try to fix invoker making it ComyConstructible and Movable. 2014-08-27 13:35:59 +02:00
Vicente J. Botet Escriba
3195253230 rollback last merge as it is breaking all the regression tests. 2014-08-27 00:16:19 +02:00
Vicente J. Botet Escriba
4336a7bbe3 Merge pull request #24 from MarcelRaad/patch-1
Use BOOST_THREAD_RV_REF for move constructors
2014-08-26 18:44:38 +02:00
Marcel Raad
3b75d6dabc Use BOOST_THREAD_RV_REF for move constructors
If BOOST_THREAD_FWD_REF is used, the copy constructor is re-declared. Tested with clang 3.4.
2014-08-26 10:17:26 +02:00
Vicente J. Botet Escriba
fc0d7e23b3 remove todo comments. 2014-08-25 17:17:50 +02:00
Vicente J. Botet Escriba
aeabda8d45 make use of move when a rvalue is used and make use of BOOST_THREAD_FWD_REF when a URef is used. 2014-08-24 22:48:06 +02:00
Vicente J. Botet Escriba
3bde7e103c Added virtual submit(work&). 2014-08-24 18:17:59 +02:00
Vicente J. Botet Escriba
ea0889485e Make use of BOOST_THREAD_COPYABLE_AND_MOVABLE and BOOST_THREAD_COPY_ASSIGN_REF when appropriated. 2014-08-24 18:16:28 +02:00
Vicente J. Botet Escriba
d4d46c64dd fix loop_executor run_queued_closures issue. 2014-08-23 19:14:21 +02:00
Vicente J. Botet Escriba
f3fa80c866 Added generic_executor_ref, queue_base and queue views, fix some issues in executors. 2014-08-23 18:29:47 +02:00
Vicente J. Botet Escriba
7e21f24991 Merge branch 'develop' of github.com:boostorg/thread into develop 2014-08-21 19:18:56 +02:00
Vicente J. Botet Escriba
2037a64c51 Avoid pedantic clang watnings. 2014-08-21 19:17:27 +02:00
Vicente J. Botet Escriba
8bfd1cea31 fix typo. 2014-08-21 19:16:41 +02:00
Niall Douglas
a26e7eb8c4 Merge pull request #22 from eldiener/master
For clang turn warnings to 'on' and remove '-pedantic' to avoid Boost PP...
2014-08-05 10:10:05 +01:00
Edward Diener
e47eba8751 For clang turn warnings to 'on' and remove '-pedantic' to avoid Boost PP warnings. 2014-08-04 19:30:29 -04:00
Eric Niebler
8aef8000d9 Merge branch 'master' into develop 2014-08-03 12:12:27 -07:00
Niall Douglas
78f1044c68 The previous mingw32 fix unfortunately broke mingw-w64, so that is now fixed too. 2014-08-02 21:38:31 +01:00
Niall Douglas
26042ca26a Fixed mingw32 compile breakage. 2014-08-02 18:56:08 +01:00
Vicente J. Botet Escriba
74132067ba prepare tss<void>. 2014-07-31 19:29:19 +02:00
Vicente J. Botet Escriba
c4d42e6b6c make use of wait_pull_front instead of pull_front. 2014-07-31 19:28:04 +02:00
Vicente J. Botet Escriba
59c504d5d8 Merge pull request #21 from Lastique/patch-3
Fixed compilation with gcc 4.6 in C++11 mode
2014-07-31 07:11:42 +02:00
Andrey Semashev
b81a838a43 Fixed compilation with gcc 4.6 in C++11 mode
The compiler considers invoke() call ambiguous when the function object is actually a function pointer. This caused compilation errors in Boost.Coroutine, which uses invoke() through call_once(). Also added missing includes.
2014-07-31 02:27:33 +04:00
Steve Gates
a06dde3794 Merge branch 'develop' into winrt2
Conflicts:
	include/boost/thread/win32/thread_primitives.hpp
	src/win32/gettickcount64.cpp
2014-07-18 12:19:46 -07:00
Steve Gates
726a3faf19 Removing QueueUserAPC on Windows Runtime. 2014-07-17 10:49:09 -07:00
Steve Gates
c977c8d420 Qualifying some functions calls in thread_primitives.hpp to avoid potentially ambiguity. 2014-07-10 18:09:24 -07:00
Steve Gates
a1faacd7bb Fixing up copyrights that got reordered. 2014-07-09 16:43:48 -07:00
Steve Gates
866b78cbd0 Addressing more feedback:
Reverting disabling thread attributes for WinRT.
Created common GetSystemInfo/GetNativeSystemInfo function.
Fix this_thread get_id() bug on WinRT.
Enabled initializing the Windows Runtime in each test for execution. This
is not when using in Windows store/phone applications, just if a desktop
app.
2014-07-09 15:47:37 -07:00
Steve Gates
0861f81b05 Merge branch 'develop' of https://github.com/boostorg/thread into feedback 2014-07-08 14:53:47 -07:00
Steve Gates
6488028a22 Incorporating feedback: removed copyright, removed some ifdefs. 2014-07-08 14:53:39 -07:00
Steve Gates
9ceea9822f Enabling Boost.Thread to be used in the Windows Runtime.
This involves basically 3 changes:
1. Using __declspec(thread) instead of the Tls APIs.
2. Using Windows::System::Threading since Win32 Threading APIs aren't allowed.
3. Updating or replacing some banned APIs like WaitForSingleObject with WaitForSingleObjectEx.
2014-07-02 14:21:43 -07:00
143 changed files with 13437 additions and 3094 deletions

40
.gitignore vendored Normal file
View 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

View File

@@ -78,12 +78,12 @@ 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

View File

@@ -1,13 +1,13 @@
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
//
// Use modification and distribution are subject to the boost Software
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
#include "../../../boost/atomic.hpp"
#include "../../../boost/static_assert.hpp"
// Copyright (c) 2013, Petr Machata, Red Hat Inc.
//
// Use modification and distribution are subject to the boost Software
// License, Version 1.0. (See http://www.boost.org/LICENSE_1_0.txt).
int main(int argc, char *argv[])
{
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
return 0;
}
#include "../../../boost/atomic.hpp"
#include "../../../boost/static_assert.hpp"
int main(int argc, char *argv[])
{
BOOST_STATIC_ASSERT(BOOST_ATOMIC_FLAG_LOCK_FREE);
return 0;
}

View File

@@ -10,7 +10,7 @@
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from tis paper to show the differences.]
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3785.pdf [*N3785 - Executors and Schedulers revision 3]] C++1y proposal from Chris Mysen, Niklas Gustafsson, Matt Austern, Jeffrey Yasskin. The text that follows has been adapted from this paper to show the differences.]
Executors are objects that can execute units of work packaged as function objects. Boost.Thread differs from N3785 mainly in the an Executor doesn't needs to inherit from an abstract class Executor. Static polymorphism is used instead and type erasure is used internally.
@@ -122,27 +122,26 @@ An Executor is an object that schedules the closures that have been submitted to
* The choice of which executor to use is explicit. This is important for reasons described in the Motivation section. In particular, consider the common case of an asynchronous operation that itself spawns asynchronous operations. If both operations ran on the same executor, and if that executor had a bounded number of worker threads, then we could get deadlock. Programs often deal with such issues by splitting different kinds of work between different executors.
* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable a robust way.
* Even if there could be a strong value in having a default executor, that can be used when detailed control is unnecessary, the authors don't know how to implement it in a portable and robust way.
* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is suing without making it a template and it possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
* The library provides Executors based on static and dynamic polymorphism. The static polymorphism interface is intended to be used on contexts that need to have the best performances. The dynamic polymorphism interface has the advantage to been able to change the executor a function is using without making it a template and is possible to pass executors across a binary interface. For some applications, the cost of an additional virtual dispatch could be almost certainly negligible compared to the other operations involved.
* Conceptually, an executor puts closures on a queue and at some point executes them. The queue is always unbounded, so adding a closure to an executor never blocks. (Defining “never blocks” formally is challenging, but informally we just mean that submit() is an ordinary function that executes something and returns, rather than waiting for the completion of some potentially long running operation in another thread.)
[heading Closure]
One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `voidv.
One important question is just what a closure is. This library has a very simple answer: a closure is a `Callable` with no parameters and returning `void`.
N3785 choose the more specific `std::function<void()>` as it provides only dynamic polymorphism and states that in practice the implementation of a template based approach or another approach is impractical. The authors of this library think that the template based approach is compatible with a dynamic based approach. They give some arguments:
The first one is that a virtual function can not be a template. This is true but it is also true that the executor interface can provide the template functions that call to the virtual public functions. Another reason they give is that "a template parameter would complicate the interface without adding any real generality. In the end an executor class is going to need some kind of type erasure to handle all the different kinds of function objects with `void()` signature, and thats exactly what std::function already does". We think that it is up to the executor to manage with this implementation details, not to the user.
We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what is needs.
We share all the argument they give related to the `void()` interface of the work unit. A work unit is a closure that takes no arguments and returns no value. This is indeed a limitation on user code, but combined with `boost::async` taking executors as parameters the user has all what she needs.
The third one is related to performance. They assert that "any mechanism for storing closures on an executors queue will have to use some form of type erasure. Theres no reason to believe that a custom closure mechanism, written just for std::executor and used nowhere else within the standard library, would be better in that respect than `std::function<void()>`". We believe that the implementation can do better that storing the closure on a `std::function<void()>`. e.g. the implementation can use intrusive data to store the closure and the pointers to other nodes needed to store the closures in a given order.
In addition `std::function<void()>` can not be constructed by moving the closure, so e.g. `std::packaged_task` could not be a Closure.
[/
[heading Scheduled work]
The approach of this library respect to scheduled work of the N3785 proposal is quite different. Instead of adding the scheduled operations to a specific scheduled_executor polymorphic interface, we opt by adding two member template functions to a class scheduled_executor that wraps an existing executor. This has several advantages:
@@ -156,7 +155,6 @@ In order to manage with all the clocks, there are two alternatives:
* have a single instance of a `scheduled_executor<Clock>` for each `CLock`.
The library chose the first of those options, largely for simplicity.
]
[heading Not Handled Exceptions]
As in N3785 and based on the same design decision than `std`/`boost::thread` if a user closure throws an exception, the executor must call the `std::terminate` function.
@@ -166,7 +164,7 @@ Note that when we combine `boost::async` and `Executors`, the exception will be
It is common idiom to set some thread local variable at the beginning of a thread. As Executors could instantiate threads internally these Executors shall have the ability to call a user specific function at thread entry on the executor constructor.
For executors that don't instantiate any thread an that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
For executors that don't instantiate any thread and that would use the current thread this function shall be called only for the thread calling the `at_thread_entry` member function.
[heading Cancelation]
@@ -182,49 +180,108 @@ An alternative is to make async return a cancelable_task but this will need also
[/
The library would provide in the future a cancelable_task that could support cancelation.
class cancelation_state {
std::atomic<bool> requested; std::atomic<bool> enabled; std::condition_variable* cond; std::mutex cond_mutex;
public:
cancelation_state(): thread_cond(0) {} void cancel() { requested.store(true,std::memory_order_relaxed); std::lock_guard<std::mutex> lk(cond_mutex); if(cond) { cond->notify_all(); } } bool cancellation_requested() const { return requested.load(std::memory_order_relaxed); }
void enable() { enable.store(true,std::memory_order_relaxed); } void disable() { enable.store(false,std::memory_order_relaxed); } bool cancellation_enabled() const { return enabled.load(std::memory_order_relaxed); } void set_condition_variable(std::condition_variable& cv) { std::lock_guard<std::mutex> lk(cond_mutex); cond = &cv; } void clear_condition_variable() { std::lock_guard<std::mutex> lk(cond_mutex); cond = 0; } struct clear_cv_on_destruct { ~clear_cv_on_destruct() { this_thread_interrupt_flag.clear_condition_variable(); } };
void cancelation_point();
void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk) { cancelation_point(); this_cancelable_state.set_condition_variable(cv); this_cancelable_state::clear_cv_on_destruct guard; interruption_point();
cv.wait_for(lk, std::chrono::milliseconds(1)); this_cancelable_state.clear_condition_variable(); cancelation_point(); }
class disable_cancelation
{
public:
disable_cancelation(const disable_cancelation&) = delete;
disable_cancelation& operator=(const disable_cancelation&) = delete;
disable_cancelation(cancelable_closure& closure) noexcept;
~disable_cancelation() noexcept;
};
class restore_cancelation
{
public:
restore_cancelation(const restore_cancelation&) = delete;
restore_cancelation& operator=(const restore_cancelation&) = delete;
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
~restore_cancelation() noexcept;
};
};
template <class Closure>
struct cancelable_closure_mixin : cancelable_closure {
void operator() {
cancel_point();
this->Closure::run();
}
};
struct my_clousure : cancelable_closure_mixin<my_clousure>
class cancelation_state
{
void run() {
while () {
cancel_point();
}
}
std::atomic<bool> requested;
std::atomic<bool> enabled;
std::condition_variable* cond;
std::mutex cond_mutex;
public:
cancelation_state() :
thread_cond(0)
{
}
void cancel()
{
requested.store(true, std::memory_order_relaxed);
std::lock_guard < std::mutex > lk(cond_mutex);
if (cond)
{
cond->notify_all();
}
}
bool cancellation_requested() const
{
return requested.load(std::memory_order_relaxed);
}
void enable()
{
enable.store(true, std::memory_order_relaxed);
}
void disable()
{
enable.store(false, std::memory_order_relaxed);
}
bool cancellation_enabled() const
{
return enabled.load(std::memory_order_relaxed);
}
void set_condition_variable(std::condition_variable& cv)
{
std::lock_guard < std::mutex > lk(cond_mutex);
cond = &cv;
}
void clear_condition_variable()
{
std::lock_guard < std::mutex > lk(cond_mutex);
cond = 0;
}
struct clear_cv_on_destruct
{
~clear_cv_on_destruct()
{
this_thread_interrupt_flag.clear_condition_variable();
}
};
void cancelation_point();
void cancelable_wait(std::condition_variable& cv, std::unique_lock<std::mutex>& lk)
{
cancelation_point();
this_cancelable_state.set_condition_variable(cv);
this_cancelable_state::clear_cv_on_destruct guard;
interruption_point();
cv.wait_for(lk, std::chrono::milliseconds(1));
this_cancelable_state.clear_condition_variable();
cancelation_point();
}
class disable_cancelation
{
public:
disable_cancelation(const disable_cancelation&)= delete;
disable_cancelation& operator=(const disable_cancelation&)= delete;
disable_cancelation(cancelable_closure& closure)
noexcept ;
~disable_cancelation() noexcept;
};
class restore_cancelation
{
public:
restore_cancelation(const restore_cancelation&) = delete;
restore_cancelation& operator=(const restore_cancelation&) = delete;
explicit restore_cancelation(cancelable_closure& closure, disable_cancelation& disabler) noexcept;
~restore_cancelation() noexcept;
};
};
template <class Closure>
struct cancelable_closure_mixin: cancelable_closure
{
void operator()
{
cancel_point();this->Closure::run();
}
};
struct my_clousure: cancelable_closure_mixin<my_clousure>
{
void run()
{
while ()
{
cancel_point();
}
}
}
]
[heading Current executor]
@@ -287,9 +344,6 @@ The `Executor` concept models the common operations of all the executors.
A type `E` meets the `Executor` requirements if the following expressions are well-formed and have the specified semantics
* `E::work`
* `e.submit(lw);`
* `e.submit(rw);`
* `e.submit(lc);`
* `e.submit(rc);`
* `e.close();`
@@ -300,50 +354,10 @@ A type `E` meets the `Executor` requirements if the following expressions are we
where
* `e` denotes a value of type `E`,
* `lw` denotes a lvalue referece of type `E::work`,
* `rc` denotes a rvalue referece of type `E::work`
* `lc` denotes a lvalue referece of type `Closure`,
* `rc` denotes a rvalue referece of type `Closure`
* `p` denotes a value of type `Predicate`
[/////////////////////////////////////]
[section:submitlw `e.submit(lw);`]
[variablelist
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
[[Return type:] [`void`.]]
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
]
[endsect]
[/////////////////////////////////////]
[section:submitrw `e.submit(rw);`]
[variablelist
[[Effects:] [The specified closure will be scheduled for execution at some point in the future.
If invoked closure throws an exception the executor will call std::terminate, as is the case with threads.]]
[[Synchronization:] [completion of closure on a particular thread happens before destruction of thread's thread local variables.]]
[[Return type:] [`void`.]]
[[Throws:] [sync_queue_is_closed if the thread pool is closed. Whatever exception that can be throw while storing the closure.]]
[[Exception safety:] [If an exception is thrown then the executor state is unmodified.]]
]
[endsect]
[/////////////////////////////////////]
[section:submitlc `e.submit(lc);`]
@@ -401,15 +415,16 @@ If invoked closure throws an exception the executor will call std::terminate, as
[endsect]
[/////////////////////////////////////]
[section:close `b = e.close();`]
[section:closed `b = e.closed();`]
[variablelist
[[Return type:] [`bool`.]]
[[Return:] [`void`.]]
[[Return:] [whether the pool is closed for submissions.]]
[[Throws:] [Whatever exception that can be throw while ensuring the thread safety.]]
[[Throws:] [whether the pool is closed for submissions.]]
]
@@ -433,7 +448,7 @@ If invoked closure throws an exception the executor will call std::terminate, as
[endsect]
[/////////////////////////////////////]
[section:try_executing_one `e.reschedule_until(p);`]
[section:reschedule_until `e.reschedule_until(p);`]
[variablelist
@@ -491,6 +506,7 @@ Executor abstract base class.
virtual bool closed() = 0;
virtual void submit(work&& closure) = 0;
virtual void submit(work& closure) = 0;
template <typename Closure>
void submit(Closure&& closure);
@@ -553,12 +569,13 @@ Polymorphic adaptor of a model of Executor to an executor.
template <typename ...Args>
executor_adaptor(Args&& ... args);
Executor& underlying_executor();
Executor& underlying_executor() noexcept;
void close();
bool closed();
void submit(work&& closure);
void submit(work& closure);
bool try_executing_one();
@@ -584,7 +601,7 @@ Polymorphic adaptor of a model of Executor to an executor.
[/////////////////////////////////////]
[section:destructor Destructor `~executor_adaptor()`]
virtual ~ executor_adaptor();
virtual ~executor_adaptor();
[variablelist
@@ -598,47 +615,78 @@ Polymorphic adaptor of a model of Executor to an executor.
[/////////////////////////////////////]
[section:underlying_executor Function member `underlying_executor()`]
Executor& underlying_executor();
Executor& underlying_executor() noexcept;
[variablelist
[[Return:] [The underlying executor instance. ]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[/
[/////////////////////////////////]
[section:generic_executor_ref Class `generic_executor_ref`]
Executor abstract base class.
#include <boost/thread/generic_executor_ref.hpp>
namespace boost {
class generic_executor_ref
{
public:
generic_executor_ref(generic_executor_ref const&);
generic_executor_ref& operator=(generic_executor_ref const&);
template <class Executor>
generic_executor_ref(Executor& ex);
generic_executor_ref() {};
void close() = 0;
bool closed() = 0;
template <typename Closure>
void submit(Closure&& closure);
virtual bool try_executing_one() = 0;
template <typename Pred>
bool reschedule_until(Pred const& pred);
};
}
[endsect]
[//////////////////////////////////////////////////////////]
[section:scheduled_executor Template Class `scheduled_executor`]
[section:scheduled_executor_ref Template Class `scheduled_executor_ref`]
Executor providing time related functions.
#include <boost/thread/scheduled_executor.hpp>
#include <boost/thread/executors/scheduled_executor_ref.hpp>
namespace boost {
template <class Executor>
class scheduled_executor
class scheduled_executor_ref
{
Executor& ex;
public:
typedef executor::work work;
scheduled_executor(scheduled_executor const&) = delete;
scheduled_executor& operator=(scheduled_executor const&) = delete;
scheduled_executor_ref(scheduled_executor_ref const&) = delete;
scheduled_executor_ref& operator=(scheduled_executor_ref const&) = delete;
template <class Rep, class Period>
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
scheduled_executor_ref(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
Executor& underlying_executor();
Executor& underlying_executor() noexcept;
void close();
bool closed();
void submit(work&& closure);
void submit(work& closure);
template <typename Closure>
void submit(Closure&& closure);
@@ -658,14 +706,14 @@ Executor providing time related functions.
}
[/////////////////////////////////////]
[section:constructor Constructor `scheduled_executor(Executor&, chrono::duration<Rep, Period>)`]
[section:constructor Constructor `scheduled_executor_ref(Executor&, chrono::duration<Rep, Period>)`]
template <class Rep, class Period>
scheduled_executor(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
scheduled_executor_ref(Executor& ex, chrono::duration<Rep, Period> granularity=chrono::milliseconds(100));
[variablelist
[[Effects:] [Constructs a scheduled_executor. ]]
[[Effects:] [Constructs a scheduled_executor_ref. ]]
[[Throws:] [Nothing. ]]
@@ -674,9 +722,9 @@ Executor providing time related functions.
[endsect]
[/////////////////////////////////////]
[section:destructor Destructor `~scheduled_executor()`]
[section:destructor Destructor `~scheduled_executor_ref()`]
~scheduled_executor();
~scheduled_executor_ref();
[variablelist
@@ -690,12 +738,29 @@ Executor providing time related functions.
[/////////////////////////////////////]
[section:underlying_executor Function member `underlying_executor()`]
Executor& underlying_executor();
Executor& underlying_executor() noexcept;
[variablelist
[[Return:] [The underlying executor instance. ]]
]
[endsect]
[/////////////////////////////////////]
[section:submit_at Template Function Member `submit_at()`]
template <class Clock, class Duration, typename Closure>
void submit_at(chrono::time_point<Clock,Duration> abs_time, Closure&& closure);
template <class Rep, class Period, typename Closure>
void submit_after(chrono::duration<Rep,Period> rel_time, Closure&& closure);
[variablelist
[[Effects:] [The underlying executor instance. ]]
[[Throws:] [Nothing.]]
]
@@ -703,11 +768,12 @@ Executor providing time related functions.
[endsect]
[endsect]
]
[//////////////////////////////////////////////////////////]
[section:scheduled_executor Template Class `serial_executor`]
[section:serial_executor Template Class `serial_executor`]
A serial executor ensuring that there are no two work units that executes concurrently.
@@ -716,21 +782,18 @@ A serial executor ensuring that there are no two work units that executes concur
template <class Executor>
class serial_executor
{
Executor& ex;
public:
typedef executors::work work;
serial_executor(serial_executor const&) = delete;
serial_executor& operator=(serial_executor const&) = delete;
template <class Executor>
serial_executor(Executor& ex);
Executor& underlying_executor();
Executor& underlying_executor() noexcept;
void close();
bool closed();
void submit(work&& closure);
template <typename Closure>
void submit(Closure&& closure);
@@ -742,8 +805,9 @@ A serial executor ensuring that there are no two work units that executes concur
}
[/////////////////////////////////////]
[section:constructor Constructor `serial_executor(Executor&, chrono::duration<Rep, Period>)`]
[section:constructor Constructor `serial_executor(Executor&)`]
template <class Executor>
serial_executor(Executor& ex);
[variablelist
@@ -773,7 +837,7 @@ A serial executor ensuring that there are no two work units that executes concur
[/////////////////////////////////////]
[section:underlying_executor Function member `underlying_executor()`]
Executor& underlying_executor();
generic_executor_ref& underlying_executor() noexcept;
[variablelist
@@ -788,6 +852,145 @@ A serial executor ensuring that there are no two work units that executes concur
[endsect]
[//////////////////////////////////////////////////////////]
[section:generic_serial_executor Class `generic_serial_executor`]
A serial executor ensuring that there are no two work units that executes concurrently.
#include <boost/thread/generic_serial_executor.hpp>
namespace boost {
class generic_serial_executor
{
public:
generic_serial_executor(generic_serial_executor const&) = delete;
generic_serial_executor& operator=(generic_serial_executor const&) = delete;
template <class Executor>
generic_serial_executor(Executor& ex);
generic_executor_ref& underlying_executor() noexcept;
void close();
bool closed();
template <typename Closure>
void submit(Closure&& closure);
bool try_executing_one();
template <typename Pred>
bool reschedule_until(Pred const& pred);
};
}
[/////////////////////////////////////]
[section:constructor Constructor `generic_serial_executor(Executor&)`]
template <class Executor>
generic_serial_executor(Executor& ex);
[variablelist
[[Effects:] [Constructs a serial_executor. ]]
[[Throws:] [Nothing. ]]
]
[endsect]
[/////////////////////////////////////]
[section:destructor Destructor `~serial_executor()`]
~generic_serial_executor();
[variablelist
[[Effects:] [Destroys the serial_executor.]]
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
]
[endsect]
[/////////////////////////////////////]
[section:underlying_executor Function member `underlying_executor()`]
Executor& underlying_executor() noexcept;
[variablelist
[[Return:] [The underlying executor instance. ]]
]
[endsect]
[endsect]
[//////////////////////////////////////////////////////////]
[section:inline_executor Class `inline_executor`]
A serial executor ensuring that there are no two work units that executes concurrently.
#include <boost/thread/inline_executor.hpp>
namespace boost {
class inline_executor
{
public:
inline_executor(inline_executor const&) = delete;
inline_executor& operator=(inline_executor const&) = delete;
inline_executor();
void close();
bool closed();
template <typename Closure>
void submit(Closure&& closure);
bool try_executing_one();
template <typename Pred>
bool reschedule_until(Pred const& pred);
};
}
[/////////////////////////////////////]
[section:constructor Constructor `inline_executor()`]
inline_executor();
[variablelist
[[Effects:] [Constructs a inline_executor. ]]
[[Throws:] [Nothing. ]]
]
[endsect]
[/////////////////////////////////////]
[section:destructor Destructor `~inline_executor()`]
~inline_executor();
[variablelist
[[Effects:] [Destroys the inline_executor.]]
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
]
[endsect]
[endsect]
@@ -796,13 +999,12 @@ A serial executor ensuring that there are no two work units that executes concur
A thread pool with up to a fixed number of threads.
#include <boost/thread/work.hpp>
#include <boost/thread/executors/basic_thread_pool.hpp>
namespace boost {
class basic_thread_pool
{
public:
typedef boost::work work;
basic_thread_pool(basic_thread_pool const&) = delete;
basic_thread_pool& operator=(basic_thread_pool const&) = delete;
@@ -841,7 +1043,7 @@ A thread pool with up to a fixed number of threads.
[/////////////////////////////////////]
[section:destructor Destructor `~basic_thread_pool()`]
virtual ~basic_thread_pool();
~basic_thread_pool();
[variablelist
@@ -854,6 +1056,64 @@ A thread pool with up to a fixed number of threads.
[endsect]
[///////////////////////////////////////]
[section:thread_executor Class `thread_executor`]
A thread_executor with a threads for each task.
#include <boost/thread/executors/thread_executor.hpp>
namespace boost {
class thread_executor
{
public:
thread_executor(thread_executor const&) = delete;
thread_executor& operator=(thread_executor const&) = delete;
thread_executor();
template <class AtThreadEntry>
basic_thread_pool( unsigned const thread_count, AtThreadEntry at_thread_entry);
~thread_executor();
void close();
bool closed();
template <typename Closure>
void submit(Closure&& closure);
};
}
[/////////////////////////////////////]
[section:constructor Constructor `thread_executor()`]
[variablelist
[[Effects:] [creates a thread_executor. ]]
[[Throws:] [Whatever exception is thrown while initializing the needed resources. ]]
]
[endsect]
[/////////////////////////////////////]
[section:destructor Destructor `~thread_executor()`]
~thread_executor();
[variablelist
[[Effects:] [Waits for closures (if any) to complete, then joins and destroys the threads.]]
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]
]
[endsect]
[endsect]
[/////////////////////////////////]
[section:loop_executor Class `loop_executor`]
@@ -864,8 +1124,7 @@ A user scheduled executor.
class loop_executor
{
public:
typedef thread_detail::work work;
loop_executor(loop_executor const&) = delete;
loop_executor& operator=(loop_executor const&) = delete;
@@ -909,7 +1168,7 @@ A user scheduled executor.
[variablelist
[[Effects:] [Destroys the thread pool.]]
[[Effects:] [Destroys the executor.]]
[[Synchronization:] [The completion of all the closures happen before the completion of the executor destructor.]]

View File

@@ -8,6 +8,101 @@
[section:changes History]
[heading Version 4.5.0 - boost 1.58]
[*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/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:]
@@ -28,7 +123,7 @@
Please take a look at [@https://svn.boost.org/trac/boost/query?status=assigned&status=new&status=reopened&component=thread&type=!Feature+Requests&col=id&col=summary&order=id thread Know Bugs] to see the current state.
Please take a look at [@http://www.boost.org/development/tests/release/developer/thread.html thread trunk regression test] to see the last snapshot.
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:]
@@ -496,9 +591,6 @@ been moved to __thread_id__.
The following features will be included in next releases.
# Complete the C++11 missing features, in particular
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
# Add some minor features, in particular
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
@@ -506,13 +598,6 @@ The following features will be included in next releases.
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
# Add 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/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
# And some additional extensions related to futures as:
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic shared_future::then.

View File

@@ -101,7 +101,31 @@
[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]
@@ -161,8 +185,6 @@
[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/2013/n3785.pdf N3785 Executors and Schedulers]]
[table Asynchronous Executors
@@ -181,30 +203,13 @@ While Boost.Thread implementation of executors would not use dynamic polymorphis
[[V.2.5] [thread_executor] [Yes] [ static version thread_executor, dynamic one execduler_adaptor<thread_executor> ]]
]
[endsect]
[section:async Improvements to std::future<T> and Related APIs]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3784.pdf N3784-Improvements to `std::future<T> and Related APIs]]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3857.pdf N3857-Improvements to std::future<T> and Related APIs]]
[note These functions are based on [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
[table Improvements to std::future<T> and related APIs]
[table `async, future/shared_future::then`and Executors
[[Section] [Description] [Status] [Comments]]
[[30.6.6] [Class template future] [Partial] [ - ]]
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
[[30.6.6] [then] [Yes] [ - ]]
[[30.6.6] [unwrap] [Yes] [ - ]]
[[30.6.6] [ready] [Partial] [ is_ready ]]
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
[[30.6.6] [unwrap constructor] [Yes] [ - ]]
[[30.6.7] [then] [Yes] [ - ]]
[[30.6.7] [unwrap] [No] [ #XXXX ]]
[[30.6.7] [ready] [Partial] [ is_ready ]]
[[30.6.X] [Function template when_all] [Partial] [ interface not complete #7447 ]]
[[30.6.X] [Function template when_any] [Partial] [ interface not complete #7446 ]]
[[30.6.X] [Function template when_any_swaped] [No] [ #XXXX ]]
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
[[30.6.8] [Function template async ] [Yes] [ - ]]
[[30.6.6] [`future<T>::then`] [Yes] [ ]]
[[30.6.7] [`shared_future<T>::then`] [Yes] [ ]]
[[30.6.8] [`async`] [Yes] [ - ]]
]
[endsect]

View File

@@ -79,47 +79,54 @@
struct uses_allocator<packaged_task <S>, Alloc>;
template <class F>
future<typename result_of<typename decay<F>::type()>::type>
async(F f);
future<typename result_of<typename decay<F>::type()>::type>
async(F f);
template <class F>
future<typename result_of<typename decay<F>::type()>::type>
async(launch policy, F f);
future<typename result_of<typename decay<F>::type()>::type>
async(launch policy, F f);
template <class F, class... Args>
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(F&& f, Args&&... args);
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(F&& f, Args&&... args);
template <class F, class... Args>
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(launch policy, F&& f, Args&&... args);
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(launch policy, F&& f, Args&&... args);
template <class Executor, class F, class... Args>
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
future<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
template<typename Iterator>
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
template<typename F1,typename... FS>
void wait_for_all(F1& f1,Fs&... fs); // EXTENSION
void wait_for_all(F1& f1,Fs&... fs); // EXTENSION
template<typename Iterator>
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
template<typename F1,typename... Fs>
unsigned wait_for_any(F1& f1,Fs&... fs); // EXTENSION
unsigned wait_for_any(F1& f1,Fs&... fs); // EXTENSION
template <class InputIterator>
future<std::vector<typename InputIterator::value_type::value_type>>
when_all(InputIterator first, InputIterator last);
template <typename... T>
future<std::tuple<decay_t<T>...> when_all(T&&... futures);
template <class InputIterator>
future<std::vector<typename InputIterator::value_type::value_type>>
when_any(InputIterator first, InputIterator last); // EXTENSION
template <typename... T>
future<std::tuple<decay_t<T>...> when_any(T&&... futures);
template <typename T>
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
future<void> make_future(); // DEPRECATED
template <typename T>
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
future<void> make_ready_future(); // EXTENSION
//template <typename T>
//future<T> make_ready_future(exception_ptr ex); // DEPRECATED
//template <typename T, typename E>
//future<T> make_ready_future(E ex); // DEPRECATED
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
template <typename E>
exceptional_ptr make_exceptional(E ex); // EXTENSION
exceptional_ptr make_exceptional(E ex); // EXTENSION
exceptional_ptr make_exceptional(); // EXTENSION
@@ -333,13 +340,13 @@ The object's `name` virtual function returns a pointer to the string "future".]]
shared_future<R> share();
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(S& scheduler, F&& func); // EXTENSION
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(launch policy, F&& func); // EXTENSION
see below unwrap(); // EXTENSION
@@ -438,6 +445,7 @@ There are not too much tests yet, so it is possible that you can find out some t
[variablelist
[[Requires:] [`other.valid()`.]
[[Effects:] [Constructs a new __unique_future__, and transfers ownership of the shared state associated with `other` and unwrapping the inner future (see `unwrap()`).]]
[[Postconditions:] [[unique_future_get_state_link `this->get_state()`] returns the value of `other->get_state()` prior to the
@@ -756,6 +764,8 @@ prior to waiting.]]
[[Returns:] [`true` if `*this` is associated with a shared state, `false`
otherwise.]]
[[Remarks:] [The result of this function is not stable and that the future could become invalid even if the function returned true or vice-versa.]]
[[Throws:] [Nothing.]]
]
@@ -771,6 +781,8 @@ otherwise.]]
[[Returns:] [`true` if `*this` is associated with a shared state and that result is ready for retrieval, `false`
otherwise.]]
[[Remarks:] [The result of this function is not stable and that the future could become not ready even if the function returned true or vice-versa.]]
[[Throws:] [Nothing.]]
]
@@ -786,6 +798,8 @@ otherwise.]]
[[Returns:] [`true` if `*this` is associated with a shared state, that result is ready for retrieval, and the result is a
stored value, `false` otherwise.]]
[[Remarks:] [The result of this function is not stable and the future could lost its value even if the function returned true or vice-versa.]]
[[Throws:] [Nothing.]]
]
@@ -801,6 +815,8 @@ stored value, `false` otherwise.]]
[[Returns:] [`true` if `*this` is associated with a shared state, that result is ready for retrieval, and the result is a
stored exception, `false` otherwise.]]
[[Remarks:] [The result of this function is not stable and the future could lost its exception even if the function returned true or vice-versa.]]
[[Throws:] [Nothing.]]
]
@@ -818,6 +834,8 @@ entry, and the result has a ['wait callback] set, that callback is invoked prior
[[Returns:] [a exception_ptr, storring or not an exception.]]
[[Remarks:] [The result of this function is not stable and the future could lost its exception even if the function returned a valid `exception_ptr` or vice-versa.]]
[[Throws:] [Whatever `mutex::lock()/mutex::unlock()` can throw.]]
]
@@ -835,6 +853,8 @@ entry, and the result has a ['wait callback] set, that callback is invoked prior
[[Returns:] [__uninitialized__ if `*this` is not associated with a shared state. __ready__ if the shared state
associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
[[Remarks:] [The result of this function is not stable.]]
[[Throws:] [Nothing.]]
]
@@ -860,13 +880,13 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
[section:then Member function `then()` - EXTENSION]
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(S& scheduler, F&& func); // EXTENSION
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(launch policy, F&& func); // EXTENSION
[warning These functions are experimental and subject to change in future versions.
@@ -883,6 +903,8 @@ second parameter.]]
[[Effects:] [
All the functions create a shared state that is associated with the returned future object. The further behavior of the functions is as follows.
- The continuation is called when the object's shared state is ready (has a value or exception stored).
- The continuation launches according to the specified policy or scheduler.
@@ -890,9 +912,11 @@ second parameter.]]
- When the scheduler or launch policy is not provided the continuation inherits the
parent's launch policy or scheduler.
- If the parent was created with `promise<<` or with a `packaged_task<>` (has no associated launch policy), the
- Any value returned from the continuation is stored as the result in the shared state of the resulting `future`. Any exception propagated from the execution of the continuation is stored as the exceptional result in the shared state of the resulting `future`.
- If the parent was created with `promise<>` or with a `packaged_task<>` (has no associated launch policy), the
continuation behaves the same as the third overload with a policy argument of `launch::async | launch::deferred` and
the same argument for func.
the same argument for `func`.
- If the parent has a policy of `launch::deferred` and the continuation does not have a specified launch policy or
scheduler, then the parent is filled by immediately calling `.wait()`, and the policy of the antecedent is
@@ -902,11 +926,20 @@ scheduler, then the parent is filled by immediately calling `.wait()`, and the p
[[Returns:] [An object of type `__unique_future__<typename boost::result_of<F(__unique_future__)>` that refers to the shared state created by the continuation.]]
[[Notes:] [
- Note that nested futures are not implicitly unwrapped yet. This could be subject to change in future versions.
- The returned futures behave as the ones returned from boost::async, the destructor of the future object returned from then will block. This could be subject to change in future versions.
]]
[[Postconditions:] [
- The `__unique_future__` object passed to the parameter of the continuation function is a copy of the original `__unique_future__`.
- `valid() == false` on original future object immediately after it returns.
- `valid() == false` on original future; `valid() == true` on the `future` returned from then.
[/ In case of implicit unwrapping, the validity of the `future` returned from `then` cannot be established until after the completion of the functor passed into `then`. In such case, the resulting `future` becomes ready with an exception of type `future_error`, with an error code of `future_errc::broken_promise`. ]
]]
@@ -928,19 +961,19 @@ There are not too much tests yet, so it is possible that you can find out some t
[variablelist
[[Notes:] [Removes the outermost future and returns a future with the associated state been a proxy of inner future.]]
[[Notes:] [Removes the outermost future and returns a future with the associated state been a proxy of the outer future.]]
[[Effects:] [
- Returns a future that becomes ready when the shared state of the inner future is ready.
- Returns a future that becomes ready when the shared state of the outer and inner future is ready. The validity of the future returned from `get()` applied on the outer future cannot be established a priori. If it is not valid, this future is forced to be valid and becomes ready with an exception of type `future_error`, with an error code of `future_errc::broken_promise`.
]]
[[Returns:] [An object of type future with the associated state been a proxy of inner future.]]
[[Returns:] [An object of type future with the associated state been a proxy of outer future.]]
[[Postconditions:] [
- The returned future has `valid() == true` regardless of the validity of the inner future.
- The returned future has `valid() == true`.
]]
@@ -975,14 +1008,14 @@ There are not too much tests yet, so it is possible that you can find out some t
// factories
template<typename F>
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
then(F&& func); // EXTENSION
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(F&& func) const; // EXTENSION
template<typename S, typename F>
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(S& scheduler, F&& func) const; // EXTENSION
template<typename F>
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
then(launch policy, F&& func); // EXTENSION
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(launch policy, F&& func) const; // EXTENSION
void swap(shared_future& other);
@@ -1324,14 +1357,14 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
[section:then Member function `then()` EXTENSION]
template<typename F>
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
then(F&& func); // EXTENSION
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(F&& func) const; // EXTENSION
template<typename S, typename F>
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(S& scheduler, F&& func) const; // EXTENSION
template<typename F>
__unique_future__<typename boost::result_of<F(shared_future&)>::type>
then(launch policy, F&& func); // EXTENSION
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(launch policy, F&& func) const; // EXTENSION
[warning These functions are experimental and subject to change in future versions.
@@ -1367,11 +1400,22 @@ scheduler, then the parent is filled by immediately calling `.wait()`, and the p
[[Returns:] [An object of type `__unique_future__<typename boost::result_of<F(shared_future)>` that refers to the shared state created by the continuation.]]
[[Notes:] [
- Note that nested futures are not implicitly unwrapped yet. This could be subject to change in future versions.
- The returned futures behave as the ones returned from boost::async, the destructor of the future object returned from then will block. This could be subject to change in future versions.
]]
[[Postconditions:] [
- The future object is moved to the parameter of the continuation function .
- `valid() == false` on original future object immediately after it returns.
- `valid() == true` on original `shared_future`; `valid() == true` on the `future` returned from then.
[/- In case of implicit unwrapping, the validity of the `future` returned from `then` cannot be established until after the completion of the functor passed into `then`. In such case, the resulting `future` becomes ready with an exception of type `future_error`, with an error code of `future_errc::broken_promise`. ]
]]
@@ -1927,19 +1971,17 @@ __packaged_task__.]]
The function template async provides a mechanism to launch a function potentially in a new thread and
provides the result of the function in a future object with which it shares a shared state.
[warning `async(launch::deferred, F)` is NOT YET IMPLEMENTED!]
[heading Non-Variadic variant]
template <class F>
__unique_future__<typename result_of<typename decay<F>::type()>::type>
async(F&& f);
__unique_future__<typename result_of<typename decay<F>::type()>::type>
async(F&& f);
template <class F>
__unique_future__<typename result_of<typename decay<F>::type()>::type>
async(launch policy, F&& f);
__unique_future__<typename result_of<typename decay<F>::type()>::type>
async(launch policy, F&& f);
template <class Executor, class F>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
[variablelist
[[Requires:] [
@@ -1955,7 +1997,7 @@ shall be a valid expression.
The first function behaves the same as a call to the second function with a policy argument of
`launch::async | launch::deferred` and the same arguments for `F`.
The second function creates a shared state that is associated with the returned future object.
The second and third functions create a shared state that is associated with the returned future object.
The further behavior of the second function depends on the policy argument as follows (if more than one of these conditions applies, the implementation may choose any of the corresponding policies):
@@ -1963,7 +2005,14 @@ The further behavior of the second function depends on the policy argument as fo
- if `policy & launch::deferred` is non-zero - Stores `decay_copy(boost::forward<F>(f))` in the shared state. This copy of `f` constitute a deferred function. Invocation of the deferred function evaluates `boost::move(g)()` where `g` is the stored value of `decay_copy(boost::forward<F>(f))`. The shared state is not made ready until the function has completed. The first call to a non-timed waiting function on an asynchronous return object referring to this shared state shall invoke the deferred function in the thread that called the waiting function. Once evaluation of `boost::move(g)()` begins, the function is no longer considered deferred. (Note: If this policy is specified together with other policies, such as when using a policy value of `launch::async | launch::deferred`, implementations should defer invocation or the selection of the policy when no more concurrency can be effectively exploited.)
- if no valid launch policy is provided the behaviour is undefined.
- if no valid launch policy is provided the behavior is undefined.
The further behavior of the third function is as follows:
- The Executor::submit() function is given a function<void ()> which calls `INVOKE (DECAY_COPY
(std::forward<F>(f)), DECAY_COPY (std::forward<Args>(args))...). The implementation of the executor
is decided by the programmer.
]]
@@ -1991,22 +2040,22 @@ If the implementation chooses the `launch::async` policy,
]]
[[Remarks:] [The first signature shall not participate in overload resolution if decay<F>::type is boost::launch.
]]
[[Remarks::] [The first signature shall not participate in overload resolution if `decay_t<F> is `boost::
launch` or `boost::is_executor<F>` is `true_type`.]]
]
[heading Variadic variant]
template <class F, class... Args>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(F&& f, Args&&... args);
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(F&& f, Args&&... args);
template <class F, class... Args>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(launch policy, F&& f, Args&&... args);
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(launch policy, F&& f, Args&&... args);
template <class Executor, class F, class... Args>
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
__unique_future__<typename result_of<typename decay<F>::type(typename decay<Args>::type...)>::type>
async(Executor &ex, F&& f, Args&&... args);
[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing <tuple> (waiting for a boost::tuple that is move aware), and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.]
@@ -2087,19 +2136,19 @@ with the return from the last function that releases the shared state, whichever
[section:wait_for_any Non-member function `wait_for_any()` - EXTENSION]
template<typename Iterator>
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
Iterator wait_for_any(Iterator begin,Iterator end); // EXTENSION
template<typename F1,typename F2>
unsigned wait_for_any(F1& f1,F2& f2); // EXTENSION
unsigned wait_for_any(F1& f1,F2& f2); // EXTENSION
template<typename F1,typename F2,typename F3>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3); // EXTENSION
unsigned wait_for_any(F1& f1,F2& f2,F3& f3); // EXTENSION
template<typename F1,typename F2,typename F3,typename F4>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
template<typename F1,typename F2,typename F3,typename F4,typename F5>
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
[variablelist
@@ -2127,19 +2176,19 @@ with any of the futures being waited for. `std::bad_alloc` if memory could not
[section:wait_for_all Non-member function `wait_for_all()` - EXTENSION]
template<typename Iterator>
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
void wait_for_all(Iterator begin,Iterator end); // EXTENSION
template<typename F1,typename F2>
void wait_for_all(F1& f1,F2& f2); // EXTENSION
void wait_for_all(F1& f1,F2& f2); // EXTENSION
template<typename F1,typename F2,typename F3>
void wait_for_all(F1& f1,F2& f2,F3& f3); // EXTENSION
void wait_for_all(F1& f1,F2& f2,F3& f3); // EXTENSION
template<typename F1,typename F2,typename F3,typename F4>
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4); // EXTENSION
template<typename F1,typename F2,typename F3,typename F4,typename F5>
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4,F5& f5); // EXTENSION
[variablelist
@@ -2158,16 +2207,167 @@ __unique_future__ or __shared_future__.]]
[endsect]
[/////////////////////////////////////////////////////////////////////]
[section:when_all Non-member function `when_all()` - EXTENSION]
template <class InputIterator>
future<std::vector<typename InputIterator::value_type::value_type>>
when_all(InputIterator first, InputIterator last);
template <typename... FutTypes>
future<std::tuple<decay_t<FutTypes>...> when_all(FutTypes&&... futures);
[variablelist
[[Requires:] [
- For the first overload, `InputIterator`'s value type shall be convertible to `future<R>` or `shared_future<R>`.
All `R` types must be the same. If any of the `future<R>` or `shared_future<R>` objects are in invalid state (i.e. `valid() == false`), the behavior is undefined.
- For the second overload, `FutTypes` is of type `future<R>` or `shared_future<R>`. The effect of calling `when_all` on a `future` or a `shared_future` object for which `valid() == false` is undefined.
]]
[[Notes:] [
- There are two variations of `when_all`. The first version takes a pair of `InputIterators`. The second takes any arbitrary number of `future<R0>` and `shared_future<R1>` objects, where `R0` and `R1` need not be the same type.
- Calling the first signature of `when_all` where `InputIterator` first equals last, returns a future with an empty `vector` that is immediately ready.
- Calling the second signature of `when_all` with no arguments returns a future<tuple<>> that is immediately ready.
]]
[[Effects:] [
- If any of the futures supplied to a call to `when_all` refer to deferred tasks that have not started execution, those tasks are executed before the call to `when_all` returns. Once all such tasks have been executed, the call to `when_all` returns immediately.
- The call to `when_all` does not wait for non-deferred tasks, or deferred tasks that have already started executing elsewhere, to complete before returning.
- Once all the `future`s/`shared_future`s supplied to the call to `when_all` are ready, the `future`s/`shared_future`s are moved/copied into the associated state of the future returned from the call to `when_all`, preserving the order of the futures supplied to `when_all`.
- The collection is then stored as the result in a newly created shared state.
- A new future object that refers to the shared state is created. The exact type of the future is further described below.
- The `future` returned by `when_all` will not throw an exception when calling `wait()` or `get()`, but the futures held in the output collection may.
]]
[[Returns:] [
- `future<tuple<>>` if `when_all` is called with zero arguments.
- `future<vector<future<R>>>` if the input cardinality is unknown at compile and the iterator pair yields `future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
- `future<vector<shared_future<R>>>` if the input cardinality is unknown at compile time and the iterator pair yields `shared_future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
- `future<tuple<decay_t<FutTypes>...>>` if inputs are fixed in number.
]]
[[Postconditions:] [
- All input futures valid() == false.
- All input shared future valid() == true.
- valid() == true.
]]
]
[endsect]
[/////////////////////////////////////////////////////////////////////]
[section:when_any Non-member function `when_any()` - EXTENSION]
template <class InputIterator>
future<std::vector<typename InputIterator::value_type::value_type>>
when_any(InputIterator first, InputIterator last);
template <typename... FutTypes>
future<std::tuple<decay_t<FutTypes>...>
when_any(FutTypes&&... futures);
[variablelist
[[Requires:] [
- For the first overload, `InputIterator`'s value type shall be convertible to `future<R>` or `shared_future<R>`. All `R` types must be the same. If any of the `future<R>` or `shared_future<R>` objects are in invalid state (i.e. `valid() == false`), the behavior is undefined.
- For the second overload, `FutTypes` is of type `future<R>` or `shared_future<R>`. The effect of calling `when_any` on a `future` or a `shared_future` object for which `valid() == false is undefined`.
]]
[[Notes:] [
- There are two variations of `when_any `. The first version takes a pair of `InputIterators`. The second takes any arbitrary number of `future<R0>` and `shared_future<R1>` objects, where `R0` and `R1` need not be the same type.
- Calling the first signature of `when_any ` where `InputIterator` first equals last, returns a future with an empty `vector` that is immediately ready.
- Calling the second signature of `when_any` with no arguments returns a future<tuple<>> that is immediately ready.
]]
[[Effects:] [
- Each of the futures supplied to `when_any` is checked in the order supplied. If a given future is ready, then no further futures are checked, and the call to `when_any` returns immediately. If a given future refers to a deferred task that has not yet started execution, then no further futures are checked, that task is executed, and the call to `when_any` then returns immediately.
- The call to `when_any` does not wait for non-deferred tasks, or deferred tasks that have already started executing elsewhere, to complete before returning.
- Once at least one of the futures supplied to the call to `when_any` are ready, the futures are moved into the associated state of the future returned from the call to `when_any`, preserving the order of the futures supplied to `when_any`. That future is then ready.
- The collection is then stored as the result in a newly created shared state.
- A new future object that refers to the shared state is created. The exact type of the future is further described below.
- The future returned by `when_any` will not throw an exception when calling `wait()` or `get()`, but the futures held in the output collection may.
]]
[[Returns:] [
- `future<tuple<>>` if `when_any ` is called with zero arguments.
- `future<vector<future<R>>>` if the input cardinality is unknown at compile and the iterator pair yields `future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
- `future<vector<shared_future<R>>>` if the input cardinality is unknown at compile time and the iterator pair yields `shared_future<R>`. The order of the futures in the output vector will be the same as given by the input iterator.
- `future<tuple<decat_t<FutTypes>...>>` if inputs are fixed in number.
]]
[[Postconditions:] [
- All input futures valid() == false.
- All input shared_futures valid() == true.
- valid() == true.
]]
]
[endsect]
[/////////////////////////////////////////////////////////////////////////////]
[section:make_ready_future Non-member function `make_ready_future()` EXTENSION]
template <typename T>
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
future<typename decay<T>::type> make_ready_future(T&& value); // EXTENSION
future<void> make_ready_future(); // EXTENSION
template <typename T>
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
future<T> make_ready_future(exception_ptr ex); // DEPRECATED
template <typename T, typename E>
future<T> make_ready_future(E ex); // DEPRECATED
future<T> make_ready_future(E ex); // DEPRECATED
[variablelist
@@ -2207,7 +2407,7 @@ Otherwise the value is copied to the shared state of the returned function.
exceptional_ptr make_exceptional(exception_ptr ex); // EXTENSION
template <typename E>
exceptional_ptr make_exceptional(E ex); // EXTENSION
exceptional_ptr make_exceptional(E ex); // EXTENSION
exceptional_ptr make_exceptional(); // EXTENSION
[variablelist
@@ -2228,7 +2428,7 @@ An exceptional_ptr instance implicitly convertible to a future<T>
[section:make_future Non-member function `make_future()` DEPRECATED]
template <typename T>
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
future<typename decay<T>::type> make_future(T&& value); // DEPRECATED
future<void> make_future(); // DEPRECATED
@@ -2264,7 +2464,7 @@ Otherwise the value is copied to the shared state of the returned function.
[section:make_shared_future Non-member function `make_shared_future()` DEPRECATED]
template <typename T>
shared_future<typename decay<T>::type> make_shared_future(T&& value); // DEPRECATED
shared_future<typename decay<T>::type> make_shared_future(T&& value); // DEPRECATED
shared_future<void> make_shared_future(); // DEPRECATED
[variablelist

482
doc/parallel.qbk Normal file
View 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]

View File

@@ -229,12 +229,12 @@ where
[endsect]
[/////////////////////////////////////]
[section:non_waaiting Non-waiting Concurrent Queue Operations]
[section:non_waiting Non-waiting Concurrent Queue Operations]
The ConcurrentQueue concept models a queue with .
The ConcurrentQueue concept models a queue with Non-waiting operations.
A type `Q` meets the ConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
A type `Q` meets the ConcurrentQueue requirements if is a model of a BasicConcurrentQueue and the following expressions are well-formed and have the specified semantics
* `s = q.try_push_back(e);`
* `s = q.try_push_back(rve);`
@@ -281,7 +281,7 @@ where
[endsect]
[/////////////////////////////////////]
[section:try_push_back_m `s = q.try_push_back(rve());`]
[section:try_push_back_m `s = q.try_push_back(rve);`]
[variablelist
@@ -345,7 +345,7 @@ For cases when blocking for mutual exclusion is undesirable, we have non-blockin
The interface is the same as the try operations but is allowed to also return queue_op_status::busy
in case the operation is unable to complete without blocking.
Non-blocking operations are provided only for BlockingQueues
Non-blocking operations are provided only for lock based queues
* `s = q.nonblocking_push_back(nb, e);`
* `s = q.nonblocking_push_back(nb, rve);`
@@ -616,6 +616,226 @@ Closed queues add the following valid expressions
[endsect]
[endsect]
[/////////////////////////////////////]
[section:queue_op_status Queue Operation Status]
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
namespace boost
{
enum class queue_op_status { success = 0, empty, full, closed, busy }
}
[endsect]
[/////////////////////////////////////]
[section:queue_base Queue Base]
#include <boost/thread/concurrent_queues/queue_base.hpp>
namespace boost
{
template <typename ValueType>
class queue_base
{
public:
typedef ValueType value_type;
typedef std::size_t size_type;
// Constructors/Assignment/Destructors
virtual ~queue_base() {};
// 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 push_back(BOOST_THREAD_RV_REF(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_push_back(BOOST_THREAD_RV_REF(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_push_back(BOOST_THREAD_RV_REF(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_push_back(BOOST_THREAD_RV_REF(value_type) x) = 0;
virtual queue_op_status wait_pull_front(ValueType& elem) = 0;
};
}
[endsect]
[/////////////////////////////////////]
[section:queue_adaptor Queue Adaptor]
#include <boost/thread/concurrent_queues/queue_adaptor.hpp>
namespace boost
{
template <typename Queue>
class queue_adaptor : public queue_base<typename Queue::value_type>
{
public:
typedef typename Queue::value_type value_type;
typedef std::size_t size_type;
// Constructors/Assignment/Destructors
queue_adaptor();
// Observers
bool empty() const;
bool full() const;
size_type size() const { return queue.size(); }
bool closed() const;
// Modifiers
void close();
void push_back(const value_type& x);
void push_back(BOOST_THREAD_RV_REF(value_type) x);
void pull_front(value_type& x);
value_type pull_front();
queue_op_status try_push_back(const value_type& x);
queue_op_status try_push_back(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status try_pull_front(value_type& x);
queue_op_status nonblocking_push_back(const value_type& x);
queue_op_status nonblocking_push_back(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status nonblocking_pull_front(value_type& x);
queue_op_status wait_push_back(const value_type& x);
queue_op_status wait_push_back(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status wait_pull_front(value_type& x);
};
}
[endsect]
[/////////////////////////////////////]
[section:queue_views Queue Views]
#include <boost/thread/concurrent_queues/queue_views.hpp>
namespace boost
{
template <typename Queue>
class queue_back_view;
template <typename Queue>
class queue_front_view
template <class T>
using queue_back = queue_back_view<queue_base<T>>;
template <class T>
using queue_front = queue_front_view<queue_base<T>>;
}
[/////////////////////////////////////]
[section:queue_back_view Class template `queue_back_view<>`]
template <typename Queue>
class queue_back_view
{
public:
typedef typename Queue::value_type value_type;
typedef typename Queue::size_type size_type;
// Constructors/Assignment/Destructors
queue_back_view(Queue& q) noexcept;
// Observers
bool empty() const;
bool full() const;
size_type size() const;
bool closed() const;
// Modifiers
void close();
void push(const value_type& x);
void push(BOOST_THREAD_RV_REF(value_type) x);
void pull(value_type& x);
value_type pull();
queue_op_status try_push(const value_type& x);
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status try_pull(value_type& x);
queue_op_status nonblocking_push(const value_type& x);
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status nonblocking_pull(value_type& x);
queue_op_status wait_push(const value_type& x);
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status wait_pull_front(value_type& x);
};
[endsect]
[/////////////////////////////////////]
[section:queue_front_view Class template `queue_front_view<>`]
template <typename Queue>
class queue_front_view
{
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;
// Observers
bool empty() const;
bool full() const;
size_type size() const;
bool closed() const;
// Modifiers
void close();
void push(const value_type& x);
void push(BOOST_THREAD_RV_REF(value_type) x);
void pull(value_type& x);
value_type pull();
queue_op_status try_push(const value_type& x);
queue_op_status try_push(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status try_pull(value_type& x);
queue_op_status nonblocking_push(const value_type& x);
queue_op_status nonblocking_push(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status nonblocking_pull(value_type& x);
queue_op_status wait_push(const value_type& x);
queue_op_status wait_push(BOOST_THREAD_RV_REF(value_type) x);
queue_op_status wait_pull(value_type& x);
};
[endsect]
[endsect]
[/////////////////////////////////////]
[section:sync_bounded_queue_ref Synchronized Bounded Queue]
@@ -830,7 +1050,7 @@ Closed queues add the following valid expressions
[/////////////////////////////////////]
[section:constructor Constructor `sync_bounded_queue(size_type)`]
[section:constructor Constructor `sync_queue(size_type)`]
explicit sync_queue();
@@ -843,21 +1063,6 @@ Closed queues add the following valid expressions
]
[endsect]
[/////////////////////////////////////]
[section:constructort Template Constructor `sync_bounded_queue(size_type, Range)`]
template <typename Range>
sync_bounded_queue(size_type max_elems, Range range);
[variablelist
[[Effects:] [Constructs an sync_queue with all the elements of the range. ]]
[[Throws:] [any exception that can be throw because of resources unavailable. ]]
]
[endsect]
[/////////////////////////////////////]
[section:full Member Function `full()`]

View File

@@ -8,7 +8,7 @@
[library Thread
[quickbook 1.5]
[version 4.3.0]
[version 4.4.0]
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
[copyright 2007-11 Anthony Williams]
[copyright 2011-14 Vicente J. Botet Escriba]
@@ -244,7 +244,6 @@
[include futures.qbk]
[endsect]
[include tss.qbk]
[section:sds Synchronized Data Structures]
@@ -253,6 +252,8 @@
[/include sync_streams.qbk]
[endsect]
[include parallel.qbk]
[include time.qbk]
[include emulations.qbk]

View File

@@ -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
@@ -752,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.
[/
@@ -801,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.
[/
@@ -841,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.
[/
@@ -881,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.
[/
@@ -917,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.
]]
@@ -1489,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
@@ -1500,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__.]]
]
@@ -1513,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
@@ -1523,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__.]]
]

View File

@@ -7,9 +7,6 @@
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_EXECUTORS
@@ -67,12 +64,13 @@ void submit_some(boost::executor& tp)
}
void at_th_entry(boost::basic_thread_pool& )
{
}
int main()
int test_executor_adaptor()
{
// std::cout << BOOST_CONTEXTOF << std::endl;
{
@@ -144,3 +142,9 @@ int main()
// std::cout << BOOST_CONTEXTOF << std::endl;
return 0;
}
int main()
{
return test_executor_adaptor();
}

View 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

View File

@@ -4,9 +4,6 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

View File

@@ -4,11 +4,7 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
//&& ! defined BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
@@ -48,6 +44,7 @@ int p2(boost::future<int> f)
BOOST_ASSERT(false);
}
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
return 0;
}
int p2s(boost::shared_future<int> f)
{
@@ -68,6 +65,7 @@ int p2s(boost::shared_future<int> f)
BOOST_ASSERT(false);
}
BOOST_THREAD_LOG << "P2S>" << BOOST_THREAD_END_LOG;
return 0;
}
int main()

View File

@@ -4,9 +4,6 @@
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif

View File

@@ -5,16 +5,13 @@
#include <boost/config.hpp>
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
//#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/future.hpp>
@@ -93,16 +90,80 @@ int main()
{
try
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
boost::future<std::tuple<> > all0 = boost::when_all();
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_all(boost::move(f1), boost::move(f2));
//(void) all.wait();
boost::csbl::vector<boost::future<int> > res = all.get();
BOOST_THREAD_LOG
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
BOOST_THREAD_LOG
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
{
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)
{
@@ -120,16 +181,113 @@ int main()
{
try
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
boost::future<int> f2 = boost::async(boost::launch::async, &p1b);
boost::future<std::tuple<> > all0 = boost::when_any();
boost::future<boost::csbl::vector<boost::future<int> > > all = boost::when_any(boost::move(f1), boost::move(f2));
//(void) all.wait();
boost::csbl::vector<boost::future<int> > res = all.get();
BOOST_THREAD_LOG
<< res[0].get() <<" " << BOOST_THREAD_END_LOG;
BOOST_THREAD_LOG
<< res[1].get() <<" " << BOOST_THREAD_END_LOG;
{
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)
{
@@ -155,7 +313,6 @@ using namespace boost;
void f( boost::csbl::vector<future<int> > &//vec
, BOOST_THREAD_RV_REF(future<int>) //f
) {
//vec.push_back(boost::forward<future<int> >(f));
}
int main()
{

View 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();
}

View File

@@ -8,9 +8,6 @@
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
#endif
#define BOOST_THREAD_VERSION 4
//#define BOOST_THREAD_USES_LOG

View File

@@ -3,12 +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>
#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
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#include <boost/thread/executors/basic_thread_pool.hpp>

View File

@@ -3,14 +3,15 @@
// Distributed under the 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
//#ifndef BOOST_NO_CXX11_DECLTYPE_N3276
//#define BOOST_THREAD_NO_CXX11_DECLTYPE_N3276
//#endif
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#include <boost/thread/executors/basic_thread_pool.hpp>
#include <boost/thread/future.hpp>

View File

@@ -6,9 +6,13 @@
// 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
@@ -87,25 +91,24 @@ void consumer2(the_ostream &mos, boost::sync_queue<int> & sbq)
mos << "exception !!!\n";
}
}
//void consumer3(the_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";
// }
//}
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));
}
}
catch(...)
{
mos << "exception !!!\n";
}
}
int main()
{

View 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;
}

View File

@@ -6,8 +6,13 @@
// 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>

View File

@@ -3,10 +3,15 @@
// Distributed under the 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
#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>

View File

@@ -3,13 +3,18 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#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()

View File

@@ -41,6 +41,7 @@ namespace boost
{
}
BOOST_THREAD_MOVABLE(default_barrier_reseter)
//BOOST_THREAD_COPYABLE_AND_MOVABLE(default_barrier_reseter)
default_barrier_reseter(default_barrier_reseter const& other) BOOST_NOEXCEPT :
size_(other.size_)
@@ -71,6 +72,7 @@ namespace boost
{}
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_)
@@ -78,6 +80,7 @@ namespace boost
}
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_))
{
}
@@ -96,6 +99,7 @@ namespace boost
{
}
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_)
@@ -112,6 +116,10 @@ namespace boost
}
};
}
//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)

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View File

@@ -10,8 +10,16 @@
#define BOOST_CSBL_DEQUE_HPP
#include <boost/config.hpp>
#if defined BOOST_THREAD_USES_BOOST_DEQUE || defined BOOST_NO_CXX11_HDR_DEQUE || defined BOOST_NO_CXX11_RVALUE_REFERENCES
// 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

View File

@@ -15,97 +15,13 @@
// default_delete
#if defined BOOST_NO_CXX11_SMART_PTR
#include <boost/thread/csbl/memory/pointer_traits.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_scalar.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
#include <boost/move/unique_ptr.hpp>
namespace boost
{
namespace csbl
{
namespace detail
{
template <class _Ptr1, class _Ptr2,
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
>::value
>
struct same_or_less_cv_qualified_imp
: is_convertible<_Ptr1, _Ptr2>
{};
template <class _Ptr1, class _Ptr2>
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
: false_type
{};
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
!is_pointer<_Ptr1>::value>
struct same_or_less_cv_qualified
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2>
{};
template <class _Ptr1, class _Ptr2>
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
: false_type
{};
}
template <class T>
struct BOOST_SYMBOL_VISIBLE default_delete
{
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() = default;
#else
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
{}
#endif
template <class U>
BOOST_SYMBOL_VISIBLE
default_delete(const default_delete<U>&,
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT
{}
BOOST_SYMBOL_VISIBLE
void operator() (T* ptr) const BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
delete ptr;
}
};
template <class T>
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
{
public:
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() = default;
#else
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT
{}
#endif
template <class U>
BOOST_SYMBOL_VISIBLE
default_delete(const default_delete<U[]>&,
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT
{}
template <class U>
BOOST_SYMBOL_VISIBLE
void operator() (U* ptr,
typename enable_if<detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
delete [] ptr;
}
};
using ::boost::movelib::default_delete;
}
}
#else

View 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

View File

@@ -1,106 +1,28 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
// 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.
// 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>
// 20.8.1 class template unique_ptr:
#if defined BOOST_NO_CXX11_SMART_PTR
#include <boost/thread/csbl/memory/default_delete.hpp>
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
#include <boost/move/unique_ptr.hpp>
#include <boost/move/make_unique.hpp>
namespace boost
{
namespace csbl
{
template <class T, class D = default_delete<T> > class unique_ptr :
public ::boost::interprocess::unique_ptr<T,D>
{
typedef ::boost::interprocess::unique_ptr<T,D> base_type;
BOOST_MOVABLE_BUT_NOT_COPYABLE(unique_ptr)
protected:
//typedef typename base_type::nat nat;
//typedef typename base_type::nullptr_t nullptr_t;
struct nat {int for_bool;};
struct nat2 {int for_nullptr;};
typedef int nat2::*nullptr_t;
using ::boost::movelib::unique_ptr;
using ::boost::movelib::make_unique;
public:
typedef typename base_type::element_type element_type;
typedef typename base_type::deleter_type deleter_type;
typedef typename base_type::pointer pointer;
unique_ptr() : base_type()
{}
explicit unique_ptr(pointer p): base_type(p)
{}
unique_ptr(pointer p
,typename interprocess::ipcdetail::if_<interprocess::ipcdetail::is_reference<D>
,D
,typename interprocess::ipcdetail::add_reference<const D>::type>::type d)
: base_type(p, d)
{}
unique_ptr(BOOST_RV_REF(unique_ptr) u)
: base_type(boost::move(static_cast<base_type&>(u)))
{}
template <class U, class E>
unique_ptr(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u,
typename interprocess::ipcdetail::enable_if_c<
interprocess::ipcdetail::is_convertible<typename unique_ptr<U, E>::pointer, pointer>::value &&
interprocess::ipcdetail::is_convertible<E, D>::value &&
(
!interprocess::ipcdetail::is_reference<D>::value ||
interprocess::ipcdetail::is_same<D, E>::value
)
,
nat
>::type = nat())
: base_type(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)))
{}
unique_ptr& operator=(BOOST_RV_REF(unique_ptr) u)
{
this->base_type::operator=(boost::move(static_cast<base_type&>(u)));
return *this;
}
template <class U, class E>
unique_ptr& operator=(BOOST_RV_REF_BEG unique_ptr<U, E> BOOST_RV_REF_END u)
{
this->base_type::template operator=<U,E>(boost::move(static_cast< ::boost::interprocess::unique_ptr<U,E>&>(u)));
return *this;
}
unique_ptr& operator=(nullptr_t t)
{
this->base_type::operator=(t);
return *this;
}
void swap(unique_ptr& u)
{
this->base_type::swap(u);
}
};
template <class T, class D>
class unique_ptr<T[], D> :
public ::boost::interprocess::unique_ptr<T[],D>
{
};
}
}
#else
namespace boost
{
namespace csbl
{
using ::std::unique_ptr;
}
}
#endif // BOOST_NO_CXX11_SMART_PTR
#endif // header

View File

@@ -28,10 +28,14 @@ namespace boost
#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:

View File

@@ -239,7 +239,6 @@
! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
! defined(BOOST_NO_CXX11_DECLTYPE) && \
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) && \
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)
@@ -354,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

View File

@@ -16,7 +16,7 @@
* 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; \

View File

@@ -47,7 +47,7 @@ namespace boost
void call()
{
f();
if (impl) f();
}
};
public:

View File

@@ -47,7 +47,6 @@ namespace boost
#if ! defined(BOOST_NO_SFINAE_EXPR) && \
! defined(BOOST_NO_CXX11_DECLTYPE) && \
! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \
! defined(BOOST_THREAD_NO_CXX11_DECLTYPE_N3276) && \
! defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES)
#define BOOST_THREAD_PROVIDES_INVOKE
@@ -339,7 +338,6 @@ namespace boost
! defined BOOST_NO_CXX11_HDR_FUNCTIONAL && \
defined BOOST_MSVC
//#error
template <class Ret, class Fp>
inline
Ret invoke(BOOST_THREAD_RV_REF(Fp) f)

View File

@@ -20,8 +20,8 @@
// The invoker code is based on the one from libcxx.
//===----------------------------------------------------------------------===//
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
#define BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
#ifndef BOOST_THREAD_DETAIL_INVOKER_HPP
#define BOOST_THREAD_DETAIL_INVOKER_HPP
#include <boost/config.hpp>
@@ -51,7 +51,7 @@ namespace boost
csbl::tuple<Fp, Args...> f_;
public:
BOOST_THREAD_MOVABLE_ONLY( invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker)
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
typedef typename result_of<Fp(Args...)>::type result_type;
@@ -65,6 +65,22 @@ namespace boost
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;
@@ -89,7 +105,7 @@ namespace boost
csbl::tuple<Fp, Args...> f_;
public:
BOOST_THREAD_MOVABLE_ONLY( invoker_ret)
BOOST_THREAD_COPYABLE_AND_MOVABLE( invoker_ret)
typedef R result_type;
template <class F, class ... As>
@@ -147,7 +163,7 @@ namespace boost
Fp fp_; \
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
public: \
BOOST_THREAD_MOVABLE_ONLY(invoker) \
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) > \
@@ -160,7 +176,7 @@ namespace boost
{} \
\
BOOST_SYMBOL_VISIBLE \
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
invoker(BOOST_THREAD_RV_REF(invoker) x) \
: fp_(boost::move(x.fp_)) \
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
{} \
@@ -179,7 +195,7 @@ namespace boost
Fp fp_; \
BOOST_PP_REPEAT(n, BOOST_THREAD_DCL, ~) \
public: \
BOOST_THREAD_MOVABLE_ONLY(invoker) \
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) > \
@@ -192,7 +208,7 @@ namespace boost
{} \
\
BOOST_SYMBOL_VISIBLE \
invoker(BOOST_THREAD_FWD_REF(invoker) x) \
invoker(BOOST_THREAD_RV_REF(invoker) x) \
: fp_(x.fp_) \
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_RHS_PARAM, ~) \
{} \
@@ -248,7 +264,7 @@ namespace boost
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
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
@@ -276,7 +292,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -317,7 +333,7 @@ namespace boost
T6 v6_;
T7 v7_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
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
@@ -343,7 +359,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -381,7 +397,7 @@ namespace boost
T5 v5_;
T6 v6_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -405,7 +421,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -440,7 +456,7 @@ namespace boost
T4 v4_;
T5 v5_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -462,7 +478,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -494,7 +510,7 @@ namespace boost
T3 v3_;
T4 v4_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -514,7 +530,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -543,7 +559,7 @@ namespace boost
T2 v2_;
T3 v3_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -561,7 +577,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -587,7 +603,7 @@ namespace boost
T1 v1_;
T2 v2_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -603,7 +619,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -626,7 +642,7 @@ namespace boost
T0 v0_;
T1 v1_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0, T1)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -640,7 +656,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
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_))
@@ -660,7 +676,7 @@ namespace boost
Fp fp_;
T0 v0_;
public:
BOOST_THREAD_MOVABLE_ONLY(invoker)
BOOST_THREAD_COPYABLE_AND_MOVABLE(invoker)
typedef typename result_of<Fp(T0)>::type result_type;
BOOST_SYMBOL_VISIBLE
@@ -672,7 +688,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
invoker(BOOST_THREAD_RV_REF(invoker) f)
: fp_(boost::move(BOOST_THREAD_RV(f).fp))
, v0_(boost::move(BOOST_THREAD_RV(f).v0_))
{}
@@ -697,7 +713,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
invoker(BOOST_THREAD_RV_REF(invoker) f)
: fp_(boost::move(f.fp_))
{}
result_type operator()()
@@ -719,7 +735,7 @@ namespace boost
{}
BOOST_SYMBOL_VISIBLE
invoker(BOOST_THREAD_FWD_REF(invoker) f)
invoker(BOOST_THREAD_RV_REF(invoker) f)
: fp_(f.fp_)
{}
result_type operator()()

View File

@@ -80,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
@@ -100,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
@@ -121,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
@@ -140,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 >
@@ -198,6 +202,8 @@ namespace detail
#define BOOST_THREAD_MOVABLE(TYPE)
#define BOOST_THREAD_COPYABLE(TYPE)
#else
#if defined BOOST_THREAD_USES_MOVE
@@ -220,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) \
@@ -233,15 +244,20 @@ 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) \
@@ -249,6 +265,31 @@ namespace boost
{
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> {};

View File

@@ -13,7 +13,7 @@
#include <boost/config.hpp>
#include <boost/thread/detail/memory.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <boost/thread/csbl/memory/shared_ptr.hpp>
#include <boost/type_traits/decay.hpp>
namespace boost
@@ -33,7 +33,7 @@ namespace boost
{
}
};
shared_ptr<impl_base> impl;
csbl::shared_ptr<impl_base> impl;
template <typename F>
struct impl_type: impl_base
{
@@ -64,7 +64,7 @@ namespace boost
}
};
public:
BOOST_THREAD_MOVABLE(nullary_function)
BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function)
explicit nullary_function(void (*f)()):
impl(new impl_type_ptr(f))
@@ -90,29 +90,39 @@ namespace boost
{
}
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=(nullary_function const& other) BOOST_NOEXCEPT
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()()
{ impl->call();}
{ if (impl) impl->call();}
};
@@ -126,7 +136,7 @@ namespace boost
{
}
};
shared_ptr<impl_base> impl;
csbl::shared_ptr<impl_base> impl;
template <typename F>
struct impl_type: impl_base
{
@@ -158,7 +168,7 @@ namespace boost
}
};
public:
BOOST_THREAD_MOVABLE(nullary_function)
BOOST_THREAD_COPYABLE_AND_MOVABLE(nullary_function)
nullary_function(R (*f)()):
impl(new impl_type_ptr(f))
@@ -179,10 +189,16 @@ namespace boost
{
}
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()
{
@@ -191,23 +207,28 @@ namespace boost
{
}
nullary_function& operator=(nullary_function const& other) BOOST_NOEXCEPT
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()()
{ return impl->call();}
{ 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

View File

@@ -7,6 +7,7 @@
// (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
@@ -291,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
):
@@ -301,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))
{

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
// 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)
@@ -36,7 +36,7 @@ namespace executors
typedef csbl::vector<thread_t> thread_vector;
/// the thread safe work queue
sync_queue<work > work_queue;
concurrent::sync_queue<work > work_queue;
/// A move aware vector
thread_vector threads;
@@ -48,9 +48,9 @@ namespace executors
*/
bool try_executing_one()
{
work task;
try
{
work task;
if (work_queue.try_pull_front(task) == queue_op_status::success)
{
task();
@@ -58,12 +58,9 @@ namespace executors
}
return false;
}
catch (std::exception& )
{
return false;
}
catch (...)
{
std::terminate();
return false;
}
}
@@ -85,12 +82,20 @@ namespace executors
*/
void worker_thread()
{
while (!closed())
try
{
schedule_one_or_yield();
for(;;)
{
work task;
queue_op_status st = work_queue.wait_pull_front(task);
if (st == queue_op_status::closed) return;
task();
}
}
while (try_executing_one())
catch (...)
{
std::terminate();
return;
}
}
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
@@ -98,37 +103,19 @@ namespace executors
void worker_thread1(AtThreadEntry& at_thread_entry)
{
at_thread_entry(*this);
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
worker_thread();
}
#endif
void worker_thread2(void(*at_thread_entry)(basic_thread_pool&))
{
at_thread_entry(*this);
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
worker_thread();
}
template <class AtThreadEntry>
void worker_thread3(BOOST_THREAD_FWD_REF(AtThreadEntry) at_thread_entry)
{
at_thread_entry(*this);
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
worker_thread();
}
static void do_nothing_at_thread_entry(basic_thread_pool&) {}
@@ -141,7 +128,7 @@ namespace executors
*
* \b Throws: Whatever exception is thrown while initializing the needed resources.
*/
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency())
basic_thread_pool(unsigned const thread_count = thread::hardware_concurrency()+1)
{
try
{
@@ -238,6 +225,17 @@ namespace executors
// 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.
@@ -271,33 +269,20 @@ namespace executors
template <typename Closure>
void submit(Closure & closure)
{
//work w ((closure));
//work_queue.push_back(boost::move(w));
work_queue.push_back(work(closure)); // todo check why this doesn't work
work_queue.push_back(work(closure));
}
#endif
void submit(void (*closure)())
{
//work w ((closure));
//work_queue.push_back(boost::move(w));
work_queue.push_back(work(closure)); // todo check why this doesn't work
work_queue.push_back(work(closure));
}
#if 0
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w = boost::move(closure);
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
}
#else
template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
work_queue.push_back(work(boost::forward<Closure>(closure)));
}
#endif
/**
* \b Requires: This must be called from an scheduled task.
*

View File

@@ -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

View File

@@ -32,43 +32,55 @@ namespace boost
executor() {}
/**
* \b Effects: Destroys the executor.
* \par Effects
* Destroys the executor.
*
* \b Synchronization: The completion of all the closures happen before the completion of the executor destructor.
* \par Synchronization
* The completion of all the closures happen before the completion of the executor destructor.
*/
virtual ~executor() {};
/**
* \b Effects: close the \c executor for submissions.
* \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;
/**
* \b Returns: whether the pool is closed for submissions.
* \par Returns
* Whether the pool is closed for submissions.
*/
virtual bool closed() = 0;
/**
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* \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.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
* \par Synchronization
* Ccompletion 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.
* \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;
/**
* \b Requires: \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
* \par Requires
* \c Closure is a model of Callable(void()) and a model of CopyConstructible/MoveConstructible.
*
* \b Effects: The specified closure will be scheduled for execution at some point in the future.
* \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.
*
* \b Synchronization: completion of closure on a particular thread happens before destruction of thread's thread local variables.
* \par 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.
* \par Throws
* \c sync_queue_is_closed if the thread pool is closed.
* Whatever exception that can be throw while storing the closure.
*/
@@ -94,16 +106,23 @@ namespace boost
}
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
* Throws: whatever the current task constructor throws or the task() throws.
* \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;
/**
* \b Requires: This must be called from an scheduled task.
* \par Requires
* This must be called from an scheduled task.
*
* \b Effects: reschedule functions until pred()
* \par Effects
* Reschedule functions until pred()
*/
template <typename Pred>
bool reschedule_until(Pred const& pred)
@@ -119,7 +138,6 @@ namespace boost
}
};
}
using executors::executor;
}

View File

@@ -97,39 +97,28 @@ namespace executors
*/
void submit(BOOST_THREAD_RV_REF(work) closure) {
return ex.submit(boost::move(closure));
//return ex.submit(boost::forward<work>(closure));
}
// void submit(work & closure) {
// return ex.submit(closure);
// }
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
submit(boost::move(w));
//submit(work(closure));
submit(work(closure));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
submit(boost::move(w));
//submit(work(closure));
submit(work(closure));
}
#if 0
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
submit(boost::move(w));
}
#else
template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
submit(work(boost::forward<Closure>(closure)));
}
#endif
/**
* Effects: try to execute one task.

View 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

View File

@@ -26,6 +26,7 @@ namespace executors
/// type-erasure to store the works to do
typedef executors::work work;
bool closed_;
mutable mutex mtx_;
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
@@ -66,16 +67,22 @@ namespace executors
*/
void close()
{
lock_guard<mutex> lk(mtx_);
closed_ = true;
}
/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed()
bool closed(lock_guard<mutex>& )
{
return closed_;
}
bool closed()
{
lock_guard<mutex> lk(mtx_);
return closed(lk);
}
/**
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
@@ -93,21 +100,54 @@ namespace executors
template <typename Closure>
void submit(Closure & closure)
{
if (closed()) return;
closure();
{
lock_guard<mutex> lk(mtx_);
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
}
try
{
closure();
}
catch (...)
{
std::terminate();
return;
}
}
#endif
void submit(void (*closure)())
{
if (closed()) return;
closure();
{
lock_guard<mutex> lk(mtx_);
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
}
try
{
closure();
}
catch (...)
{
std::terminate();
return;
}
}
template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
if (closed()) return;
closure();
{
lock_guard<mutex> lk(mtx_);
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
}
try
{
closure();
}
catch (...)
{
std::terminate();
return;
}
}
/**

View File

@@ -31,7 +31,7 @@ namespace executors
typedef executors::work work;
private:
/// the thread safe work queue
sync_queue<work > work_queue;
concurrent::sync_queue<work > work_queue;
public:
/**
@@ -51,12 +51,9 @@ namespace executors
}
return false;
}
catch (std::exception& )
{
return false;
}
catch (...)
{
std::terminate();
return false;
}
}
@@ -74,19 +71,7 @@ namespace executors
}
/**
* The main loop of the worker thread
*/
void worker_thread()
{
while (!closed())
{
schedule_one_or_yield();
}
while (try_executing_one())
{
}
}
public:
/// loop_executor is not copyable.
@@ -112,9 +97,19 @@ namespace executors
}
/**
* loop
* The main loop of the worker thread
*/
void loop() { 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.
@@ -148,24 +143,18 @@ namespace executors
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
work_queue.push_back(boost::move(w));
//work_queue.push(work(closure)); // todo check why this doesn't work
work_queue.push_back(work(closure));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(closure)); // todo check why this doesn't work
work_queue.push_back(work(closure));
}
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
work_queue.push_back(work(boost::forward<Closure>(closure)));
}
/**
@@ -184,17 +173,18 @@ namespace executors
} 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())
while (! q.empty())
{
work task = q.front();
q.pop_front();
work& task = q.front();
task();
q.pop_front();
}
}

View File

@@ -0,0 +1,68 @@
// Copyright (C) 2014 Ian Forbed
// Copyright (C) 2014 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
#define BOOST_THREAD_EXECUTORS_SCHEDULED_THREAD_POOL_HPP
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
namespace boost
{
namespace executors
{
class scheduled_thread_pool : public detail::scheduled_executor_base
{
private:
thread_group _workers;
public:
scheduled_thread_pool(size_t num_threads) : super()
{
for(size_t i = 0; i < num_threads; i++)
{
_workers.create_thread(bind(&super::loop, this));
}
}
~scheduled_thread_pool()
{
this->close();
_workers.join_all();
}
private:
typedef detail::scheduled_executor_base super;
inline void loop();
}; //end class
void scheduled_thread_pool::loop()
{
try
{
for(;;)
{
super::work task;
queue_op_status st = super::_workq.wait_pull(task);
if (st == queue_op_status::closed) return;
task();
}
}
catch (...)
{
std::terminate();
return;
}
}
} //end executors namespace
using executors::scheduled_thread_pool;
} //end boost
#endif

View File

@@ -0,0 +1,259 @@
// Copyright (C) 2014 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
#define BOOST_THREAD_EXECUTORS_SCHEDULER_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
#include <boost/chrono/system_clocks.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace executors
{
/// Wraps the reference to an executor and a function to make a work that submit the function using the executor.
template <class Executor, class Function>
class resubmitter
{
public:
resubmitter(Executor& ex, Function funct) :
ex(ex),
funct(boost::move(funct))
{}
void operator()()
{
ex.submit(funct);
}
private:
Executor& ex;
Function funct;
};
/// resubmitter factory
template <class Executor, class Function>
resubmitter<Executor, typename decay<Function>::type>
resubmit(Executor& ex, BOOST_THREAD_FWD_REF(Function) funct) {
return resubmitter<Executor, typename decay<Function>::type >(ex, boost::move(funct));
}
/// Wraps references to a @c Scheduler and an @c Executor providing an @c Executor that
/// resubmit the function using the referenced Executor at a given @c time_point known at construction.
template <class Scheduler, class Executor>
class resubmit_at_executor
{
public:
typedef chrono::steady_clock clock;
resubmit_at_executor(Scheduler& sch, Executor& ex, clock::time_point const& tp) :
sch(sch),
ex(ex),
tp(tp),
is_closed(false)
{
}
~resubmit_at_executor()
{
close();
}
template <class Work>
void submit(BOOST_THREAD_FWD_REF(Work) w)
{
if (closed())
{
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
}
sch.submit_at(resubmit(ex,boost::forward<Work>(w)), tp);
}
Executor& underlying_executor()
{
return ex;
}
Scheduler& underlying_scheduler()
{
return sch;
}
void close()
{
is_closed = true;
}
bool closed()
{
return is_closed || sch.closed() || ex.closed();
}
private:
Scheduler& sch;
Executor& ex;
clock::time_point tp;
bool is_closed;
};
/// Expression template helper storing a pair of references to an @c Scheduler and an @c Executor
/// It provides factory helper functions such as at/after that convert these a pair of @c Scheduler @c Executor
/// into an new @c Executor that submit the work using the referenced @c Executor at/after a specific time/duration
/// respectively, using the referenced @Scheduler.
template <class Scheduler, class Executor>
class scheduler_executor_wrapper
{
public:
typedef chrono::steady_clock clock;
typedef resubmit_at_executor<Scheduler, Executor> the_executor;
scheduler_executor_wrapper(Scheduler& sch, Executor& ex) :
sch(sch),
ex(ex)
{}
~scheduler_executor_wrapper()
{
}
Executor& underlying_executor()
{
return ex;
}
Scheduler& underlying_scheduler()
{
return sch;
}
template <class Duration>
the_executor after(Duration const& rel_time)
{
return at(clock::now() + rel_time );
}
the_executor at(clock::time_point const& abs_time)
{
return the_executor(sch, ex, abs_time);
}
private:
Scheduler& sch;
Executor& ex;
}; //end class
/// Wraps a reference to a @c Scheduler providing an @c Executor that
/// run the function at a given @c time_point known at construction.
template <class Scheduler>
class at_executor
{
public:
typedef chrono::steady_clock clock;
at_executor(Scheduler& sch, clock::time_point const& tp) :
sch(sch),
tp(tp),
is_closed(false)
{}
~at_executor()
{
close();
}
Scheduler& underlying_scheduler()
{
return sch;
}
void close()
{
is_closed = true;
}
bool closed()
{
return is_closed || sch.closed();
}
template <class Work>
void submit(BOOST_THREAD_FWD_REF(Work) w)
{
if (closed())
{
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
}
sch.submit_at(boost::forward<Work>(w), tp);
}
template <class Executor>
resubmit_at_executor<Scheduler, Executor> on(Executor& ex)
{
return resubmit_at_executor<Scheduler, Executor>(sch, ex, tp);
}
private:
Scheduler& sch;
clock::time_point tp;
bool is_closed;
}; //end class
/// A @c Scheduler using a specific thread. Note that a Scheduler is not an Executor.
/// It provides factory helper functions such as at/after that convert a @c Scheduler into an @c Executor
/// that submit the work at/after a specific time/duration respectively.
class scheduler : public detail::scheduled_executor_base
{
public:
typedef chrono::steady_clock clock;
typedef clock::time_point time_point;
scheduler()
: super(),
thr(&super::loop, this) {}
~scheduler()
{
this->close();
thr.join();
}
template <class Ex>
scheduler_executor_wrapper<scheduler, Ex> on(Ex& ex)
{
return scheduler_executor_wrapper<scheduler, Ex>(*this, ex);
}
template <class Duration>
at_executor<scheduler> after(Duration const& rel_time)
{
return at(rel_time + clock::now());
}
at_executor<scheduler> at(time_point const& tp)
{
return at_executor<scheduler>(*this, tp);
}
private:
typedef detail::scheduled_executor_base super;
thread thr;
};
}
using executors::resubmitter;
using executors::resubmit;
using executors::resubmit_at_executor;
using executors::scheduler_executor_wrapper;
using executors::at_executor;
using executors::scheduler;
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,72 @@
// Copyright (C) 2014 Ian Forbed
// Copyright (C) 2014 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
#define BOOST_THREAD_EXECUTORS_SCHEDULING_ADAPTOR_HPP
#include <boost/thread/executors/detail/scheduled_executor_base.hpp>
namespace boost
{
namespace executors
{
template <typename Executor>
class scheduling_adpator : public detail::scheduled_executor_base
{
private:
Executor& _exec;
thread _scheduler;
public:
scheduling_adpator(Executor& ex)
: super(),
_exec(ex),
_scheduler(&scheduling_adpator::loop, this) {}
~scheduling_adpator()
{
this->close();
_scheduler.join();
}
Executor& underlying_executor()
{
return _exec;
}
private:
typedef detail::scheduled_executor_base super;
void loop();
}; //end class
template<typename Executor>
void scheduling_adpator<Executor>::loop()
{
try
{
for(;;)
{
super::work task;
queue_op_status st = super::_workq.wait_pull(task);
if (st == queue_op_status::closed) return;
_exec.submit(task);
}
}
catch (...)
{
std::terminate();
return;
}
}
} //end executors
using executors::scheduling_adpator;
} //end boost
#endif

View File

@@ -14,7 +14,7 @@
#include <boost/thread/detail/move.hpp>
#include <boost/thread/sync_queue.hpp>
#include <boost/thread/executors/work.hpp>
#include <boost/thread/executors/executor.hpp>
#include <boost/thread/executors/generic_executor_ref.hpp>
#include <boost/thread/future.hpp>
#include <boost/thread/scoped_thread.hpp>
@@ -33,8 +33,8 @@ namespace executors
typedef scoped_thread<> thread_t;
/// the thread safe work queue
sync_queue<work > work_queue;
executor& ex;
concurrent::sync_queue<work > work_queue;
generic_executor_ref ex;
thread_t thr;
struct try_executing_one_task {
@@ -43,11 +43,17 @@ namespace executors
try_executing_one_task(work& task, boost::promise<void> &p)
: task(task), p(p) {}
void operator()() {
task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
task();
p.set_value();
}
};
public:
/**
* \par Returns
* The underlying executor wrapped on a generic executor reference.
*/
generic_executor_ref& underlying_executor() BOOST_NOEXCEPT { return ex; }
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
@@ -63,22 +69,14 @@ namespace executors
boost::promise<void> p;
try_executing_one_task tmp(task,p);
ex.submit(tmp);
// ex.submit([&task, &p]()
// {
// task(); // if task() throws promise is not set but as the the program terminates and should terminate there is no need to use try-catch here.
// p.set_value();
// });
p.get_future().wait();
return true;
}
return false;
}
catch (std::exception& )
{
return false;
}
catch (...)
{
std::terminate();
return false;
}
}
@@ -118,7 +116,8 @@ namespace executors
*
* \b Throws: Whatever exception is thrown while initializing the needed resources.
*/
serial_executor(executor& ex)
template <class Executor>
serial_executor(Executor& ex)
: ex(ex), thr(&serial_executor::worker_thread, this)
{
}
@@ -129,7 +128,7 @@ namespace executors
*/
~serial_executor()
{
// signal to all the worker thread that there will be no more submissions.
// signal to the worker thread that there will be no more submissions.
close();
}
@@ -166,24 +165,18 @@ namespace executors
template <typename Closure>
void submit(Closure & closure)
{
work w ((closure));
work_queue.push_back(boost::move(w));
//work_queue.push(work(closure)); // todo check why this doesn't work
work_queue.push_back(work(closure));
}
#endif
void submit(void (*closure)())
{
work w ((closure));
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(closure)); // todo check why this doesn't work
work_queue.push_back(work(closure));
}
template <typename Closure>
void submit(BOOST_THREAD_RV_REF(Closure) closure)
{
work w =boost::move(closure);
work_queue.push_back(boost::move(w));
//work_queue.push_back(work(boost::move(closure))); // todo check why this doesn't work
work_queue.push_back(work(boost::forward<Closure>(closure)));
}
/**

View File

@@ -15,6 +15,8 @@
#include <boost/thread/executors/work.hpp>
#include <boost/thread/executors/executor.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/csbl/vector.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -28,6 +30,11 @@ namespace executors
/// type-erasure to store the works to do
typedef executors::work work;
bool closed_;
typedef scoped_thread<> thread_t;
typedef csbl::vector<thread_t> threads_type;
threads_type threads_;
mutable mutex mtx_;
/**
* Effects: try to execute one task.
* Returns: whether a task has been executed.
@@ -52,7 +59,7 @@ namespace executors
{
}
/**
* \b Effects: Destroys the inline executor.
* \b Effects: Waits for closures (if any) to complete, then joins and destroys the threads.
*
* \b Synchronization: The completion of all the closures happen before the completion of the \c thread_executor destructor.
*/
@@ -60,6 +67,7 @@ namespace executors
{
// signal to all the worker thread that there will be no more submissions.
close();
// all the scoped threads will join before destroying
}
/**
@@ -68,16 +76,22 @@ namespace executors
*/
void close()
{
lock_guard<mutex> lk(mtx_);
closed_ = true;
}
/**
* \b Returns: whether the pool is closed for submissions.
*/
bool closed()
bool closed(lock_guard<mutex>& )
{
return closed_;
}
bool closed()
{
lock_guard<mutex> lk(mtx_);
return closed(lk);
}
/**
* \b Requires: \c Closure is a model of \c Callable(void()) and a model of \c CopyConstructible/MoveConstructible.
@@ -95,24 +109,30 @@ namespace executors
template <typename Closure>
void submit(Closure & closure)
{
if (closed()) return;
lock_guard<mutex> lk(mtx_);
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
threads_.reserve(threads_.size() + 1);
thread th(closure);
th.detach();
threads_.push_back(thread_t(boost::move(th)));
}
#endif
void submit(void (*closure)())
{
if (closed()) return;
lock_guard<mutex> lk(mtx_);
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
threads_.reserve(threads_.size() + 1);
thread th(closure);
th.detach();
threads_.push_back(thread_t(boost::move(th)));
}
template <typename Closure>
void submit(BOOST_THREAD_FWD_REF(Closure) closure)
{
if (closed()) return;
lock_guard<mutex> lk(mtx_);
if (closed(lk)) BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
threads_.reserve(threads_.size() + 1);
thread th(boost::forward<Closure>(closure));
th.detach();
threads_.push_back(thread_t(boost::move(th)));
}
/**

View File

@@ -7,6 +7,15 @@
#ifndef BOOST_THREAD_EXECUTORS_WORK_HPP
#define BOOST_THREAD_EXECUTORS_WORK_HPP
#include <boost/thread/detail/config.hpp>
#if ! defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE \
&& ! defined BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE
#define BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE
//#define BOOST_THREAD_EXECUTORS_WORK_DONT_ACCEPT_MOVABLE
#endif
#if defined BOOST_THREAD_EXECUTORS_WORK_ACCEPTS_MOVABLE
#include <boost/thread/detail/nullary_function.hpp>
@@ -18,4 +27,17 @@ namespace boost
}
} // namespace boost
#else
#include <boost/thread/csbl/functional.hpp>
namespace boost
{
namespace executors
{
typedef csbl::function<void()> work;
}
} // namespace boost
#endif
#endif // BOOST_THREAD_EXECUTORS_WORK_HPP

View File

@@ -0,0 +1,23 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP
#define BOOST_THREAD_EXPERIMENTAL_CONFIG_INLINE_NAMESPACE_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/config.hpp>
#if !defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
# define BOOST_THREAD_INLINE_NAMESPACE(name) inline namespace name
#else
# define BOOST_THREAD_INLINE_NAMESPACE(name) namespace name
#endif
#endif

View File

@@ -0,0 +1,16 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP
#define BOOST_THREAD_EXPERIMENTAL_EXCEPTION_LIST_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/thread/experimental/parallel/v1/exception_list.hpp>
#endif

View File

@@ -0,0 +1,70 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_EXCEPTION_LIST_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/thread/detail/config.hpp>
#include <boost/thread/experimental/parallel/v1/inline_namespace.hpp>
#include <boost/exception_ptr.hpp>
#include <exception>
#include <list>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace experimental
{
namespace parallel
{
BOOST_THREAD_INLINE_NAMESPACE(v1)
{
class BOOST_SYMBOL_VISIBLE exception_list: public std::exception
{
typedef std::list<exception_ptr> exception_ptr_list;
exception_ptr_list list_;
public:
typedef exception_ptr_list::const_iterator const_iterator;
~exception_list() BOOST_NOEXCEPT_OR_NOTHROW {}
void add(exception_ptr const& e)
{
list_.push_back(e);
}
size_t size() const BOOST_NOEXCEPT
{
return list_.size();
}
const_iterator begin() const BOOST_NOEXCEPT
{
return list_.begin();
}
const_iterator end() const BOOST_NOEXCEPT
{
return list_.end();
}
const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
{
return "exception_list";
}
};
}
} // parallel
} // experimental
} // boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,28 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V1_INLINE_NAMESPACE_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/thread/experimental/config/inline_namespace.hpp>
namespace boost {
namespace experimental {
namespace parallel {
BOOST_THREAD_INLINE_NAMESPACE(v1) {}
#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
using namespace v1;
#endif
}
}
}
#endif

View File

@@ -0,0 +1,29 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_INLINE_NAMESPACE_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/thread/experimental/config/inline_namespace.hpp>
namespace boost {
namespace experimental {
namespace parallel {
BOOST_THREAD_INLINE_NAMESPACE(v2) {}
#if defined(BOOST_NO_CXX11_INLINE_NAMESPACES)
using namespace v2;
#endif
}
}
}
#endif

View File

@@ -0,0 +1,316 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the 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.
//
//////////////////////////////////////////////////////////////////////////////
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR
#include <boost/thread/detail/config.hpp>
#include <boost/thread/future.hpp>
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
#include <boost/thread/executors/basic_thread_pool.hpp>
#endif
#include <boost/thread/experimental/exception_list.hpp>
#include <boost/thread/experimental/parallel/v2/inline_namespace.hpp>
#include <boost/config/abi_prefix.hpp>
#define BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
namespace boost
{
namespace experimental
{
namespace parallel
{
BOOST_THREAD_INLINE_NAMESPACE(v2)
{
class BOOST_SYMBOL_VISIBLE task_canceled_exception: public std::exception
{
public:
//task_canceled_exception() BOOST_NOEXCEPT {}
//task_canceled_exception(const task_canceled_exception&) BOOST_NOEXCEPT {}
//task_canceled_exception& operator=(const task_canceled_exception&) BOOST_NOEXCEPT {}
virtual const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
{ return "task_canceled_exception";}
};
template <class Executor>
class task_region_handle_gen;
namespace detail
{
void handle_task_region_exceptions(exception_list& errors)
{
try {
boost::rethrow_exception(boost::current_exception());
//throw boost::current_exception();
}
catch (task_canceled_exception& ex)
{
}
catch (exception_list const& el)
{
for (boost::exception_ptr const& e: el)
{
try {
rethrow_exception(e);
}
catch (...)
{
handle_task_region_exceptions(errors);
}
}
}
catch (...)
{
errors.add(boost::current_exception());
}
}
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
template <class TRH, class F>
struct wrapped
{
TRH& tr;
F f;
wrapped(TRH& tr, F&& f) : tr(tr), f(move(f))
{}
void operator()()
{
try
{
f();
}
catch (...)
{
lock_guard<mutex> lk(tr.mtx);
tr.canceled = true;
handle_task_region_exceptions(tr.exs);
}
}
};
#endif
}
template <class Executor>
class task_region_handle_gen
{
private:
// Private members and friends
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
template <class TRH, class F>
friend struct detail::wrapped;
#endif
template <typename F>
friend void task_region(F&& f);
template<typename F>
friend void task_region_final(F&& f);
template <class Ex, typename F>
friend void task_region(Ex&, F&& f);
template<class Ex, typename F>
friend void task_region_final(Ex&, F&& f);
void wait_all()
{
wait_for_all(group.begin(), group.end());
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
for (future<void>& f: group)
{
if (f.has_exception())
{
try
{
boost::rethrow_exception(f.get_exception_ptr());
}
catch (...)
{
detail::handle_task_region_exceptions(exs);
}
}
}
#endif
if (exs.size() != 0)
{
boost::throw_exception(exs);
//throw exs;
}
}
protected:
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
{}
#endif
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
: canceled(false)
, ex(0)
{}
task_region_handle_gen(Executor& ex)
: canceled(false)
, ex(&ex)
{}
#endif
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
: ex(0)
{}
task_region_handle_gen(Executor& ex)
: ex(&ex)
{}
#endif
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
: canceled(false)
{
}
#endif
~task_region_handle_gen()
{
//wait_all();
}
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
bool canceled;
#endif
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
Executor* ex;
#endif
exception_list exs;
csbl::vector<future<void>> group;
mutable mutex mtx;
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)
{
lock_guard<mutex> lk(mtx);
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
if (canceled) {
boost::throw_exception(task_canceled_exception());
//throw task_canceled_exception();
}
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
#else
group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
#endif
#else
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
group.push_back(async(*ex, forward<F>(f)));
#else
group.push_back(async(forward<F>(f)));
#endif
#endif
}
void wait()
{
lock_guard<mutex> lk(mtx);
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
if (canceled) {
boost::throw_exception(task_canceled_exception());
//throw task_canceled_exception{};
}
#endif
wait_all();
}
};
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
typedef basic_thread_pool default_executor;
#else
typedef int default_executor;
#endif
class task_region_handle :
public task_region_handle_gen<default_executor>
{
default_executor tp;
template <typename F>
friend void task_region(F&& f);
template<typename F>
friend void task_region_final(F&& f);
protected:
task_region_handle() : task_region_handle_gen<default_executor>()
{
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
ex = &tp;
#endif
}
task_region_handle(const task_region_handle&) = delete;
task_region_handle& operator=(const task_region_handle&) = delete;
task_region_handle* operator&() const = delete;
};
template <typename Executor, typename F>
void task_region_final(Executor& ex, F&& f)
{
task_region_handle_gen<Executor> tr(ex);
try
{
f(tr);
}
catch (...)
{
lock_guard<mutex> lk(tr.mtx);
detail::handle_task_region_exceptions(tr.exs);
}
tr.wait_all();
}
template <typename Executor, typename F>
void task_region(Executor& ex, F&& f)
{
task_region_final(ex, forward<F>(f));
}
template <typename F>
void task_region_final(F&& f)
{
task_region_handle tr;
try
{
f(tr);
}
catch (...)
{
lock_guard<mutex> lk(tr.mtx);
detail::handle_task_region_exceptions(tr.exs);
}
tr.wait_all();
}
template <typename F>
void task_region(F&& f)
{
task_region_final(forward<F>(f));
}
} // v2
} // parallel
} // experimental
} // boost
#include <boost/config/abi_suffix.hpp>
#endif
#endif

View File

@@ -0,0 +1,16 @@
#ifndef BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP
#define BOOST_THREAD_EXPERIMENTAL_TASK_REGION_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <boost/thread/experimental/parallel/v2/task_region.hpp>
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -27,14 +27,14 @@ namespace boost
/// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero.
/// Returns: true if count_ reached the value 0.
/// @ThreadSafe ensured by the @c lk parameter
bool count_down(unique_lock<mutex> &lk)
bool count_down(unique_lock<mutex> &)
/// pre_condition (count_ > 0)
{
BOOST_ASSERT(count_ > 0);
if (--count_ == 0)
{
++generation_;
lk.unlock();
//lk.unlock();
cond_.notify_all();
return true;
}

View File

@@ -160,7 +160,7 @@ namespace boost
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
boost::throw_exception(thread_resource_error(res, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
boost::throw_exception(thread_resource_error(res2, "boost::condition_variable_any::condition_variable_any() failed in pthread_cond_init"));
}
}
~condition_variable_any()

View File

@@ -3,7 +3,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2013. Distributed under the Boost
// (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)
//
@@ -11,723 +11,6 @@
//
//////////////////////////////////////////////////////////////////////////////
#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>
#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
{
BOOST_SCOPED_ENUM_DECLARE_BEGIN(queue_op_status)
{ success = 0, empty, full, closed, busy }
BOOST_SCOPED_ENUM_DECLARE_END(queue_op_status)
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
struct no_block_tag{};
BOOST_CONSTEXPR_OR_CONST no_block_tag no_block = {};
#endif
struct sync_queue_is_closed : std::exception
{
};
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;
}
}
#include <boost/config/abi_suffix.hpp>
#include <boost/thread/concurrent_queues/sync_bounded_queue.hpp>
#endif

View File

@@ -3,7 +3,7 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2013. Distributed under the Boost
// (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)
//
@@ -11,651 +11,6 @@
//
//////////////////////////////////////////////////////////////////////////////
#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/smart_ptr/shared_ptr.hpp>
#include <boost/smart_ptr/make_shared.hpp>
#include <boost/thread/sync_bounded_queue.hpp>
#include <boost/thread/csbl/deque.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
template <typename ValueType>
class sync_queue
{
public:
typedef ValueType value_type;
typedef csbl::deque<ValueType> underlying_queue_type;
typedef std::size_t size_type;
typedef queue_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();
// Observers
inline bool empty() const;
inline bool full() 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 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);
inline underlying_queue_type underlying_queue() {
lock_guard<mutex> lk(mtx_);
return boost::move(data_);
}
private:
mutable mutex mtx_;
condition_variable not_empty_;
size_type waiting_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 void throw_if_closed(unique_lock<mutex>&);
inline bool closed(unique_lock<mutex>& lk) const;
#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);
inline void wait_until_not_empty(unique_lock<mutex>& lk);
inline void wait_until_not_empty(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();
}
}
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
inline void pull(value_type& elem, unique_lock<mutex>& )
{
elem = boost::move(data_.front());
data_.pop_front();
}
inline value_type pull(unique_lock<mutex>& )
{
value_type e = boost::move(data_.front());
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(data_.front()));
data_.pop_front();
return res;
}
#endif
inline void pull_front(value_type& elem, unique_lock<mutex>& )
{
elem = boost::move(data_.front());
data_.pop_front();
}
inline value_type pull_front(unique_lock<mutex>& )
{
value_type e = boost::move(data_.front());
data_.pop_front();
return boost::move(e);
}
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
inline void push(const value_type& elem, unique_lock<mutex>& lk)
{
data_.push_back(elem);
notify_not_empty_if_needed(lk);
}
inline void push(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
{
data_.push_back(boost::move(elem));
notify_not_empty_if_needed(lk);
}
#endif
inline void push_back(const value_type& elem, unique_lock<mutex>& lk)
{
data_.push_back(elem);
notify_not_empty_if_needed(lk);
}
inline void push_back(BOOST_THREAD_RV_REF(value_type) elem, unique_lock<mutex>& lk)
{
data_.push_back(boost::move(elem));
notify_not_empty_if_needed(lk);
}
};
template <typename ValueType>
sync_queue<ValueType>::sync_queue() :
waiting_empty_(0), data_(), closed_(false)
{
BOOST_ASSERT(data_.empty());
}
// template <typename ValueType>
// template <typename Range>
// explicit sync_queue<ValueType>::sync_queue(Range range) :
// waiting_empty_(0), 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()
{
}
template <typename ValueType>
void sync_queue<ValueType>::close()
{
{
lock_guard<mutex> lk(mtx_);
closed_ = true;
}
not_empty_.notify_all();
}
template <typename ValueType>
bool sync_queue<ValueType>::closed() const
{
lock_guard<mutex> lk(mtx_);
return closed_;
}
template <typename ValueType>
bool sync_queue<ValueType>::closed(unique_lock<mutex>&) const
{
return closed_;
}
template <typename ValueType>
bool sync_queue<ValueType>::empty() const
{
lock_guard<mutex> lk(mtx_);
return empty(lk);
}
template <typename ValueType>
bool sync_queue<ValueType>::full() const
{
return false;
}
template <typename ValueType>
typename sync_queue<ValueType>::size_type sync_queue<ValueType>::size() const
{
lock_guard<mutex> lk(mtx_);
return size(lk);
}
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
template <typename ValueType>
bool sync_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_queue<ValueType>::try_pull(unique_lock<mutex>& lk)
{
if (empty(lk))
{
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 (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_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
{
if (empty(lk))
{
if (closed(lk)) return queue_op_status::closed;
}
bool has_been_closed = false;
wait_until_not_empty(lk, has_been_closed);
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(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(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(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(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(mtx_);
return try_pull(lk);
}
#endif
template <typename ValueType>
queue_op_status sync_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_queue<ValueType>::throw_if_closed(unique_lock<mutex>&)
{
if (closed_)
{
BOOST_THROW_EXCEPTION( sync_queue_is_closed() );
}
}
template <typename ValueType>
void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk)
{
for (;;)
{
if (! empty(lk)) break;
throw_if_closed(lk);
++waiting_empty_;
not_empty_.wait(lk);
}
}
template <typename ValueType>
void sync_queue<ValueType>::wait_until_not_empty(unique_lock<mutex>& lk, bool & closed)
{
for (;;)
{
if (! empty(lk)) break;
if (closed_) {closed=true; return;}
++waiting_empty_;
not_empty_.wait(lk);
}
closed=false;
}
#ifndef BOOST_THREAD_QUEUE_DEPRECATE_OLD
template <typename ValueType>
void sync_queue<ValueType>::pull(ValueType& elem)
{
unique_lock<mutex> lk(mtx_);
wait_until_not_empty(lk);
pull(elem, lk);
}
template <typename ValueType>
void sync_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_queue<ValueType>::pull()
{
unique_lock<mutex> lk(mtx_);
wait_until_not_empty(lk);
return pull(lk);
}
template <typename ValueType>
boost::shared_ptr<ValueType> sync_queue<ValueType>::ptr_pull()
{
unique_lock<mutex> lk(mtx_);
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(mtx_);
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(mtx_);
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)
{
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(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 (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(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 (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(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(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(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(mtx_);
throw_if_closed(lk);
push(elem, lk);
}
#endif
template <typename ValueType>
void sync_queue<ValueType>::push_back(const ValueType& elem)
{
unique_lock<mutex> lk(mtx_);
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)
{
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(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 (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(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 (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(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(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(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(mtx_);
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(mtx_);
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;
}
}
#include <boost/config/abi_suffix.hpp>
#include <boost/thread/concurrent_queues/sync_queue.hpp>
#endif

View File

@@ -19,10 +19,10 @@ namespace boost
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
@@ -42,16 +42,16 @@ namespace boost
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
@@ -60,10 +60,10 @@ namespace boost
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
typedef T element_type;
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}
@@ -87,7 +87,7 @@ namespace boost
{
return get();
}
T& operator*() const
typename boost::detail::sp_dereference< T >::type operator*() const
{
return *get();
}

View File

@@ -81,7 +81,7 @@ namespace boost
do
{
unsigned const retval(win32::WaitForSingleObject(sem, ::boost::detail::win32::infinite));
unsigned const retval(win32::WaitForSingleObjectEx(sem, ::boost::detail::win32::infinite,0));
BOOST_VERIFY(0 == retval || ::boost::detail::win32::wait_abandoned == retval);
// BOOST_VERIFY(win32::WaitForSingleObject(
// sem,::boost::detail::win32::infinite)==0);
@@ -142,7 +142,7 @@ namespace boost
do
{
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
if(win32::WaitForSingleObjectEx(sem,::boost::detail::get_milliseconds_until(wait_until),0)!=0)
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
@@ -203,9 +203,14 @@ namespace boost
do
{
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
chrono::time_point<chrono::system_clock, chrono::system_clock::duration> now = chrono::system_clock::now();
if (tp<=now) {
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-now);
if(win32::WaitForSingleObject(sem,static_cast<unsigned long>(rel_time.count()))!=0)
if(win32::WaitForSingleObjectEx(sem,static_cast<unsigned long>(rel_time.count()),0)!=0)
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;

View File

@@ -96,7 +96,7 @@ namespace boost
bool woken()
{
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0);
unsigned long const woken_result=detail::win32::WaitForSingleObjectEx(wake_sem,0,0);
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
return woken_result==0;
}

View File

@@ -17,34 +17,29 @@
#ifdef BOOST_MSVC
extern "C" void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
namespace boost
{
namespace detail
{
// Since VS2005 volatile reads always acquire
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
long const res=*x;
_ReadWriteBarrier();
return res;
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
void* const res=*x;
_ReadWriteBarrier();
return res;
}
// Since VS2005 volatile writes always release
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
_ReadWriteBarrier();
*x=value;
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
_ReadWriteBarrier();
*x=value;
}
}

View File

@@ -152,14 +152,11 @@ namespace boost
{
name_once_mutex(mutex_name,flag_address);
}
#ifdef BOOST_NO_ANSI_APIS
return ::boost::detail::win32::CreateEventW(
#else
return ::boost::detail::win32::CreateEventA(
#endif
0,::boost::detail::win32::manual_reset_event,
::boost::detail::win32::event_initially_reset,
mutex_name);
return ::boost::detail::win32::create_event(
mutex_name,
::boost::detail::win32::manual_reset_event,
::boost::detail::win32::event_initially_reset);
}
struct once_context {
@@ -267,8 +264,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite, 0));
}
}
//#endif
@@ -311,8 +308,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, class A, class ...ArgTypes>
@@ -358,8 +355,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
#else
@@ -403,8 +400,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1>
@@ -446,8 +443,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2>
@@ -489,8 +486,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2, typename T3>
@@ -532,8 +529,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
#elif defined BOOST_NO_CXX11_RVALUE_REFERENCES
@@ -577,8 +574,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1>
@@ -620,8 +617,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2>
@@ -663,8 +660,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2, typename T3>
@@ -706,8 +703,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
#endif
@@ -751,8 +748,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename T1>
@@ -796,8 +793,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2>
@@ -842,8 +839,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2, typename T3>
@@ -889,8 +886,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
#endif
@@ -933,8 +930,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
@@ -980,8 +977,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2>
@@ -1027,8 +1024,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}
template<typename Function, typename T1, typename T2, typename T3>
@@ -1076,8 +1073,8 @@ namespace boost
continue;
}
}
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObject(
ctx.event_handle,::boost::detail::win32::infinite));
BOOST_VERIFY(!::boost::detail::win32::WaitForSingleObjectEx(
ctx.event_handle,::boost::detail::win32::infinite,0));
}
}

View File

@@ -75,7 +75,13 @@ namespace boost
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
void release_shared_waiters(state_data old_state)
{
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
public:
BOOST_THREAD_NO_COPYABLE(shared_mutex)
@@ -184,7 +190,7 @@ namespace boost
return true;
}
unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
unsigned long const res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until), 0);
if(res==detail::win32::timeout)
{
for(;;)
@@ -289,8 +295,8 @@ namespace boost
unsigned long res;
if (tp>n) {
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-n);
res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],
static_cast<unsigned long>(rel_time.count()));
res=detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],
static_cast<unsigned long>(rel_time.count()), 0);
} else {
res=detail::win32::timeout;
}
@@ -466,7 +472,7 @@ namespace boost
#else
const bool wait_all = false;
#endif
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until));
unsigned long const wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until), 0);
if(wait_res==detail::win32::timeout)
{
for(;;)
@@ -578,8 +584,8 @@ namespace boost
unsigned long wait_res;
if (tp>n) {
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,
static_cast<unsigned long>(rel_time.count()));
wait_res=detail::win32::WaitForMultipleObjectsEx(2,semaphores,wait_all,
static_cast<unsigned long>(rel_time.count()), 0);
} else {
wait_res=detail::win32::timeout;
}
@@ -690,7 +696,7 @@ namespace boost
return;
}
BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(semaphores[unlock_sem],detail::win32::infinite, 0));
}
}
@@ -750,6 +756,9 @@ namespace boost
{
release_waiters(old_state);
}
else {
release_shared_waiters(old_state);
}
// #7720
//else {
// release_waiters(old_state);
@@ -779,7 +788,7 @@ namespace boost
{
if(!last_reader)
{
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
BOOST_VERIFY(!detail::win32::WaitForSingleObjectEx(upgrade_sem,detail::win32::infinite, 0));
}
break;
}

View File

@@ -11,6 +11,8 @@
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/thread_heap_alloc.hpp>
#include <boost/predef/platform.h>
#include <boost/intrusive_ptr.hpp>
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
@@ -93,10 +95,18 @@ namespace boost
struct BOOST_THREAD_DECL thread_data_base
{
long count;
// Win32 threading APIs are not available in store apps so
// use abstraction on top of Windows::System::Threading.
#if BOOST_PLAT_WINDOWS_RUNTIME
detail::win32::scoped_winrt_thread thread_handle;
#else
detail::win32::handle_manager thread_handle;
#endif
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
std::map<void const*,boost::detail::tss_data_node> tss_data;
unsigned id;
std::map<void const*,boost::detail::tss_data_node> tss_data;
typedef std::vector<std::pair<condition_variable*, mutex*>
//, hidden_allocator<std::pair<condition_variable*, mutex*> >
> notify_list_t;
@@ -113,9 +123,11 @@ namespace boost
//#endif
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
thread_exit_callbacks(0),tss_data(),
count(0),
thread_handle(),
thread_exit_callbacks(0),
id(0),
tss_data(),
notify(),
async_states_()
//#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
@@ -173,14 +185,15 @@ namespace boost
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount64()()),
start(win32::GetTickCount64_()()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
relative(true)
//,
// abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount64()()),
start(win32::GetTickCount64_()()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
@@ -205,7 +218,7 @@ namespace boost
}
else if(relative)
{
win32::ticks_type const now=win32::GetTickCount64()();
win32::ticks_type const now=win32::GetTickCount64_()();
win32::ticks_type const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}

View File

@@ -11,6 +11,7 @@
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/predef/platform.h>
#include <boost/throw_exception.hpp>
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
@@ -18,6 +19,10 @@
//#include <boost/detail/winapi/synchronization.hpp>
#include <algorithm>
#if BOOST_PLAT_WINDOWS_RUNTIME
#include <thread>
#endif
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
@@ -28,40 +33,60 @@ namespace boost
namespace win32
{
typedef HANDLE handle;
typedef SYSTEM_INFO system_info;
typedef unsigned __int64 ticks_type;
unsigned const infinite=INFINITE;
unsigned const timeout=WAIT_TIMEOUT;
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
unsigned const event_modify_state=EVENT_MODIFY_STATE;
unsigned const synchronize=SYNCHRONIZE;
unsigned const wait_abandoned=WAIT_ABANDONED;
unsigned const create_event_initial_set = 0x00000002;
unsigned const create_event_manual_reset = 0x00000001;
unsigned const event_all_access = EVENT_ALL_ACCESS;
unsigned const semaphore_all_access = SEMAPHORE_ALL_ACCESS;
# ifdef BOOST_NO_ANSI_APIS
# if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
using ::CreateMutexW;
using ::CreateEventW;
using ::OpenEventW;
using ::CreateSemaphoreW;
# else
using ::CreateMutexExW;
using ::CreateEventExW;
using ::CreateSemaphoreExW;
# endif
using ::OpenEventW;
# else
using ::CreateMutexA;
using ::CreateEventA;
using ::OpenEventA;
using ::CreateSemaphoreA;
# endif
#if BOOST_PLAT_WINDOWS_RUNTIME
using ::GetNativeSystemInfo;
using ::GetTickCount64;
#else
using ::GetSystemInfo;
#endif
using ::CloseHandle;
using ::ReleaseMutex;
using ::ReleaseSemaphore;
using ::SetEvent;
using ::ResetEvent;
using ::WaitForMultipleObjects;
using ::WaitForSingleObject;
using ::WaitForMultipleObjectsEx;
using ::WaitForSingleObjectEx;
using ::GetCurrentProcessId;
using ::GetCurrentThreadId;
using ::GetCurrentThread;
using ::GetCurrentProcess;
using ::DuplicateHandle;
#if !BOOST_PLAT_WINDOWS_RUNTIME
using ::SleepEx;
using ::Sleep;
using ::QueueUserAPC;
#endif
}
}
}
@@ -82,13 +107,19 @@ extern "C" {
typedef int BOOL;
typedef unsigned long DWORD;
typedef void* HANDLE;
# include <kfuncs.h>
# ifdef __cplusplus
}
# endif
# endif
# ifdef __cplusplus
extern "C" {
# endif
struct _SYSTEM_INFO;
# ifdef __cplusplus
}
#endif
namespace boost
{
@@ -102,20 +133,32 @@ namespace boost
typedef unsigned long ulong_ptr;
# endif
typedef void* handle;
typedef _SYSTEM_INFO system_info;
typedef unsigned __int64 ticks_type;
unsigned const infinite=~0U;
unsigned const timeout=258U;
handle const invalid_handle_value=(handle)(-1);
unsigned const event_modify_state=2;
unsigned const synchronize=0x100000u;
unsigned const wait_abandoned=0x00000080u;
unsigned const create_event_initial_set = 0x00000002;
unsigned const create_event_manual_reset = 0x00000001;
unsigned const event_all_access = 0x1F0003;
unsigned const semaphore_all_access = 0x1F0003;
extern "C"
{
struct _SECURITY_ATTRIBUTES;
# ifdef BOOST_NO_ANSI_APIS
# if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
# else
__declspec(dllimport) void* __stdcall CreateMutexExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long);
__declspec(dllimport) void* __stdcall CreateEventExW(_SECURITY_ATTRIBUTES*,wchar_t const*,unsigned long,unsigned long);
__declspec(dllimport) void* __stdcall CreateSemaphoreExW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*,unsigned long,unsigned long);
# endif
__declspec(dllimport) void* __stdcall OpenEventW(unsigned long,int,wchar_t const*);
# else
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
@@ -123,16 +166,24 @@ namespace boost
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
__declspec(dllimport) void* __stdcall OpenEventA(unsigned long,int,char const*);
# endif
#if BOOST_PLAT_WINDOWS_RUNTIME
__declspec(dllimport) void __stdcall GetNativeSystemInfo(_SYSTEM_INFO*);
__declspec(dllimport) ticks_type __stdcall GetTickCount64();
#else
__declspec(dllimport) void __stdcall GetSystemInfo(_SYSTEM_INFO*);
#endif
__declspec(dllimport) int __stdcall CloseHandle(void*);
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObjectEx(void*,unsigned long,int);
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjectsEx(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds,int bAlertable);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
#if !BOOST_PLAT_WINDOWS_RUNTIME
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
__declspec(dllimport) void __stdcall Sleep(unsigned long);
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
#endif
# ifndef UNDER_CE
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
@@ -165,19 +216,26 @@ namespace boost
{
namespace win32
{
typedef unsigned __int64 ticks_type;
namespace detail { typedef int (__stdcall *farproc_t)(); typedef ticks_type (__stdcall *gettickcount64_t)(); }
#if !BOOST_PLAT_WINDOWS_RUNTIME
extern "C"
{
__declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *);
__declspec(dllimport) detail::farproc_t __stdcall GetProcAddress(void *, const char *);
#if !defined(BOOST_NO_ANSI_APIS)
__declspec(dllimport) void * __stdcall GetModuleHandleA(const char *);
__declspec(dllimport) void * __stdcall GetModuleHandleA(const char *);
#else
__declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *);
__declspec(dllimport) void * __stdcall GetModuleHandleW(const wchar_t *);
#endif
int __stdcall GetTickCount();
__declspec(dllimport) unsigned long __stdcall GetTickCount();
#ifdef _MSC_VER
long _InterlockedCompareExchange(long volatile *, long, long);
#pragma intrinsic(_InterlockedCompareExchange)
#elif defined(__MINGW64_VERSION_MAJOR)
long _InterlockedCompareExchange(long volatile *, long, long);
#else
// Mingw doesn't provide intrinsics
#define _InterlockedCompareExchange InterlockedCompareExchange
#endif
}
// Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
inline ticks_type __stdcall GetTickCount64emulation()
@@ -227,11 +285,19 @@ namespace boost
// Oops, we weren't called often enough, we're stuck
return 0xFFFFFFFF;
}
inline detail::gettickcount64_t GetTickCount64()
#else
#endif
inline detail::gettickcount64_t GetTickCount64_()
{
static detail::gettickcount64_t gettickcount64impl;
if(gettickcount64impl)
return gettickcount64impl;
// GetTickCount and GetModuleHandle are not allowed in the Windows Runtime,
// and kernel32 isn't used in Windows Phone.
#if BOOST_PLAT_WINDOWS_RUNTIME
gettickcount64impl = &GetTickCount64;
#else
detail::farproc_t addr=GetProcAddress(
#if !defined(BOOST_NO_ANSI_APIS)
GetModuleHandleA("KERNEL32.DLL"),
@@ -243,10 +309,11 @@ namespace boost
gettickcount64impl=(detail::gettickcount64_t) addr;
else
gettickcount64impl=&GetTickCount64emulation;
#endif
return gettickcount64impl;
}
enum event_type
enum event_type
{
auto_reset_event=false,
manual_reset_event=true
@@ -258,13 +325,32 @@ namespace boost
event_initially_set=true
};
inline handle create_anonymous_event(event_type type,initial_event_state state)
inline handle create_event(
#if !defined(BOOST_NO_ANSI_APIS)
const char *mutex_name,
#else
const wchar_t *mutex_name,
#endif
event_type type,
initial_event_state state)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=win32::CreateEventA(0,type,state,0);
handle const res = win32::CreateEventA(0, type, state, mutex_name);
#elif BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
handle const res = win32::CreateEventW(0, type, state, mutex_name);
#else
handle const res=win32::CreateEventW(0,type,state,0);
handle const res = win32::CreateEventExW(
0,
mutex_name,
type ? create_event_manual_reset : 0 | state ? create_event_initial_set : 0,
event_all_access);
#endif
return res;
}
inline handle create_anonymous_event(event_type type,initial_event_state state)
{
handle const res = create_event(0, type, state);
if(!res)
{
boost::throw_exception(thread_resource_error());
@@ -272,28 +358,29 @@ namespace boost
return res;
}
inline handle create_anonymous_semaphore(long initial_count,long max_count)
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
handle const res=win32::CreateSemaphoreA(0,initial_count,max_count,0);
#else
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
#if BOOST_USE_WINAPI_VERSION < BOOST_WINAPI_VERSION_VISTA
handle const res=win32::CreateSemaphoreEx(0,initial_count,max_count,0,0);
#else
handle const res=win32::CreateSemaphoreExW(0,initial_count,max_count,0,0,semaphore_all_access);
#endif
#endif
return res;
}
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
handle const res=create_anonymous_semaphore_nothrow(initial_count,max_count);
if(!res)
{
boost::throw_exception(thread_resource_error());
}
return res;
}
inline handle create_anonymous_semaphore_nothrow(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
#else
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
#endif
return res;
}
inline handle duplicate_handle(handle source)
{
@@ -312,7 +399,64 @@ namespace boost
{
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
}
inline void get_system_info(system_info *info)
{
#if BOOST_PLAT_WINDOWS_RUNTIME
win32::GetNativeSystemInfo(info);
#else
win32::GetSystemInfo(info);
#endif
}
inline void sleep(unsigned long milliseconds)
{
if(milliseconds == 0)
{
#if BOOST_PLAT_WINDOWS_RUNTIME
std::this_thread::yield();
#else
::boost::detail::win32::Sleep(0);
#endif
}
else
{
#if BOOST_PLAT_WINDOWS_RUNTIME
::boost::detail::win32::WaitForSingleObjectEx(::boost::detail::win32::GetCurrentThread(), milliseconds, 0);
#else
::boost::detail::win32::Sleep(milliseconds);
#endif
}
}
#if BOOST_PLAT_WINDOWS_RUNTIME
class BOOST_THREAD_DECL scoped_winrt_thread
{
public:
scoped_winrt_thread() : m_completionHandle(invalid_handle_value)
{}
~scoped_winrt_thread()
{
if (m_completionHandle != ::boost::detail::win32::invalid_handle_value)
{
CloseHandle(m_completionHandle);
}
}
typedef unsigned(__stdcall * thread_func)(void *);
bool start(thread_func address, void *parameter, unsigned int *thrdId);
handle waitable_handle() const
{
BOOST_ASSERT(m_completionHandle != ::boost::detail::win32::invalid_handle_value);
return m_completionHandle;
}
private:
handle m_completionHandle;
};
#endif
class BOOST_THREAD_DECL handle_manager
{
private:
@@ -375,7 +519,6 @@ namespace boost
cleanup();
}
};
}
}
}

View File

@@ -46,11 +46,12 @@ namespace boost {
* );
*/
template <class Lockable, class Function, class... Args>
auto with_lock_guard(
typename boost::result_of<Function(Args...)>::type with_lock_guard(
Lockable& m,
BOOST_FWD_REF(Function) func,
BOOST_FWD_REF(Args)... args
) -> decltype(func(boost::forward<Args>(args)...)) {
) //-> decltype(func(boost::forward<Args>(args)...))
{
boost::lock_guard<Lockable> lock(m);
return func(boost::forward<Args>(args)...);
}

View File

@@ -20,7 +20,6 @@
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <boost/cstdint.hpp>
#if defined BOOST_THREAD_USES_DATETIME
@@ -33,6 +32,19 @@
#endif
#include <stdio.h>
#include <windows.h>
#include <boost/predef/platform.h>
#if BOOST_PLAT_WINDOWS_RUNTIME
#include <mutex>
#include <atomic>
#include <Activation.h>
#include <wrl\client.h>
#include <wrl\event.h>
#include <wrl\wrappers\corewrappers.h>
#include <wrl\ftm.h>
#include <windows.system.threading.h>
#pragma comment(lib, "runtimeobject.lib")
#endif
namespace boost
{
@@ -65,50 +77,67 @@ namespace boost
// Windows CE does not define the TLS_OUT_OF_INDEXES constant.
#define TLS_OUT_OF_INDEXES 0xFFFFFFFF
#endif
#if !BOOST_PLAT_WINDOWS_RUNTIME
DWORD current_thread_tls_key=TLS_OUT_OF_INDEXES;
#else
__declspec(thread) boost::detail::thread_data_base* current_thread_data_base;
#endif
void create_current_thread_tls_key()
{
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
#if !BOOST_PLAT_WINDOWS_RUNTIME
current_thread_tls_key=TlsAlloc();
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
#endif
}
void cleanup_tls_key()
{
#if !BOOST_PLAT_WINDOWS_RUNTIME
if(current_thread_tls_key!=TLS_OUT_OF_INDEXES)
{
TlsFree(current_thread_tls_key);
current_thread_tls_key=TLS_OUT_OF_INDEXES;
}
#endif
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
if (current_thread_tls_key!=TLS_OUT_OF_INDEXES)
#if BOOST_PLAT_WINDOWS_RUNTIME
current_thread_data_base = new_data;
#else
if (current_thread_tls_key != TLS_OUT_OF_INDEXES)
{
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
BOOST_VERIFY(TlsSetValue(current_thread_tls_key, new_data));
}
else
{
BOOST_VERIFY(false);
//boost::throw_exception(thread_resource_error());
}
#endif
}
}
namespace detail
{
thread_data_base* get_current_thread_data()
{
if(current_thread_tls_key==TLS_OUT_OF_INDEXES)
#if BOOST_PLAT_WINDOWS_RUNTIME
return current_thread_data_base;
#else
if (current_thread_tls_key == TLS_OUT_OF_INDEXES)
{
return 0;
}
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
#endif
}
}
namespace
{
#ifndef BOOST_HAS_THREADEX
@@ -165,6 +194,66 @@ namespace boost
}
#if BOOST_PLAT_WINDOWS_RUNTIME
namespace detail
{
std::atomic_uint threadCount;
bool win32::scoped_winrt_thread::start(thread_func address, void *parameter, unsigned int *thrdId)
{
Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IThreadPoolStatics> threadPoolFactory;
HRESULT hr = ::Windows::Foundation::GetActivationFactory(
Microsoft::WRL::Wrappers::HStringReference(RuntimeClass_Windows_System_Threading_ThreadPool).Get(),
&threadPoolFactory);
if (hr != S_OK)
{
return false;
}
// Create event for tracking work item completion.
*thrdId = ++threadCount;
handle completionHandle = CreateEventExW(NULL, NULL, 0, EVENT_ALL_ACCESS);
if (!completionHandle)
{
return false;
}
m_completionHandle = completionHandle;
// Create new work item.
Microsoft::WRL::ComPtr<ABI::Windows::System::Threading::IWorkItemHandler> workItem =
Microsoft::WRL::Callback<Microsoft::WRL::Implements<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::ClassicCom>, ABI::Windows::System::Threading::IWorkItemHandler, Microsoft::WRL::FtmBase>>
([address, parameter, completionHandle](ABI::Windows::Foundation::IAsyncAction *)
{
// Add a reference since we need to access the completionHandle after the thread_start_function.
// This is to handle cases where detach() was called and run_thread_exit_callbacks() would end
// up closing the handle.
::boost::detail::thread_data_base* const thread_info(reinterpret_cast<::boost::detail::thread_data_base*>(parameter));
intrusive_ptr_add_ref(thread_info);
__try
{
address(parameter);
}
__finally
{
SetEvent(completionHandle);
intrusive_ptr_release(thread_info);
}
return S_OK;
});
// Schedule work item on the threadpool.
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> asyncAction;
hr = threadPoolFactory->RunWithPriorityAndOptionsAsync(
workItem.Get(),
ABI::Windows::System::Threading::WorkItemPriority_Normal,
ABI::Windows::System::Threading::WorkItemOptions_TimeSliced,
&asyncAction);
return hr == S_OK;
}
}
#endif
namespace
{
void run_thread_exit_callbacks()
@@ -199,7 +288,6 @@ namespace boost
current_thread_data->tss_data.erase(current);
}
}
set_current_thread_data(0);
}
}
@@ -236,6 +324,16 @@ namespace boost
bool thread::start_thread_noexcept()
{
#if BOOST_PLAT_WINDOWS_RUNTIME
intrusive_ptr_add_ref(thread_info.get());
if (!thread_info->thread_handle.start(&thread_start_function, thread_info.get(), &thread_info->id))
{
intrusive_ptr_release(thread_info.get());
// boost::throw_exception(thread_resource_error());
return false;
}
return true;
#else
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
if(!new_thread)
{
@@ -246,10 +344,16 @@ namespace boost
thread_info->thread_handle=(detail::win32::handle)(new_thread);
ResumeThread(thread_info->thread_handle);
return true;
#endif
}
bool thread::start_thread_noexcept(const attributes& attr)
{
#if BOOST_PLAT_WINDOWS_RUNTIME
// Stack size isn't supported with Windows Runtime.
attr;
return start_thread_noexcept();
#else
//uintptr_t const new_thread=_beginthreadex(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
uintptr_t const new_thread=_beginthreadex(0,static_cast<unsigned int>(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
if(!new_thread)
@@ -261,8 +365,9 @@ namespace boost
thread_info->thread_handle=(detail::win32::handle)(new_thread);
ResumeThread(thread_info->thread_handle);
return true;
#endif
}
thread::thread(detail::thread_data_ptr data):
thread_info(data)
{}
@@ -321,31 +426,37 @@ namespace boost
}
return current_thread_data;
}
}
thread::id thread::get_id() const BOOST_NOEXCEPT
{
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
detail::thread_data_ptr local_thread_info=(get_thread_info)();
return local_thread_info?local_thread_info->id:0;
//return const_cast<thread*>(this)->native_handle();
#else
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(!local_thread_info)
{
return 0;
}
return local_thread_info->id;
#else
return thread::id((get_thread_info)());
#endif
#endif
}
bool thread::joinable() const BOOST_NOEXCEPT
{
return (get_thread_info)() ? true : false;
detail::thread_data_ptr local_thread_info = (get_thread_info)();
if(!local_thread_info)
{
return false;
}
return true;
}
bool thread::join_noexcept()
{
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
this_thread::interruptible_wait(this->native_handle(),detail::timeout::sentinel());
release_handle();
return true;
}
@@ -366,7 +477,7 @@ namespace boost
detail::thread_data_ptr local_thread_info=(get_thread_info)();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,milli))
if(!this_thread::interruptible_wait(this->native_handle(),milli))
{
res=false;
return true;
@@ -404,21 +515,23 @@ namespace boost
bool thread::interruption_requested() const BOOST_NOEXCEPT
{
detail::thread_data_ptr local_thread_info=(get_thread_info)();
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
return local_thread_info.get() && (detail::win32::WaitForSingleObjectEx(local_thread_info->interruption_handle,0,0)==0);
}
#endif
unsigned thread::hardware_concurrency() BOOST_NOEXCEPT
{
//SYSTEM_INFO info={{0}};
SYSTEM_INFO info;
GetSystemInfo(&info);
detail::win32::system_info info;
detail::win32::get_system_info(&info);
return info.dwNumberOfProcessors;
}
unsigned thread::physical_concurrency() BOOST_NOEXCEPT
{
#if BOOST_PLAT_WINDOWS_RUNTIME
return hardware_concurrency();
#else
unsigned cores = 0;
#if !(defined(__MINGW32__) || defined (__MINGW64__))
DWORD size = 0;
@@ -439,12 +552,22 @@ namespace boost
}
#endif
return cores;
#endif
}
thread::native_handle_type thread::native_handle()
{
detail::thread_data_ptr local_thread_info=(get_thread_info)();
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
if(!local_thread_info)
{
return detail::win32::invalid_handle_value;
}
#if BOOST_PLAT_WINDOWS_RUNTIME
// There is no 'real' Win32 handle so we return a handle that at least can be waited on.
return local_thread_info->thread_handle.waitable_handle();
#else
return (detail::win32::handle)local_thread_info->thread_handle;
#endif
}
detail::thread_data_ptr thread::get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const
@@ -461,7 +584,7 @@ namespace boost
LARGE_INTEGER due_time={{0,0}};
if(target_time.relative)
{
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64()()-target_time.start;
detail::win32::ticks_type const elapsed_milliseconds=detail::win32::GetTickCount64_()()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
@@ -535,6 +658,7 @@ namespace boost
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
#if !BOOST_PLAT_WINDOWS_RUNTIME
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
@@ -562,6 +686,7 @@ namespace boost
target_time=detail::timeout(time_left.milliseconds);
}
}
#endif
#endif
bool const using_timer=timeout_index!=~0u;
@@ -576,7 +701,7 @@ namespace boost
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
@@ -598,7 +723,7 @@ namespace boost
}
else
{
detail::win32::Sleep(time_left.milliseconds);
detail::win32::sleep(time_left.milliseconds);
}
if(target_time.relative)
{
@@ -625,6 +750,7 @@ namespace boost
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
#if !BOOST_PLAT_WINDOWS_RUNTIME
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
@@ -652,6 +778,7 @@ namespace boost
target_time=detail::timeout(time_left.milliseconds);
}
}
#endif
#endif
bool const using_timer=timeout_index!=~0u;
@@ -666,7 +793,7 @@ namespace boost
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
unsigned long const notified_index=detail::win32::WaitForMultipleObjectsEx(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds, 0);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
@@ -681,7 +808,7 @@ namespace boost
}
else
{
detail::win32::Sleep(time_left.milliseconds);
detail::win32::sleep(time_left.milliseconds);
}
if(target_time.relative)
{
@@ -695,11 +822,18 @@ namespace boost
thread::id get_id() BOOST_NOEXCEPT
{
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
return detail::win32::GetCurrentThreadId();
#else
#if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
#if BOOST_PLAT_WINDOWS_RUNTIME
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
if (current_thread_data)
{
return current_thread_data->id;
}
#endif
return detail::win32::GetCurrentThreadId();
#else
return thread::id(get_or_make_current_thread_data());
#endif
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
@@ -719,13 +853,13 @@ namespace boost
bool interruption_requested() BOOST_NOEXCEPT
{
return detail::get_current_thread_data() && (detail::win32::WaitForSingleObject(detail::get_current_thread_data()->interruption_handle,0)==0);
return detail::get_current_thread_data() && (detail::win32::WaitForSingleObjectEx(detail::get_current_thread_data()->interruption_handle,0,0)==0);
}
#endif
void yield() BOOST_NOEXCEPT
{
detail::win32::Sleep(0);
detail::win32::sleep(0);
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
@@ -839,6 +973,7 @@ namespace boost
}
}
}
BOOST_THREAD_DECL void __cdecl on_process_enter()
{}

View File

@@ -49,7 +49,8 @@ project
<toolset>pathscale:<cxxflags>-pedantic
<toolset>clang:<cxxflags>-Wextra
<toolset>clang:<cxxflags>-pedantic
#<toolset>clang:<cxxflags>-pedantic
<toolset>clang:<warnings>on
<toolset>clang:<cxxflags>-Wno-long-long
#<toolset>clang:<cxxflags>-ansi
#<toolset>clang:<cxxflags>-fpermissive # doesn't work
@@ -95,13 +96,12 @@ project
<toolset>intel:<cxxflags>-wd193,304,383,444
<toolset>intel:<cxxflags>-wd593,981
<toolset>intel:<cxxflags>-wd1418
<toolset>intel:<cxxflags>-wd2415
<toolset>intel:<cxxflags>-wd2415
;
rule thread-run ( sources )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) ../build//boost_thread ]
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
@@ -112,6 +112,7 @@ rule thread-run ( sources )
rule thread-test ( sources )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) ../build//boost_thread : : :
<library>/boost/test//boost_unit_test_framework/<link>static
@@ -126,6 +127,7 @@ rule thread-test ( sources )
rule thread-run2 ( sources : name )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) ../build//boost_thread : : :
: $(name) ]
@@ -137,6 +139,7 @@ rule thread-run2 ( sources : name )
rule thread-run2-noit ( sources : name )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) ../build//boost_thread : : :
: $(name) ]
@@ -151,6 +154,7 @@ rule thread-run2-noit ( sources : name )
rule thread-run2-noit-pthread ( sources : name )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) ../build//boost_thread : : : <threadapi>win32:<build>no
: $(name) ]
@@ -165,6 +169,7 @@ rule thread-run2-noit-pthread ( sources : name )
rule thread-run2-h ( sources : name )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) : : :
<library>/boost/system//boost_system
@@ -177,6 +182,7 @@ rule thread-run2-h ( sources : name )
rule thread-run-lib2 ( sources : name )
{
sources = $(sources) winrt_init.cpp ;
return
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
: : :
@@ -343,6 +349,7 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/futures/promise/set_rvalue_pass.cpp : promise__set_rvalue_p ]
[ thread-run2-noit ./sync/futures/promise/set_value_const_pass.cpp : promise__set_value_const_p ]
[ thread-run2-noit ./sync/futures/promise/set_value_void_pass.cpp : promise__set_value_void_p ]
[ thread-run2-noit ./sync/futures/promise/emplace_pass.cpp : promise__emplace_p ]
[ thread-run2-noit ./sync/futures/promise/use_allocator_pass.cpp : promise__use_allocator_p ]
[ thread-run2-noit ./sync/futures/promise/set_exception_at_thread_exit_pass.cpp : promise__set_exception_at_thread_exit_p ]
[ thread-run2-noit ./sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp : promise__set_lvalue_at_thread_exit_p ]
@@ -351,6 +358,12 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/futures/promise/set_value_at_thread_exit_void_pass.cpp : promise__set_value_at_thread_exit_void_p ]
;
#explicit ts_make_ready_future ;
test-suite ts_make_ready_future
:
[ thread-run2-noit ./sync/futures/make_ready_future_pass.cpp : make_ready_future_p ]
;
#explicit ts_future ;
test-suite ts_future
:
@@ -367,6 +380,9 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/futures/future/wait_for_pass.cpp : future__wait_for_p ]
[ thread-run2-noit ./sync/futures/future/wait_until_pass.cpp : future__wait_until_p ]
[ thread-run2-noit ./sync/futures/future/then_pass.cpp : future__then_p ]
[ thread-run2-noit ./sync/futures/future/then_executor_pass.cpp : future__then_executor_p ]
[ thread-run2-noit ./sync/futures/future/async_deferred_then_pass.cpp : future__async_def_then_p ]
[ thread-run2-noit ./sync/futures/future/then_deferred_pass.cpp : future__then_def_p ]
;
#explicit ts_shared_future ;
@@ -383,6 +399,7 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/futures/shared_future/wait_for_pass.cpp : shared_future__wait_for_p ]
[ thread-run2-noit ./sync/futures/shared_future/wait_until_pass.cpp : shared_future__wait_until_p ]
[ thread-run2-noit ./sync/futures/shared_future/then_pass.cpp : shared_future__then_p ]
[ thread-run2-noit ./sync/futures/shared_future/then_executor_pass.cpp : shared_future__then_executor_p ]
;
#explicit ts_packaged_task ;
@@ -407,6 +424,24 @@ rule thread-compile ( sources : reqs * : name )
;
#explicit ts_when_all ;
test-suite ts_when_all
:
[ thread-run2-noit ./sync/futures/when_all/none_pass.cpp : when_all__none_p ]
[ thread-run2-noit ./sync/futures/when_all/one_pass.cpp : when_all__one_p ]
[ thread-run2-noit ./sync/futures/when_all/iterators_pass.cpp : when_all__iterators_p ]
[ thread-run2-noit ./sync/futures/when_all/variadic_pass.cpp : when_all__variadic_p ]
;
#explicit ts_when_any ;
test-suite ts_when_any
:
[ thread-run2-noit ./sync/futures/when_any/none_pass.cpp : when_any__none_p ]
[ thread-run2-noit ./sync/futures/when_any/one_pass.cpp : when_any__one_p ]
[ thread-run2-noit ./sync/futures/when_any/iterators_pass.cpp : when_any__iterators_p ]
[ thread-run2-noit ./sync/futures/when_any/variadic_pass.cpp : when_any__variadic_p ]
;
#explicit ts_lock_guard ;
test-suite ts_lock_guard
:
@@ -430,10 +465,10 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/duration_pass.cpp : unique_lock__cons__duration_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_assign_pass.cpp : unique_lock__cons__move_assign_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_pass.cpp : unique_lock__cons__move_ctor_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_try_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_for_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp : unique_lock__cons__move_ctor_upgrade_lock_until_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp : uq_lk_cons_mv_c_upg_lk_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp : uq_lk_cons_mv_c_upg_lk_t_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp : uq_lk_cons_mv_c_upg_lk_f_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp : uq_lk_cons_mv_c_upg_lk_u_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/mutex_pass.cpp : unique_lock__cons__mutex_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/time_point_pass.cpp : unique_lock__cons__time_point_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/try_to_lock_pass.cpp : unique_lock__cons__try_to_lock_p ]
@@ -477,8 +512,8 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/duration_pass.cpp : shared_lock__cons__duration_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_assign_pass.cpp : shared_lock__cons__move_assign_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_pass.cpp : shared_lock__cons__move_ctor_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp : shared_lock__cons__move_ctor_unique_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp : shared_lock__cons__move_ctor_upgrade_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp : sh_lock_cons_move_ctor_unq_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp : sh_lock_cons_move_ctor_upg_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/mutex_pass.cpp : shared_lock__cons__mutex_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/time_point_pass.cpp : shared_lock__cons__time_point_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/shared_lock/cons/try_to_lock_pass.cpp : shared_lock__cons__try_to_lock_p ]
@@ -511,7 +546,7 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/duration_pass.cpp : upgrade_lock__cons__duration_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_assign_pass.cpp : upgrade_lock__cons__move_assign_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_pass.cpp : upgrade_lock__cons__move_ctor_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp : upgrade_lock__cons__move_ctor_unique_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp : upg_lock_cons_mv_ctor_uq_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/mutex_pass.cpp : upgrade_lock__cons__mutex_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/time_point_pass.cpp : upgrade_lock__cons__time_point_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/try_to_lock_pass.cpp : upgrade_lock__cons__try_to_lock_p ]
@@ -543,8 +578,8 @@ rule thread-compile ( sources : reqs * : name )
#explicit ts_nested_strict_lock ;
test-suite ts_nested_strict_lock
:
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_assign_fail.cpp : : nested_strict_lock__cons__copy_assign_f ]
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_ctor_fail.cpp : : nested_strict_lock__cons__copy_ctor_f ]
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_assign_fail.cpp : : nested_strict_lock_cons_copy_assign_f ]
[ thread-compile-fail ./sync/mutual_exclusion/locks/nested_strict_lock/copy_ctor_fail.cpp : : nested_strict_lock_cons_copy_ctor_f ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/nested_strict_lock/default_pass.cpp : nested_strict_lock__cons__default_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/nested_strict_lock/owns_lock_pass.cpp : nested_strict_lock__owns_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/nested_strict_lock/types_pass.cpp : nested_strict_lock__types_p ]
@@ -590,10 +625,10 @@ rule thread-compile ( sources : reqs * : name )
[ thread-compile-fail ./sync/mutual_exclusion/recursive_timed_mutex/copy_fail.cpp : : recursive_timed_mutex__copy_f ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/default_pass.cpp : recursive_timed_mutex__default_p ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/lock_pass.cpp : recursive_timed_mutex__lock_p ]
[ thread-run2-noit-pthread ./sync/mutual_exclusion/recursive_timed_mutex/native_handle_pass.cpp : recursive_timed_mutex__native_handle_p ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_for_pass.cpp : recursive_timed_mutex__try_lock_for_p ]
[ thread-run2-noit-pthread ./sync/mutual_exclusion/recursive_timed_mutex/native_handle_pass.cpp : rec_timed_mutex_native_handle_p ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_for_pass.cpp : rec_timed_mutex_try_lock_for_p ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_pass.cpp : recursive_timed_mutex__try_lock_p ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_until_pass.cpp : recursive_timed_mutex__try_lock_until_p ]
[ thread-run2-noit ./sync/mutual_exclusion/recursive_timed_mutex/try_lock_until_pass.cpp : rec_timed_mutex_try_lock_until_p ]
;
#explicit ts_timed_mutex ;
@@ -643,8 +678,33 @@ rule thread-compile ( sources : reqs * : name )
test-suite ts_sync_bounded_queue
:
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/single_thread_pass.cpp : sync_bounded_queue__single_thread_p ]
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_queue__multi_thread_p ]
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/single_thread_pass.cpp : sync_bounded_q_single_thread_p ]
[ thread-run2-noit ./sync/mutual_exclusion/sync_bounded_queue/multi_thread_pass.cpp : sync_bounded_q_multi_thread_p ]
;
test-suite ts_sync_pq
:
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/pq_single_thread_pass.cpp : sync_pq_single_thread_p ]
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/pq_multi_thread_pass.cpp : sync_pq_multi_thread_p ]
;
test-suite ts_sync_tq
:
[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_single_thread_pass.cpp : sync_tq_single_thread_p ]
#[ thread-run2-noit ./sync/mutual_exclusion/sync_pq/tq_multi_thread_pass.cpp : sync_tq_multi_thread_p ]
;
test-suite ts_scheduler
:
[ thread-run2-noit ./test_scheduled_tp.cpp : test_scheduled_tp_p ]
[ thread-run2-noit ./test_scheduling_adaptor.cpp : test_scheduling_adaptor_p ]
[ thread-run2-noit ./test_scheduler.cpp : test_scheduler_p ]
;
test-suite ts_queue_views
:
[ thread-run2-noit ./sync/mutual_exclusion/queue_views/single_thread_pass.cpp : queue_views__single_thread_p ]
#[ thread-run2-noit ./sync/mutual_exclusion/queue_views/multi_thread_pass.cpp : queue_views__multi_thread_p ]
;
#explicit ts_this_thread ;
@@ -719,29 +779,31 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ../example/ba_externallly_locked.cpp : ex_ba_externallly_locked ]
[ thread-run2 ../example/producer_consumer_bounded.cpp : ex_producer_consumer_bounded ]
[ thread-run2 ../example/producer_consumer.cpp : ex_producer_consumer ]
[ thread-run2 ../example/producer_consumer2.cpp : ex_producer_consumer2 ]
[ thread-run2 ../example/not_interleaved.cpp : ex_not_interleaved ]
[ thread-run2 ../example/lambda_future.cpp : ex_lambda_future ]
[ thread-run2 ../example/not_interleaved2.cpp : ex_not_interleaved2 ]
[ thread-run2 ../example/thread_pool.cpp : ex_thread_pool ]
[ thread-run2 ../example/user_scheduler.cpp : ex_user_scheduler ]
[ thread-run2 ../example/executor.cpp : ex_executor ]
[ thread-run2 ../example/future_when_all.cpp : future_when_all ]
[ thread-run2 ../example/generic_executor_ref.cpp : ex_generic_executor_ref ]
[ thread-run2 ../example/future_when_all.cpp : ex_future_when_all ]
[ thread-run2 ../example/parallel_accumulate.cpp : ex_parallel_accumulate ]
[ thread-run2 ../example/parallel_quick_sort.cpp : ex_parallel_quick_sort ]
[ thread-run2 ../example/with_lock_guard.cpp : ex_with_lock_guard ]
[ thread-run2 ../example/fib_task_region.cpp : ex_fib_task_region ]
;
#explicit ts_shared_upwards ;
test-suite ts_shared_upwards
:
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp : unique_lock__cons__move_ctor_shared_lock_try_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp : unique_lock__cons__move_ctor_shared_lock_for_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp : unique_lock__cons__move_ctor_shared_lock_until_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp : uq_lock_cons_mv_ctor_sh_lock_try_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp : uq_lock_cons_mv_ctor_sh_lock_for_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp : uq_lock_cons_mv_ctor_sh_lock_until_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp : upgrade_lock__cons__move_ctor_shared_lock_try_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp : upgrade_lock__cons__move_ctor_shared_lock_for_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp : upgrade_lock__cons__move_ctor_shared_lock_until_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp : upg_lock_cons_move_ctor_sh_lock_try_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp : upg_lock_cons_move_ctor_sh_lock_for_p ]
[ thread-run2-noit ./sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp : upg_lock_cons_move_ctor_sh_lock_untl_p ]
;
@@ -810,6 +872,8 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ./functional/invoker/invoker_rvalue_pass.cpp : invoker_rvalue_p ]
;
explicit ts_more ;
test-suite ts_more
:
@@ -825,6 +889,11 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run test_9079_a.cpp ]
[ thread-run test_9079_b.cpp ]
[ thread-run test_9192.cpp ]
#[ thread-run test_9303.cpp ]
#[ thread-run test_9720.cpp ]
#[ thread-run test_10125.cpp ]
#[ thread-run test_10128.cpp ]
#[ thread-run test_10340.cpp ]
;
explicit ts_more_cpp11 ;
@@ -833,21 +902,30 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run test_8596.cpp ]
[ thread-run test_8600.cpp ]
;
explicit perf ;
test-suite perf
:
#[ thread-run ../example/perf_condition_variable.cpp ]
#[ thread-run ../example/perf_shared_mutex.cpp ]
;
#explicit ts_exception_list ;
test-suite ts_exception_list
:
[ thread-run2-noit ./experimental/parallel/v1/exception_list_pass.cpp : exception_list_p ]
;
#explicit ts_task_region ;
test-suite ts_task_region
:
[ thread-run2-noit ./experimental/parallel/v2/task_region_pass.cpp : task_region_p ]
;
explicit ts_ ;
test-suite ts_
:
#[ thread-run ../example/test_so.cpp ]
#[ thread-run ../example/test_so2.cpp ]
#[ thread-run ../example/perf_condition_variable.cpp ]
#[ thread-run ../example/perf_shared_mutex.cpp ]
#[ thread-run ../example/std_async_test.cpp ]
#[ compile virtual_noexcept.cpp ]
#[ thread-run clang_main.cpp ]
#[ thread-run test_9303.cpp ]
#[ thread-run test_9720.cpp ]
#[ thread-run test_10125.cpp ]
#[ thread-run test_10128.cpp ]
;
}

View File

@@ -0,0 +1,23 @@
// 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)
// <boost/thread/experimental/parallel/v1/exception_list.hpp>
#define BOOST_THREAD_VERSION 4
#include <boost/config.hpp>
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#include <boost/thread/experimental/parallel/v1/exception_list.hpp>
#include <boost/detail/lightweight_test.hpp>
int main()
{
return boost::report_errors();
}

View File

@@ -0,0 +1,293 @@
// 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)
// <boost/thread/experimental/parallel/v1/exception_list.hpp>
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_EXECUTORS
#include <boost/config.hpp>
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#include <boost/thread/experimental/parallel/v2/task_region.hpp>
#include <string>
#include <boost/detail/lightweight_test.hpp>
#if ! defined BOOST_NO_CXX11_RANGE_BASED_FOR
using boost::experimental::parallel::v2::task_region;
using boost::experimental::parallel::v2::task_region_handle;
using boost::experimental::parallel::v1::exception_list;
#endif
#if ! defined BOOST_NO_CXX11_LAMBDAS
void run_no_exception()
{
std::string s("test");
bool parent_flag = false;
bool task1_flag = false;
bool task2_flag = false;
bool task21_flag = false;
bool task3_flag = false;
task_region([&](task_region_handle& trh)
{
parent_flag = true;
trh.run([&]()
{
task1_flag = true;
std::cout << "task1: " << s << std::endl;
});
trh.run([&]()
{
task2_flag = true;
std::cout << "task2" << std::endl;
task_region([&](task_region_handle& trh)
{
trh.run([&]()
{
task21_flag = true;
std::cout << "task2.1" << std::endl;
});
});
});
int i = 0, j = 10, k = 20;
trh.run([=, &task3_flag]()
{
task3_flag = true;
std::cout << "task3: " << i << " " << j << " " << k << std::endl;
});
std::cout << "parent" << std::endl;
});
BOOST_TEST(parent_flag);
BOOST_TEST(task1_flag);
BOOST_TEST(task2_flag);
BOOST_TEST(task21_flag);
BOOST_TEST(task3_flag);
}
void run_no_exception_wait()
{
std::string s("test");
bool parent_flag = false;
bool wait_flag = false;
bool task1_flag = false;
bool task2_flag = false;
bool task21_flag = false;
bool task3_flag = false;
task_region([&](task_region_handle& trh)
{
parent_flag = true;
trh.run([&]()
{
task1_flag = true;
std::cout << "task1: " << s << std::endl;
});
trh.run([&]()
{
task2_flag = true;
std::cout << "task2" << std::endl;
task_region([&](task_region_handle& trh)
{
trh.run([&]()
{
task21_flag = true;
std::cout << "task2.1" << std::endl;
});
});
});
int i = 0, j = 10, k = 20;
trh.run([=, &task3_flag]()
{
task3_flag = true;
std::cout << "task3: " << i << " " << j << " " << k << std::endl;
});
std::cout << "before" << std::endl;
trh.wait();
wait_flag = true;
std::cout << "parent" << std::endl;
});
BOOST_TEST(parent_flag);
BOOST_TEST(wait_flag);
BOOST_TEST(task1_flag);
BOOST_TEST(task2_flag);
BOOST_TEST(task21_flag);
BOOST_TEST(task3_flag);
}
void run_exception_1()
{
try
{
task_region([](task_region_handle& trh)
{
trh.run([]()
{
std::cout << "task1" << std::endl;
throw 1;
});
boost::this_thread::sleep_for(boost::chrono::seconds(1));
trh.run([]()
{
std::cout << "task3" << std::endl;
});
BOOST_TEST(false);
});
BOOST_TEST(false);
}
catch (exception_list const& e)
{
BOOST_TEST_EQ(e.size(), 1u);
}
catch (...)
{
BOOST_TEST(false);
}
}
void run_exception()
{
try
{
task_region([](task_region_handle& trh)
{
trh.run([]()
{
std::cout << "task1" << std::endl;
throw 1;
});
trh.run([]()
{
std::cout << "task2" << std::endl;
throw 2;
});
boost::this_thread::sleep_for(boost::chrono::seconds(1));
trh.run([]()
{
std::cout << "task3" << std::endl;
throw 3;
});
std::cout << "parent" << std::endl;
throw 100;
});
BOOST_TEST(false);
}
catch (exception_list const& el)
{
BOOST_TEST(el.size() >= 1u);
for (boost::exception_ptr const& e: el)
{
try {
boost::rethrow_exception(e);
}
catch (boost::exception&)
{
BOOST_TEST(true);
}
catch (int i) // this doesn't works yet
{
BOOST_TEST((i == 1) || (i == 2) || (i == 3));
}
catch (...)
{
BOOST_TEST(false);
}
}
}
catch (...)
{
BOOST_TEST(false);
}
}
void run_nested_exception()
{
std::string s("test");
bool parent_flag = false;
bool task1_flag = false;
bool task2_flag = false;
bool task21_flag = false;
bool task3_flag = false;
try
{
task_region([&](task_region_handle& trh)
{
parent_flag = true;
trh.run([&]()
{
task1_flag = true;
std::cout << "task1: " << s << std::endl;
});
trh.run([&]()
{
task2_flag = true;
std::cout << "task2" << std::endl;
task_region([&](task_region_handle& trh)
{
trh.run([&]()
{
task21_flag = true;
std::cout << "task2.1" << std::endl;
throw 21;
});
});
});
int i = 0, j = 10, k = 20;
trh.run([=, &task3_flag]()
{
task3_flag = true;
std::cout << "task3: " << i << " " << j << " " << k << std::endl;
});
std::cout << "parent" << std::endl;
});
}
catch (exception_list const& el)
{
BOOST_TEST(el.size() == 1u);
for (boost::exception_ptr const& e: el)
{
try {
boost::rethrow_exception(e);
}
catch (int i) // this doesn't works yet
{
BOOST_TEST_EQ(i, 21);
}
catch (boost::exception&)
{
BOOST_TEST(true);
}
catch (...)
{
BOOST_TEST(false);
}
}
}
catch (...)
{
BOOST_TEST(false);
}
BOOST_TEST(parent_flag);
BOOST_TEST(task1_flag);
BOOST_TEST(task2_flag);
BOOST_TEST(task21_flag);
}
#endif
int main()
{
#if ! defined BOOST_NO_CXX11_LAMBDAS
run_no_exception();
run_no_exception_wait();
run_exception();
run_exception_1();
run_nested_exception();
#endif
return boost::report_errors();
}

View File

@@ -70,38 +70,38 @@ public:
int value;
BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
BOOST_THREAD_MOVABLE_ONLY(MoveOnly)
MoveOnly()
{
value = 0;
}
MoveOnly( BOOST_THREAD_RV_REF(MoveOnly))
{
value = 1;
}
MoveOnly& operator=(BOOST_THREAD_RV_REF(MoveOnly))
{
value = 2;
return *this;
}
int operator()()
{
boost::this_thread::sleep_for(ms(200));
return 3;
}
template <typename OS>
friend OS& operator<<(OS& os, MoveOnly const& v)
{
os << v.value;
return os;
}
};
namespace boost
{
BOOST_THREAD_DCL_MOVABLE (MoveOnly)
{
value = 1;
}
MoveOnly& operator=(BOOST_THREAD_RV_REF(MoveOnly))
{
value = 2;
return *this;
}
int operator()()
{
boost::this_thread::sleep_for(ms(200));
return 3;
}
template <typename OS>
friend OS& operator<<(OS& os, MoveOnly const& v)
{
os << v.value;
return os;
}
};
namespace boost
{
BOOST_THREAD_DCL_MOVABLE (MoveOnly)
}
int f0()
{
@@ -263,6 +263,32 @@ int main()
}
}
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
try
{
boost::future<long> f = boost::async(boost::launch::deferred, A(3));
//boost::this_thread::sleep_for(ms(300));
int res;
{
check_timer timer(ms(500));
res = f.get();
}
BOOST_TEST(res == 3);
}
catch (std::exception& ex)
{
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
BOOST_TEST(false && "exception thrown");
}
catch (...)
{
BOOST_TEST(false && "exception thrown");
}
}
#endif
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
@@ -289,6 +315,31 @@ int main()
}
}
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
try
{
A a(3);
boost::future<long> f = boost::async(boost::launch::deferred, &A::doit, &a);
boost::this_thread::sleep_for(ms(300));
int res;
{
check_timer timer(ms(500));
res = f.get();
}
BOOST_TEST(res == 3);
}
catch (std::exception& ex)
{
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
BOOST_TEST(false && "exception thrown");
}
catch (...)
{
BOOST_TEST(false && "exception thrown");
}
}
#endif
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
@@ -313,6 +364,31 @@ int main()
BOOST_TEST(false && "exception thrown");
}
}
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
try
{
boost::future<int> f = boost::async(boost::launch::deferred, BOOST_THREAD_MAKE_RV_REF(MoveOnly()));
boost::this_thread::sleep_for(ms(300));
int res;
{
check_timer timer(ms(500));
res = f.get();
}
BOOST_TEST(res == 3);
}
catch (std::exception& ex)
{
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
BOOST_TEST(false && "exception thrown");
}
catch (...)
{
BOOST_TEST(false && "exception thrown");
}
}
#endif
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
try
@@ -342,7 +418,7 @@ int main()
try
{
boost::future<int> f = boost::async(boost::launch::deferred, f0);
boost::this_thread::sleep_for(ms(300));
//boost::this_thread::sleep_for(ms(300));
int res;
{
check_timer timer(ms(500));
@@ -436,7 +512,7 @@ int main()
try
{
boost::future<int&> f = boost::async(boost::launch::deferred, f1);
boost::this_thread::sleep_for(ms(300));
//boost::this_thread::sleep_for(ms(300));
int* res;
{
check_timer timer(ms(500));
@@ -524,7 +600,7 @@ int main()
try
{
boost::future<void> f = boost::async(boost::launch::deferred, f2);
boost::this_thread::sleep_for(ms(300));
//boost::this_thread::sleep_for(ms(300));
{
check_timer timer(ms(500));
f.get();
@@ -565,6 +641,31 @@ int main()
BOOST_TEST(false && "exception thrown");
}
}
#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
try
{
boost::future<MoveOnly> f = boost::async(boost::launch::deferred, &f3_1);
//boost::this_thread::sleep_for(ms(300));
MoveOnly res;
{
check_timer timer(ms(500));
res = f.get();
}
BOOST_TEST_EQ(res.value, 2);
}
catch (std::exception& ex)
{
std::cout << __FILE__ << "[" << __LINE__ << "]" << ex.what() << std::endl;
BOOST_TEST(false && "exception thrown");
}
catch (...)
{
BOOST_TEST(false && "exception thrown");
}
}
#endif
std::cout << __FILE__ << "[" << __LINE__ << "]" << std::endl;
{
try
@@ -638,6 +739,29 @@ int main()
}
}
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
{
try
{
boost::future<boost::csbl::unique_ptr<int> > f = boost::async(boost::launch::deferred, &f3, 3);
//boost::this_thread::sleep_for(ms(300));
boost::csbl::unique_ptr<int> res;
{
check_timer timer(ms(500));
res = f.get();
}
BOOST_TEST(*res == 3);
}
catch (std::exception& ex)
{
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
BOOST_TEST(false && "exception thrown");
}
catch (...)
{
BOOST_TEST(false && "exception thrown");
}
}
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
{
try
{
@@ -687,6 +811,29 @@ int main()
}
}
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
{
try
{
boost::future<boost::csbl::unique_ptr<int> > f = boost::async(boost::launch::deferred, &f4, boost::csbl::unique_ptr<int>(new int(3)));
//boost::this_thread::sleep_for(ms(300));
boost::csbl::unique_ptr<int> res;
{
check_timer timer(ms(500));
res = f.get();
}
BOOST_TEST(*res == 3);
}
catch (std::exception& ex)
{
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<ex.what() << std::endl;
BOOST_TEST(false && "exception thrown");
}
catch (...)
{
BOOST_TEST(false && "exception thrown");
}
}
std::cout << __FILE__ <<"["<<__LINE__<<"]"<<std::endl;
{
try
{

View File

@@ -0,0 +1,130 @@
// 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)
// <boost/thread/future.hpp>
// class future<R>
// template<typename F>
// auto then(F&& func) -> future<decltype(func(*this))>;
#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/detail/lightweight_test.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
int p1()
{
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
return 1;
}
int p2(boost::future<int> f)
{
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
BOOST_TEST(f.valid());
int i = f.get();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
return 2 * i;
}
void p3(boost::future<int> f)
{
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
BOOST_TEST(f.valid());
int i = f.get();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p3 <" << &f << " " <<i << BOOST_THREAD_END_LOG;
return;
}
int main()
{
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
BOOST_TEST(f1.valid());
boost::future<int> f2 = f1.then(&p2);
BOOST_TEST(f2.valid());
BOOST_TEST(! f1.valid());
try
{
BOOST_TEST(f2.get()==2);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(boost::launch::deferred, &p1);
BOOST_TEST(f1.valid());
boost::future<void> f2 = f1.then(&p3);
BOOST_TEST(f2.valid());
try
{
f2.wait();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f2 = boost::async(boost::launch::deferred, p1).then(&p2);
BOOST_TEST(f2.get()==2);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(boost::launch::deferred, p1);
boost::future<int> f21 = f1.then(&p2);
boost::future<int> f2= f21.then(&p2);
BOOST_TEST(f2.get()==4);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(boost::launch::deferred, p1);
boost::future<int> f2= f1.then(&p2).then(&p2);
BOOST_TEST(f2.get()==4);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f2 = boost::async(boost::launch::deferred, p1).then(&p2).then(&p2);
BOOST_TEST(f2.get()==4);
}
return boost::report_errors();
}
#else
int main()
{
return 0;
}
#endif

View File

@@ -11,7 +11,7 @@
// R& future<R&>::get_or(R&);
#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>

View File

@@ -22,7 +22,7 @@
//#define BOOST_THREAD_VERSION 3
#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>

View File

@@ -0,0 +1,130 @@
// 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)
// <boost/thread/future.hpp>
// class future<R>
// template<typename F>
// auto then(F&& func) -> future<decltype(func(*this))>;
#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/detail/lightweight_test.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
int p1()
{
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
return 1;
}
int p2(boost::future<int> f)
{
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
BOOST_TEST(f.valid());
int i = f.get();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
return 2 * i;
}
void p3(boost::future<int> f)
{
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
BOOST_TEST(f.valid());
int i = f.get();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p3 <" << &f << " " <<i << BOOST_THREAD_END_LOG;
return;
}
int main()
{
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
BOOST_TEST(f1.valid());
boost::future<int> f2 = f1.then(boost::launch::deferred, &p2);
BOOST_TEST(f2.valid());
BOOST_TEST(! f1.valid());
try
{
BOOST_TEST(f2.get()==2);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
BOOST_TEST(f1.valid());
boost::future<void> f2 = f1.then(boost::launch::deferred, &p3);
BOOST_TEST(f2.valid());
try
{
f2.wait();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f2 = boost::async(p1).then(boost::launch::deferred, &p2);
BOOST_TEST(f2.get()==2);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(p1);
boost::future<int> f21 = f1.then(boost::launch::deferred, &p2);
boost::future<int> f2= f21.then(boost::launch::deferred, &p2);
BOOST_TEST(f2.get()==4);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f1 = boost::async(p1);
boost::future<int> f2= f1.then(boost::launch::deferred, &p2).then(boost::launch::deferred, &p2);
BOOST_TEST(f2.get()==4);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::future<int> f2 = boost::async(p1).then(boost::launch::deferred, &p2).then(boost::launch::deferred, &p2);
BOOST_TEST(f2.get()==4);
}
return boost::report_errors();
}
#else
int main()
{
return 0;
}
#endif

View File

@@ -0,0 +1,139 @@
// 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)
// <boost/thread/future.hpp>
// class future<R>
// template<typename F>
// auto then(F&& func) -> future<decltype(func(*this))>;
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_PROVIDES_EXECUTORS
//#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/thread/executors/basic_thread_pool.hpp>
#include <boost/thread/executor.hpp>
#include <boost/detail/lightweight_test.hpp>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
int p1()
{
BOOST_THREAD_LOG << "p1 < " << BOOST_THREAD_END_LOG;
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p1 >" << BOOST_THREAD_END_LOG;
return 1;
}
int p2(boost::future<int> f)
{
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
BOOST_TEST(f.valid());
int i = f.get();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p2 <" << &f << BOOST_THREAD_END_LOG;
return 2 * i;
}
void p3(boost::future<int> f)
{
BOOST_THREAD_LOG << "p3 <" << &f << BOOST_THREAD_END_LOG;
BOOST_TEST(f.valid());
int i = f.get();
boost::this_thread::sleep_for(boost::chrono::milliseconds(500));
BOOST_THREAD_LOG << "p3 <" << &f << " " <<i << BOOST_THREAD_END_LOG;
return;
}
int main()
{
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::basic_thread_pool ex(1);
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
BOOST_TEST(f1.valid());
boost::future<int> f2 = f1.then(ex, &p2);
BOOST_TEST(f2.valid());
BOOST_TEST(! f1.valid());
try
{
BOOST_TEST(f2.get()==2);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::basic_thread_pool ex(1);
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
BOOST_TEST(f1.valid());
boost::future<void> f2 = f1.then(ex, &p3);
BOOST_TEST(f2.valid());
try
{
f2.wait();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_TEST(false);
}
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::basic_thread_pool ex(1);
boost::future<int> f2 = boost::async(p1).then(ex, &p2);
BOOST_TEST(f2.get()==2);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::basic_thread_pool ex(1);
boost::future<int> f1 = boost::async(p1);
boost::future<int> f21 = f1.then(ex, &p2);
boost::future<int> f2= f21.then(ex, &p2);
BOOST_TEST(f2.get()==4);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::basic_thread_pool ex(1);
boost::future<int> f1 = boost::async(p1);
boost::future<int> f2= f1.then(&p2).then(ex, &p2);
BOOST_TEST(f2.get()==4);
}
BOOST_THREAD_LOG << BOOST_THREAD_END_LOG;
{
boost::basic_thread_pool ex(1);
boost::future<int> f2 = boost::async(p1).then(ex, &p2).then(ex, &p2);
BOOST_TEST(f2.get()==4);
}
return boost::report_errors();
}
#else
int main()
{
return 0;
}
#endif

View File

@@ -11,7 +11,7 @@
// auto then(F&& func) -> future<decltype(func(*this))>;
#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>

View File

@@ -21,7 +21,7 @@
// wait_for(const chrono::duration<Rep, Period>& rel_time) const;
#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>

View File

@@ -21,7 +21,7 @@
//#define BOOST_THREAD_VERSION 3
#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>

View File

@@ -22,7 +22,7 @@
//#define BOOST_THREAD_VERSION 3
#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>

View File

@@ -0,0 +1,157 @@
//===----------------------------------------------------------------------===//
//
// 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.
//
//===----------------------------------------------------------------------===//
// Copyright (C) 2011,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)
// <boost/thread/future.hpp>
// class promise<R>
// future<void> make_ready_future();
// template <class T>
// future<decay_t<T>> make_ready_future(T&&);
// template <class T>
// future<T> make_ready_future(remove_reference_t<T>&);
// template <class T>
// future<T> make_ready_future(remove_reference_t<T>&&);
// template <class T, class ...Args>
// future<T> make_ready_future(Args&& ... args);
#define BOOST_THREAD_VERSION 3
#include <boost/thread/future.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <boost/static_assert.hpp>
struct A
{
A() :
value(0)
{
}
A(int i) :
value(i)
{
}
A(int i, int j) :
value(i+j)
{
}
int value;
};
A make(int i) {
return A(i);
}
A make(int i, int j) {
return A(i, j);
}
struct movable2
{
int value_;
BOOST_THREAD_MOVABLE_ONLY(movable2)
movable2() : value_(1){}
movable2(int i) : value_(i){}
movable2(int i, int j) : value_(i+j){}
//Move constructor and assignment
movable2(BOOST_RV_REF(movable2) m)
{ value_ = m.value_; m.value_ = 0; }
movable2 & operator=(BOOST_THREAD_RV_REF(movable2) m)
{ value_ = m.value_; m.value_ = 0; return *this; }
bool moved() const //Observer
{ return !value_; }
int value() const //Observer
{ return value_; }
};
movable2 move_return_function2(int i) {
return movable2(i);
}
int main()
{
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
BOOST_STATIC_ASSERT((boost::is_copy_constructible<movable2>::value == false));
BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled<movable2>::value == true));
BOOST_STATIC_ASSERT((boost::is_copy_constructible<A>::value == true));
BOOST_STATIC_ASSERT((boost::has_move_emulation_enabled<A>::value == false));
#endif
{
boost::future<void> f = boost::make_ready_future();
f.wait();
}
{
typedef A T;
T i;
boost::future<T> f = boost::make_ready_future(i);
BOOST_TEST(f.get().value==0);
}
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
{
typedef A T;
boost::future<T> f = boost::make_ready_future<T>();
BOOST_TEST(f.get().value==0);
}
{
typedef A T;
boost::future<T> f = boost::make_ready_future<T>(1);
BOOST_TEST(f.get().value==1);
}
{
typedef A T;
boost::future<T> f = boost::make_ready_future<T>(1,2);
BOOST_TEST(f.get().value==3);
}
{
typedef A T;
T i;
boost::future<T&> f = boost::make_ready_future<T&>(i);
BOOST_TEST(f.get().value==0);
}
#endif
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
// sync/futures/make_ready_future_pass.cpp:125:65: erreur: conversion from Ôboost::future<boost::rv<movable2> >Õ to non-scalar type Ôboost::future<movable2>Õ requested
{
typedef movable2 T;
T i;
boost::future<T> f = boost::make_ready_future(boost::move(i));
BOOST_TEST_EQ(f.get().value(),1);
}
#endif
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
{
typedef movable2 T;
boost::future<T> f = boost::make_ready_future<T>();
BOOST_TEST(f.get().value()==1);
}
{
typedef movable2 T;
boost::future<T> f = boost::make_ready_future<T>(1);
BOOST_TEST(f.get().value()==1);
}
{
typedef movable2 T;
boost::future<T> f = boost::make_ready_future<T>(1,2);
BOOST_TEST(f.get().value()==3);
}
#endif
return boost::report_errors();
}

View File

@@ -64,11 +64,24 @@ public:
++n_instances;
++n_moves; BOOST_THREAD_RV(a).data_ = -1;
}
A& operator=(BOOST_THREAD_RV_REF(A) a)
{
data_ = BOOST_THREAD_RV(a).data_;
BOOST_THREAD_RV(a).data_ = -1;
++n_moves;
return *this;
}
A(const A& a) : data_(a.data_)
{
++n_instances;
++n_copies;
}
A& operator=(BOOST_THREAD_COPY_ASSIGN_REF(A) a)
{
data_ = a.data_;
++n_copies;
return *this;
}
~A()
{
--n_instances;

View File

@@ -94,7 +94,7 @@ public:
{
++n_copies;
}
A& operator=(A const& a)
A& operator=(BOOST_THREAD_COPY_ASSIGN_REF(A) a)
{
data_ = a.data_;
++n_copies;

Some files were not shown because too many files have changed in this diff Show More