From ad3247dd290529706158c4cb67c898cef50f22e1 Mon Sep 17 00:00:00 2001 From: "Vicente J. Botet Escriba" Date: Sun, 2 Dec 2012 09:22:33 +0000 Subject: [PATCH] Thread: merge from trunk 1.53 [SVN r81667] --- build/Jamfile.v2 | 16 +- doc/changes.qbk | 79 +- doc/compliance.qbk | 19 +- doc/configuration.qbk | 230 +- doc/future_ref.qbk | 603 ++++- doc/futures.qbk | 279 ++- doc/mutex_concepts.qbk | 406 +++- doc/mutexes.qbk | 4 +- doc/scoped_thread.qbk | 473 ++++ doc/shared_mutex_ref.qbk | 84 + doc/sync_tutorial.qbk | 27 +- doc/thread.qbk | 17 +- doc/thread_ref.qbk | 292 ++- example/ba_externallly_locked.cpp | 116 + example/condition.cpp | 14 +- example/future_then.cpp | 72 + example/make_future.cpp | 42 + example/monitor.cpp | 10 +- example/mutex.cpp | 6 +- example/not_interleaved.cpp | 42 + example/recursive_mutex.cpp | 6 +- example/scoped_thread.cpp | 69 + example/shared_monitor.cpp | 1 + example/shared_mutex.cpp | 1 + example/starvephil.cpp | 26 +- example/strict_lock.cpp | 40 + example/synchronized_person.cpp | 246 ++ example/synchronized_value.cpp | 95 + example/tennis.cpp | 6 +- example/thread.cpp | 2 + example/thread_group.cpp | 49 +- example/thread_guard.cpp | 57 + example/xtime.cpp | 2 + include/boost/thread/barrier.hpp | 3 +- include/boost/thread/condition.hpp | 7 +- include/boost/thread/detail/async_func.hpp | 101 + include/boost/thread/detail/config.hpp | 210 +- include/boost/thread/detail/invoke.hpp | 88 + .../boost/thread/detail/is_convertible.hpp | 48 + include/boost/thread/detail/log.hpp | 83 + .../thread/detail/make_tuple_indices.hpp | 60 + include/boost/thread/detail/move.hpp | 47 +- include/boost/thread/detail/thread.hpp | 267 +- include/boost/thread/detail/thread_group.hpp | 64 +- .../thread/detail/thread_interruption.hpp | 5 +- include/boost/thread/exceptions.hpp | 2 + include/boost/thread/externally_locked.hpp | 304 +++ .../boost/thread/externally_locked_stream.hpp | 149 ++ include/boost/thread/future.hpp | 2139 ++++++++++++++--- .../boost/thread/is_locked_by_this_thread.hpp | 39 + include/boost/thread/lock_algorithms.hpp | 468 ++++ include/boost/thread/lock_concepts.hpp | 196 ++ include/boost/thread/lock_factories.hpp | 90 + include/boost/thread/lock_guard.hpp | 111 + include/boost/thread/lock_options.hpp | 31 + include/boost/thread/lock_traits.hpp | 42 + include/boost/thread/lock_types.hpp | 1221 ++++++++++ include/boost/thread/lockable_adapter.hpp | 226 ++ include/boost/thread/lockable_concepts.hpp | 157 ++ include/boost/thread/lockable_traits.hpp | 202 ++ include/boost/thread/locks.hpp | 1821 +------------- include/boost/thread/mutex.hpp | 34 +- include/boost/thread/null_mutex.hpp | 240 ++ include/boost/thread/poly_lockable.hpp | 68 + .../boost/thread/poly_lockable_adapter.hpp | 89 + include/boost/thread/poly_shared_lockable.hpp | 135 ++ .../thread/poly_shared_lockable_adapter.hpp | 170 ++ .../thread/pthread/condition_variable.hpp | 47 +- .../thread/pthread/condition_variable_fwd.hpp | 44 +- include/boost/thread/pthread/mutex.hpp | 77 +- .../boost/thread/pthread/recursive_mutex.hpp | 24 +- include/boost/thread/pthread/shared_mutex.hpp | 86 +- include/boost/thread/pthread/thread_data.hpp | 91 +- include/boost/thread/pthread/timespec.hpp | 106 +- include/boost/thread/recursive_mutex.hpp | 45 +- include/boost/thread/reverse_lock.hpp | 5 +- include/boost/thread/scoped_thread.hpp | 227 ++ include/boost/thread/shared_lock_guard.hpp | 3 +- include/boost/thread/shared_mutex.hpp | 22 + include/boost/thread/strict_lock.hpp | 186 ++ include/boost/thread/synchronized_value.hpp | 267 ++ include/boost/thread/testable_mutex.hpp | 142 ++ include/boost/thread/thread.hpp | 2 + include/boost/thread/thread_functors.hpp | 56 + include/boost/thread/thread_guard.hpp | 46 + include/boost/thread/v2/thread.hpp | 50 +- .../thread/win32/basic_recursive_mutex.hpp | 4 + .../boost/thread/win32/basic_timed_mutex.hpp | 6 +- .../boost/thread/win32/condition_variable.hpp | 11 +- include/boost/thread/win32/mutex.hpp | 9 +- include/boost/thread/win32/once.hpp | 12 +- .../boost/thread/win32/recursive_mutex.hpp | 9 +- include/boost/thread/win32/shared_mutex.hpp | 3 +- include/boost/thread/win32/thread_data.hpp | 33 +- .../boost/thread/win32/thread_heap_alloc.hpp | 101 +- .../boost/thread/win32/thread_primitives.hpp | 2 +- include/boost/thread/xtime.hpp | 3 +- src/pthread/thread.cpp | 215 +- src/pthread/timeconv.inl | 21 +- src/win32/thread.cpp | 162 +- test/Jamfile.v2 | 109 +- test/condition_test_common.hpp | 24 +- test/shared_mutex_locking_thread.hpp | 40 +- test/sync/futures/async/async_pass.cpp | 250 +- test/sync/futures/future/dtor_pass.cpp | 4 +- test/sync/futures/future/get_pass.cpp | 174 +- test/sync/futures/future/move_assign_pass.cpp | 4 +- test/sync/futures/future/move_ctor_pass.cpp | 4 +- test/sync/futures/future/then_pass.cpp | 61 + .../futures/packaged_task/alloc_ctor_pass.cpp | 32 +- .../packaged_task/copy_assign_fail.cpp | 12 +- .../futures/packaged_task/copy_ctor_fail.cpp | 12 +- .../packaged_task/default_ctor_pass.cpp | 10 +- test/sync/futures/packaged_task/dtor_pass.cpp | 55 +- .../futures/packaged_task/func_ctor_pass.cpp | 51 +- .../futures/packaged_task/get_future_pass.cpp | 13 +- .../make_ready_at_thread_exit_pass.cpp | 146 ++ .../packaged_task/member_swap_pass.cpp | 15 +- .../packaged_task/move_assign_pass.cpp | 15 +- .../futures/packaged_task/move_ctor_pass.cpp | 15 +- .../packaged_task/non_member_swap_pass.cpp | 15 +- .../futures/packaged_task/operator_pass.cpp | 140 +- .../sync/futures/packaged_task/reset_pass.cpp | 12 +- .../sync/futures/packaged_task/types_pass.cpp | 2 +- .../packaged_task/use_allocator_pass.cpp | 9 +- .../set_exception_at_thread_exit_pass.cpp | 78 + .../futures/promise/set_exception_pass.cpp | 81 + .../set_lvalue_at_thread_exit_pass.cpp | 49 + test/sync/futures/promise/set_lvalue_pass.cpp | 57 + .../set_rvalue_at_thread_exit_pass.cpp | 48 + test/sync/futures/promise/set_rvalue_pass.cpp | 152 ++ .../set_value_at_thread_exit_const_pass.cpp | 45 + .../set_value_at_thread_exit_void_pass.cpp | 87 + .../futures/promise/set_value_const_pass.cpp | 86 + .../futures/promise/set_value_void_pass.cpp | 64 + .../shared_future/copy_assign_pass.cpp | 85 + .../futures/shared_future/copy_ctor_pass.cpp | 77 + .../futures/shared_future/default_pass.cpp | 45 + test/sync/futures/shared_future/dtor_pass.cpp | 109 + test/sync/futures/shared_future/get_pass.cpp | 208 ++ .../shared_future/move_assign_pass.cpp | 87 + .../futures/shared_future/move_ctor_pass.cpp | 78 + .../locks/lock_guard/adopt_lock_pass.cpp | 2 +- .../locks/lock_guard/copy_assign_fail.cpp | 2 +- .../locks/lock_guard/copy_ctor_fail.cpp | 2 +- .../locks/lock_guard/default_pass.cpp | 4 +- .../make_lock_guard_adopt_lock_pass.cpp | 77 + .../locks/lock_guard/make_lock_guard_pass.cpp | 74 + .../locks/lock_guard/types_pass.cpp | 2 + .../locks/reverse_lock/copy_assign_fail.cpp | 4 +- .../locks/reverse_lock/copy_ctor_fail.cpp | 4 +- .../locks/reverse_lock/types_pass.cpp | 3 +- .../reverse_lock/unique_lock_ctor_pass.cpp | 2 +- .../shared_lock/cons/adopt_lock_pass.cpp | 2 +- .../shared_lock/cons/copy_assign_fail.cpp | 2 +- .../locks/shared_lock/cons/copy_ctor_fail.cpp | 2 +- .../locks/shared_lock/cons/default_pass.cpp | 2 +- .../shared_lock/cons/defer_lock_pass.cpp | 2 +- .../locks/shared_lock/cons/duration_pass.cpp | 2 +- .../shared_lock/cons/move_assign_pass.cpp | 2 +- .../locks/shared_lock/cons/move_ctor_pass.cpp | 2 +- .../cons/move_ctor_unique_lock_pass.cpp | 2 +- .../cons/move_ctor_upgrade_lock_pass.cpp | 2 +- .../locks/shared_lock/cons/mutex_pass.cpp | 2 +- .../shared_lock/cons/time_point_pass.cpp | 2 +- .../shared_lock/cons/try_to_lock_pass.cpp | 2 +- .../locks/shared_lock/locking/lock_pass.cpp | 2 +- .../shared_lock/locking/try_lock_for_pass.cpp | 2 +- .../shared_lock/locking/try_lock_pass.cpp | 2 +- .../locking/try_lock_until_pass.cpp | 2 +- .../locks/shared_lock/locking/unlock_pass.cpp | 2 +- .../shared_lock/mod/member_swap_pass.cpp | 2 +- .../shared_lock/mod/non_member_swap_pass.cpp | 2 +- .../locks/shared_lock/mod/release_pass.cpp | 2 +- .../locks/shared_lock/obs/mutex_pass.cpp | 2 +- .../locks/shared_lock/obs/op_bool_pass.cpp | 2 +- .../locks/shared_lock/obs/owns_lock_pass.cpp | 2 +- .../locks/shared_lock/types_pass.cpp | 2 +- .../locks/shared_lock_guard/types_pass.cpp | 1 + .../unique_lock/cons/adopt_lock_pass.cpp | 2 +- .../unique_lock/cons/copy_assign_fail.cpp | 2 +- .../locks/unique_lock/cons/copy_ctor_fail.cpp | 2 +- .../locks/unique_lock/cons/default_pass.cpp | 2 +- .../unique_lock/cons/defer_lock_pass.cpp | 2 +- .../locks/unique_lock/cons/duration_pass.cpp | 2 +- .../cons/make_unique_lock_adopt_lock_pass.cpp | 34 + .../cons/make_unique_lock_defer_lock_pass.cpp | 35 + .../cons/make_unique_lock_mutex_pass.cpp | 74 + .../make_unique_lock_try_to_lock_pass.cpp | 101 + .../cons/make_unique_locks_mutex_pass.cpp | 81 + .../unique_lock/cons/move_assign_pass.cpp | 2 +- .../locks/unique_lock/cons/move_ctor_pass.cpp | 2 +- .../cons/move_ctor_shared_lock_for_pass.cpp | 2 +- .../cons/move_ctor_shared_lock_try_pass.cpp | 2 +- .../cons/move_ctor_shared_lock_until_pass.cpp | 2 +- .../cons/move_ctor_upgrade_lock_for_pass.cpp | 2 +- .../cons/move_ctor_upgrade_lock_pass.cpp | 2 +- .../cons/move_ctor_upgrade_lock_try_pass.cpp | 2 +- .../move_ctor_upgrade_lock_until_pass.cpp | 2 +- .../locks/unique_lock/cons/mutex_pass.cpp | 2 +- .../unique_lock/cons/time_point_pass.cpp | 2 +- .../unique_lock/cons/try_to_lock_pass.cpp | 2 +- .../locks/unique_lock/locking/lock_pass.cpp | 2 +- .../unique_lock/locking/try_lock_for_pass.cpp | 2 +- .../unique_lock/locking/try_lock_pass.cpp | 2 +- .../locking/try_lock_until_pass.cpp | 2 +- .../locks/unique_lock/locking/unlock_pass.cpp | 2 +- .../unique_lock/mod/member_swap_pass.cpp | 2 +- .../unique_lock/mod/non_member_swap_pass.cpp | 2 +- .../locks/unique_lock/mod/release_pass.cpp | 2 +- .../locks/unique_lock/obs/mutex_pass.cpp | 2 +- .../locks/unique_lock/obs/op_bool_pass.cpp | 2 +- .../locks/unique_lock/obs/op_int_fail.cpp | 2 +- .../locks/unique_lock/obs/owns_lock_pass.cpp | 2 +- .../locks/unique_lock/types_pass.cpp | 1 + .../upgrade_lock/cons/adopt_lock_pass.cpp | 2 +- .../upgrade_lock/cons/copy_assign_fail.cpp | 2 +- .../upgrade_lock/cons/copy_ctor_fail.cpp | 2 +- .../locks/upgrade_lock/cons/default_pass.cpp | 2 +- .../upgrade_lock/cons/defer_lock_pass.cpp | 2 +- .../locks/upgrade_lock/cons/duration_pass.cpp | 2 +- .../upgrade_lock/cons/move_assign_pass.cpp | 2 +- .../upgrade_lock/cons/move_ctor_pass.cpp | 2 +- .../cons/move_ctor_shared_lock_for_pass.cpp | 2 +- .../cons/move_ctor_shared_lock_try_pass.cpp | 2 +- .../cons/move_ctor_shared_lock_until_pass.cpp | 2 +- .../cons/move_ctor_unique_lock_pass.cpp | 2 +- .../locks/upgrade_lock/cons/mutex_pass.cpp | 2 +- .../upgrade_lock/cons/time_point_pass.cpp | 2 +- .../upgrade_lock/cons/try_to_lock_pass.cpp | 2 +- .../locks/upgrade_lock/locking/lock_pass.cpp | 2 +- .../locking/try_lock_for_pass.cpp | 2 +- .../upgrade_lock/locking/try_lock_pass.cpp | 2 +- .../locking/try_lock_until_pass.cpp | 2 +- .../upgrade_lock/locking/unlock_pass.cpp | 2 +- .../upgrade_lock/mod/member_swap_pass.cpp | 2 +- .../upgrade_lock/mod/non_member_swap_pass.cpp | 2 +- .../locks/upgrade_lock/mod/release_pass.cpp | 2 +- .../locks/upgrade_lock/obs/mutex_pass.cpp | 2 +- .../locks/upgrade_lock/obs/op_bool_pass.cpp | 2 +- .../locks/upgrade_lock/obs/owns_lock_pass.cpp | 2 +- .../locks/upgrade_lock/types_pass.cpp | 2 +- .../timed_mutex/assign_fail.cpp | 2 +- .../timed_mutex/copy_fail.cpp | 2 +- test/test_2309.cpp | 9 +- test/test_2741.cpp | 2 + test/test_3628.cpp | 12 +- test/test_4521.cpp | 2 + test/test_4882.cpp | 39 +- test/test_5351.cpp | 2 + test/test_5542_1.cpp | 2 + test/test_5542_2.cpp | 2 + test/test_5542_3.cpp | 2 + test/test_5891.cpp | 2 + test/test_6130.cpp | 4 +- test/test_6174.cpp | 5 +- test/test_7328.cpp | 8 + test/test_7571.cpp | 93 + test/test_7665.cpp | 39 + test/test_7666.cpp | 23 + test/test_barrier.cpp | 4 +- test/test_condition.cpp | 9 +- test/test_condition_notify_all.cpp | 16 +- test/test_condition_notify_one.cpp | 16 +- test/test_condition_timed_wait_times_out.cpp | 18 +- test/test_futures.cpp | 4 +- test/test_generic_locks.cpp | 14 +- test/test_lock_concept.cpp | 11 +- test/test_ml.cpp | 2 +- test/test_move_function.cpp | 7 +- test/test_mutex.cpp | 5 +- test/test_once.cpp | 15 +- test/test_shared_mutex.cpp | 27 +- test/test_shared_mutex_part_2.cpp | 24 +- test/test_shared_mutex_timed_locks.cpp | 14 +- test/test_shared_mutex_timed_locks_chrono.cpp | 14 +- test/test_thread.cpp | 15 +- test/test_thread_launching.cpp | 3 + test/test_thread_mf.cpp | 1 + test/test_tss.cpp | 9 +- test/test_xtime.cpp | 4 +- .../container/thread_ptr_list_pass.cpp | 2 +- test/threads/container/thread_vector_pass.cpp | 10 +- test/threads/thread/assign/move_pass.cpp | 1 - .../thread/constr/FrvalueArgs_pass.cpp | 7 +- test/threads/thread/constr/Frvalue_pass.cpp | 5 + test/util.inl | 6 +- 287 files changed, 14828 insertions(+), 3477 deletions(-) create mode 100644 doc/scoped_thread.qbk create mode 100644 example/ba_externallly_locked.cpp create mode 100644 example/future_then.cpp create mode 100644 example/make_future.cpp create mode 100644 example/not_interleaved.cpp create mode 100644 example/scoped_thread.cpp create mode 100644 example/strict_lock.cpp create mode 100644 example/synchronized_person.cpp create mode 100644 example/synchronized_value.cpp create mode 100644 example/thread_guard.cpp create mode 100644 include/boost/thread/detail/async_func.hpp create mode 100644 include/boost/thread/detail/invoke.hpp create mode 100644 include/boost/thread/detail/is_convertible.hpp create mode 100644 include/boost/thread/detail/log.hpp create mode 100644 include/boost/thread/detail/make_tuple_indices.hpp create mode 100644 include/boost/thread/externally_locked.hpp create mode 100644 include/boost/thread/externally_locked_stream.hpp create mode 100644 include/boost/thread/is_locked_by_this_thread.hpp create mode 100644 include/boost/thread/lock_algorithms.hpp create mode 100644 include/boost/thread/lock_concepts.hpp create mode 100644 include/boost/thread/lock_factories.hpp create mode 100644 include/boost/thread/lock_guard.hpp create mode 100644 include/boost/thread/lock_options.hpp create mode 100644 include/boost/thread/lock_traits.hpp create mode 100644 include/boost/thread/lock_types.hpp create mode 100644 include/boost/thread/lockable_adapter.hpp create mode 100644 include/boost/thread/lockable_concepts.hpp create mode 100644 include/boost/thread/lockable_traits.hpp create mode 100644 include/boost/thread/null_mutex.hpp create mode 100644 include/boost/thread/poly_lockable.hpp create mode 100644 include/boost/thread/poly_lockable_adapter.hpp create mode 100644 include/boost/thread/poly_shared_lockable.hpp create mode 100644 include/boost/thread/poly_shared_lockable_adapter.hpp create mode 100644 include/boost/thread/scoped_thread.hpp create mode 100644 include/boost/thread/strict_lock.hpp create mode 100644 include/boost/thread/synchronized_value.hpp create mode 100644 include/boost/thread/testable_mutex.hpp create mode 100644 include/boost/thread/thread_functors.hpp create mode 100644 include/boost/thread/thread_guard.hpp create mode 100644 test/sync/futures/future/then_pass.cpp create mode 100644 test/sync/futures/packaged_task/make_ready_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_exception_pass.cpp create mode 100644 test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_lvalue_pass.cpp create mode 100644 test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp create mode 100644 test/sync/futures/promise/set_rvalue_pass.cpp create mode 100644 test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp create mode 100644 test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp create mode 100644 test/sync/futures/promise/set_value_const_pass.cpp create mode 100644 test/sync/futures/promise/set_value_void_pass.cpp create mode 100755 test/sync/futures/shared_future/copy_assign_pass.cpp create mode 100644 test/sync/futures/shared_future/copy_ctor_pass.cpp create mode 100755 test/sync/futures/shared_future/default_pass.cpp create mode 100755 test/sync/futures/shared_future/dtor_pass.cpp create mode 100755 test/sync/futures/shared_future/get_pass.cpp create mode 100755 test/sync/futures/shared_future/move_assign_pass.cpp create mode 100755 test/sync/futures/shared_future/move_ctor_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_adopt_lock_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_adopt_lock_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_defer_lock_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_mutex_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_try_to_lock_pass.cpp create mode 100644 test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_locks_mutex_pass.cpp create mode 100644 test/test_7571.cpp create mode 100644 test/test_7665.cpp create mode 100644 test/test_7666.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index a05a735c..6d84dfe1 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -60,7 +60,7 @@ project boost/thread darwin:-Wextra darwin:-pedantic - darwin:-ansi + #darwin:-ansi darwin:-fpermissive darwin:-Wno-long-long @@ -70,7 +70,7 @@ project boost/thread clang:-Wextra clang:-pedantic - clang:-ansi + #clang:-ansi #clang:-fpermissive clang:-Wno-long-long @@ -91,6 +91,18 @@ project boost/thread clang-3.0:-Wno-delete-non-virtual-dtor #clang-3.0:-Wno-unused-function #clang-3.0:-Wno-unused-variable + +# Note: Some of the remarks from the Intel compiler are disabled +# remark #193: zero used for undefined preprocessing identifier "XXX" +# remark #304: access control not specified ("public" by default) +# remark #593: variable "XXX" was set but never used +# remark #1418: external function definition with no prior declaration +# remark #2415: variable "XXX" of static storage duration was declared but never referenced + + intel:-wd193,304,383,444 + intel:-wd593,981 + intel:-wd1418 + intel:-wd2415 # : default-build multi diff --git a/doc/changes.qbk b/doc/changes.qbk index 1225943f..23312a1e 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -8,6 +8,66 @@ [section:changes History] +[heading Version 4.0.0 - boost 1.53] + +Breaking changes: + +[warning +BOOST_THREAD_VERSION==3 by default since Boost 1.53. So that all the deprecated features since 1.50 are not included by default. You can change this by setting the appropriated define (see Configuration section). +] + +Deprecated features: + +[warning Deprecated features since boost 1.53 will be available only until boost 1.58.] + +* C++11 compliance: packaged_task is deprecated, use instead packaged_task. +See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK + +* [@http://svn.boost.org/trac/boost/ticket/7537 #7537] deprecate Mutex::scoped_lock and scoped_try_lock and boost::condition + +New Features: + +* [@http://svn.boost.org/trac/boost/ticket/6270 #6270] c++11 compliance: Add thread constructor from movable callable and movable arguments +Provided when BOOST_THREAD_PROVIDES_VARIADIC_THREAD is defined (Default value from Boost 1.55): +See BOOST_THREAD_PROVIDES_VARIADIC_THREAD and BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD. + +* [@http://svn.boost.org/trac/boost/ticket/7280 #7280] C++11 compliance: Add promise::...at_thread_exit functions + +* [@http://svn.boost.org/trac/boost/ticket/7281 #7281] C++11 compliance: Add ArgTypes to packaged_task template. +Provided when BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined (Default value from Boost 1.55). +See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK. + +* [@http://svn.boost.org/trac/boost/ticket/7282 #7282] C++11 compliance: Add packaged_task::make_ready_at_thread_exit function + +* [@http://svn.boost.org/trac/boost/ticket/7412 #7412] C++11 compliance: Add async from movable callable and movable arguments +Provided when BOOST_THREAD_PROVIDES_VARIADIC_THREAD and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK are defined (Default value from Boost 1.55): +See BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK and BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK, BOOST_THREAD_PROVIDES_VARIADIC_THREAD and BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD. + +* [@http://svn.boost.org/trac/boost/ticket/7413 #7413] C++11 compliance: Add async when the launch policy is deferred. +* [@http://svn.boost.org/trac/boost/ticket/7414 #7414] C++11 compliance: future::get post-condition should be valid()==false. +* [@http://svn.boost.org/trac/boost/ticket/7414 #7444] Async: Add make_future/make_shared_future. +* [@http://svn.boost.org/trac/boost/ticket/7445 #7445] Async: Add future<>.then. +* [@http://svn.boost.org/trac/boost/ticket/7449 #7449] Synchro: Add a synchronized value class. +* [@http://svn.boost.org/trac/boost/ticket/7540 #7540] Threads: Add a helper class that join a thread on destruction. +* [@http://svn.boost.org/trac/boost/ticket/7541 #7541] Threads: Add a thread wrapper class that joins on destruction. +* [@http://svn.boost.org/trac/boost/ticket/7575 #7575] C++11 compliance: A future created by async should "join" in the destructor. +* [@http://svn.boost.org/trac/boost/ticket/7587 #7587] Synchro: Add strict_lock and nested_strict_lock +* [@http://svn.boost.org/trac/boost/ticket/7588 #7588] Synchro: Split the locks.hpp in several files to limit dependencies +* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables +* [@http://svn.boost.org/trac/boost/ticket/7590 #7590] Synchro: Add lockable concept checkers based on Boost.ConceptCheck +* [@http://svn.boost.org/trac/boost/ticket/7591 #7591] Add lockable traits that can be used with enable_if +* [@http://svn.boost.org/trac/boost/ticket/7592 #7592] Synchro: Add a null_mutex that is a no-op and that is a model of UpgardeLockable +* [@http://svn.boost.org/trac/boost/ticket/7593 #7593] Synchro: Add a externally_locked class +* [@http://svn.boost.org/trac/boost/ticket/7590 #7594] Threads: Allow to disable thread interruptions + +Fixed Bugs: + +* [@http://svn.boost.org/trac/boost/ticket/7657 #7657] Serious performance and memory consuption hit if condition_variable methods condition notify_one or notify_all is used repeatedly. +* [@http://svn.boost.org/trac/boost/ticket/7668 #7668] thread_group::join_all() should check whether its threads are joinable. +* [@http://svn.boost.org/trac/boost/ticket/7669 #7669] thread_group::join_all() should catch resource_deadlock_would_occur. +* [@http://svn.boost.org/trac/boost/ticket/7672 #7672] lockable_traits.hpp syntax error: "defined" token misspelled. + + [heading Version 3.1.0 - boost 1.52] Deprecated Features: @@ -58,6 +118,7 @@ Fixed Bugs: * [@http://svn.boost.org/trac/boost/ticket/7438 #7438] Segmentation fault in test_once regression test in group.join_all(); * [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0 * [@http://svn.boost.org/trac/boost/ticket/7499 #7499] call_once doesn't call even once + [heading Version 3.0.1 - boost 1.51] @@ -274,10 +335,22 @@ 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/7413 #7413] c++11 compliance: Add async when the launch policy is deferred. + * [@http://svn.boost.org/trac/boost/ticket/7280 #7280] C++11 compliance: Add promise::...at_thread_exit functions. + * [@http://svn.boost.org/trac/boost/ticket/7282 #7282] C++11 compliance: Add packaged_task::make_ready_at_thread_exit function. + * [@http://svn.boost.org/trac/boost/ticket/7285 #7285] C++11 compliance: Allow to pass movable arguments for call_once. + * [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them. - * async with deferred and variadic rvalue reference args. - * [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Use of variadic templates on Generic Locking Algorithms on compilers providing them. - * [@http://svn.boost.org/trac/boost/ticket/6270 #6270] Add thread constructor from movable callable and movable arguments following C++11. + +# 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], in particular + + * [@http://svn.boost.org/trac/boost/ticket/7445 #7445] Async: Add future<>.then + * [@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 + + +# Add a synchronized value class following the design in [@http://www.drdobbs.com/cpp/enforcing-correct-mutex-usage-with-synch/225200269 Enforcing Correct Mutex Usage with Synchronized Values] diff --git a/doc/compliance.qbk b/doc/compliance.qbk index de2a4247..999a9d8c 100644 --- a/doc/compliance.qbk +++ b/doc/compliance.qbk @@ -25,10 +25,10 @@ [[30.2.5.3] [Lockable requirements] [yes] [-] [-]] [[30.2.5.4] [TimedLockable requirements] [Yes] [-] [-]] [[30.2.6] [decay_copy] [-] [-] [-]] - [[30.3] [Threads] [Partial] [-] [-]] - [[30.3.1] [Class thread] [Partial] [move,variadic,terminate] [#6270]] + [[30.3] [Threads] [Yes] [-] [-]] + [[30.3.1] [Class thread] [Yes] [-] [-]] [[30.3.1.1] [Class thread::id] [Yes] [-] [-]] - [[30.3.1.2] [thread constructors] [Partial] [move,variadic] [#6270]] + [[30.3.1.2] [thread constructors] [Partial] [-] [-]] [[30.3.1.3] [thread destructor] [Yes] [-] [-]] [[30.3.1.4] [thread assignment] [Yes] [-] [-]] [[30.3.1.5] [thread members] [Yes] [-] [-]] @@ -45,7 +45,7 @@ [[30.4.1.3] [Timed mutex types] [Yes] [-] [-]] [[30.4.1.3.1] [Class timed_mutex] [Yes] [-] [-]] [[30.4.1.3.1] [Class recursive_timed_mutex] [Yes] [-] [-]] - [[30.4.2] [Locks] [Partial] [variadic] [#6227]] + [[30.4.2] [Locks] [Yes] [-] [-]] [[30.4.2.1] [Class template lock_guard] [Yes] [-] [-]] [[30.4.2.2] [Class template unique_lock] [Yes] [-] [-]] [[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Yes] [-] [-]] @@ -56,20 +56,19 @@ [[30.4.4] [Call once] [Partial] [call_once] [#7285]] [[30.4.4.1] [Struct once_flag] [Yes] [-] [-]] [[30.4.4.2] [Function call_once] [Partial] [interface] [#7285]] - [[30.5] [Condition variables] [Partial] [notify_all_at_thread_exit] [#7283]] - [[30.5 6-10] [Function notify_all_at_thread_exit] [No] [-] [#7283]] + [[30.5] [Condition variables] [Yes] [-] [-]] [[30.5.1] [Class condition_variable] [Yes] [-] [-]] [[30.5.2] [Class condition_variable_any] [Yes] [-] [-]] - [[30.6] [Futures] [Partial] [async,at_thread_exit] [#4710,#7280]] + [[30.6] [Futures] [Partial] [noexcept] [#7279]] [[30.6.1] [Overview] [Partial] [-] [-]] [[30.6.2] [Error handling] [Yes] [-] [-]] [[30.6.3] [Class future_error] [Partial] [noexcept] [#7279]] [[30.6.4] [Shared state] [-] [-] [-]] - [[30.6.5] [Class template promise] [Partial] [at_thread_exit] [#7280]] + [[30.6.5] [Class template promise] [Yes] [-] [-]] [[30.6.6] [Class template future] [Yes] [-] [-]] [[30.6.7] [Class template shared_future] [Yes] [-] [-]] - [[30.6.8] [Function template async] [Partial] [deferred not implemented and only a copyable functor is allowed yet] [#4710]] - [[30.6.9] [Class template packaged_task] [Partial] [args,make_ready_at_thread_exit] [#7281,#7282]] + [[30.6.8] [Function template async] [Yes] [-] [-]] + [[30.6.9] [Class template packaged_task] [Yes] [-] [-]] ] [/ diff --git a/doc/configuration.qbk b/doc/configuration.qbk index 35d63724..4d7a1657 100644 --- a/doc/configuration.qbk +++ b/doc/configuration.qbk @@ -9,30 +9,158 @@ [section:configuration Configuration] +[table Default Values for Configurable Features + [[Feature] [Anti-Feature] [V2] [V3] [V4] ] + [[USES_CHRONO] [DONT_USE_CHRONO] [YES] [YES] [YES] ] + [[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ] + [[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ] + + + + [[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] ] + + [[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] ] + [[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] ] + + [[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] ] + [[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] ] + [[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] ] + [[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] ] + [[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ] + [[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ] + [[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] ] + [[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] ] + + [[USES_DATETIME] [DONT_USE_DATETIME] [YES] [YES] [NO] ] + [[PROVIDES_THREAD_EQ] [DONT_PROVIDE_THREAD_EQ] [YES] [YES] [NO] ] + [[PROVIDES_CONDITION] [DONT_PROVIDE_CONDITION] [YES] [YES] [NO] ] + [[PROVIDES_NESTED_LOCKS] [DONT_PROVIDE_NESTED_LOCKS] [YES] [YES] [NO] ] + [[PROVIDES_SIGNATURE_PACKAGED_TASK] [DONT_PROVIDE_SIGNATURE_PACKAGED_TASK] [NO] [NO] [YES] ] + [[PROVIDES_FUTURE_INVALID_AFTER_GET] [DONT_PROVIDE_FUTURE_INVALID_AFTER_GET] [NO] [NO] [YES] ] + [[PROVIDES_FUTURE_CONTINUATION] [DONT_PROVIDE_FUTURE_CONTINUATION] [NO] [NO] [YES] ] + + [[PROVIDES_VARIADIC_THREAD] [DONT_PROVIDE_VARIADIC_THREAD] [NO] [NO] [C++11] ] + +] + [section:chrono Boost.Chrono] -Boost.Thread uses by default Boost.Chrono for the time related functions. For backward compatibility and also for compilers that don't work well with Boost.Chrono the user can define `BOOST_THREAD_DONT_USE_CHRONO`. - -`BOOST_THREAD_USES_CHRONO` is defined when Boost.Thread uses Boost.Chrono. - +Boost.Thread uses by default Boost.Chrono for the time related functions and define `BOOST_THREAD_USES_CHRONO` if `BOOST_THREAD_DONT_USE_CHRONO` is not defined. The user should define `BOOST_THREAD_DONT_USE_CHRONO` for compilers that don't work well with Boost.Chrono. [endsect] + [section:move Boost.Move] Boost.Thread uses by default an internal move semantic implementation. Since version 3.0.0 you can use the move emulation emulation provided by Boost.Move. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_USES_MOVE ` if you want to use Boost.Move interface. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_USE_MOVE ` if you don't want to use Boost.Move interface. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_USE_MOVE ` if you don't want to use Boost.Move interface. [endsect] +[section:date_time Boost.DateTime] + +The Boost.DateTime time related functions introduced in Boost 1.35.0, using the [link date_time Boost.Date_Time] library are deprecated. These include (but are not limited to): + +* __sleep__ +* __timed_join__ +* __cond_timed_wait__ +* __timed_lock_ref__ + + +When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_DONT_USE_DATETIME ` if you don't want to use Boost.DateTime related interfaces. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_USES_DATETIME ` if you want to use Boost.DateTime related interfaces. + +[endsect] + + +[section:thread_eq `boost::thread::oprator==` deprecated] + +The following nested typedefs are deprecated: + +* `boost::thread::oprator==` +* `boost::thread::oprator!=` + +When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature. + +Use instead + +* `boost::thread::id::oprator==` +* `boost::thread::id::oprator!=` + +[warning This is a breaking change respect to version 1.x.] + +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_PROVIDES_THREAD_EQ ` if you want this feature. +When `BOOST_THREAD_VERSION<3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_EQ ` if you don't want this feature. + +[endsect] + +[section:condition boost::condition deprecated] + +`boost::condition` is deprecated. When `BOOST_THREAD_PROVIDES_CONDITION` is defined Boost.Thread provides this deprecated feature. + +Use instead `boost::condition_variable_any`. + +[warning This is a breaking change respect to version 1.x.] + +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_PROVIDES_CONDITION` if you want this feature. +When `BOOST_THREAD_VERSION<3` define `BOOST_THREAD_DONT_PROVIDE_CONDITION` if you don't want this feature. + +[endsect] + +[section:nested_lock Mutex nested lock types deprecated] + + +The following nested typedefs are deprecated: + +* `boost::mutex::scoped_lock`, +* `boost::mutex::scoped_try_lock`, +* `boost::timed_mutex::scoped_lock` +* `boost::timed_mutex::scoped_try_lock` +* `boost::timed_mutex::timed_scoped_timed_lock` +* `boost::recursive_mutex::scoped_lock`, +* `boost::recursive_mutex::scoped_try_lock`, +* `boost::recursive_timed_mutex::scoped_lock` +* `boost::recursive_timed_mutex::scoped_try_lock` +* `boost::recursive_timed_mutex::timed_scoped_timed_lock` + +When `BOOST_THREAD_PROVIDES_NESTED_LOCKS` is defined Boost.Thread provides these deprecated feature. + + +Use instead +* `boost::unique_lock`, +* `boost::unique_lock` with the `try_to_lock_t` constructor, +* `boost::unique_lock` +* `boost::unique_lock` with the `try_to_lock_t` constructor +* `boost::unique_lock` +* `boost::unique_lock`, +* `boost::unique_lock` with the `try_to_lock_t` constructor, +* `boost::unique_lock` +* `boost::unique_lock` with the `try_to_lock_t` constructor +* `boost::unique_lock` + +[warning This is a breaking change respect to version 1.x.] + +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_PROVIDES_NESTED_LOCKS` if you want these features. +When `BOOST_THREAD_VERSION<3` define `BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS` if you don't want thes features. + +[endsect] + +[section:id thread::id] + +Boost.Thread uses by default a thread::id on Posix based on the pthread type (BOOST_THREAD_PROVIDES_BASIC_THREAD_ID). For backward compatibility and also for compilers that don't work well with this modification the user can define `BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID`. + +When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_BASIC_THREAD_ID ` if you want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID ` if you don't want these features. + +[endsect] [section:shared_gen Shared Locking Generic] The shared mutex implementation on Windows platform provides currently less functionality than the generic one that is used for PTheads based platforms. In order to have access to these functions, the user needs to define `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` to use the generic implementation, that while could be less efficient, provides all the functions. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN ` if you want these features. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN ` if you don't want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN ` if you don't want these features. [endsect] @@ -42,7 +170,7 @@ Boost.Threads includes in version 3 the Shared Locking Upwards Conversion as def These conversions need to be used carefully to avoid deadlock or livelock. The user need to define explicitly `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` to get these upwards conversions. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION ` if you want these features. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features. [endsect] @@ -62,7 +190,7 @@ C++11 uses `std::future`. Versions of Boost.Thread previous to version 3.0.0 use Since version 3.0.0 `boost::future` replaces `boost::unique_future` when `BOOST_THREAD_PROVIDES_FUTURE` is defined. The documentation doesn't contains anymore however `boost::unique_future`. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_FUTURE` if you want to use boost::future. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE` if you want to use boost::unique_future. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE` if you want to use boost::unique_future. [endsect] @@ -73,7 +201,7 @@ C++11 promise initialize the associated state at construction time. Versions of Since version 3.0.0 this difference in behavior can be configured. When `BOOST_THREAD_PROVIDES_PROMISE_LAZY` is defined the backward compatible behavior is provided. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY ` if you want to use boost::future. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_PROVIDES_PROMISE_LAZY ` if you want to use boost::unique_future. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_PROVIDES_PROMISE_LAZY ` if you want to use boost::unique_future. [endsect] @@ -117,7 +245,7 @@ Since version 3.0.0 Boost.Thread implements this constructor using the following which introduces a dependency on Boost.Container. This feature is provided only if `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS` is defined. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS ` if you want these features. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS ` if you don't want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS ` if you don't want these features. [endsect] @@ -126,10 +254,10 @@ When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALL C++11 has a different semantic for the thread destructor and the move assignment. Instead of detaching the thread, calls to terminate() if the thread was joinable. When `BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE` and `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE` is defined Boost.Thread provides the C++ semantic. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you want these features. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features. When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you want these features. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE ` if you don't want these features. [endsect] @@ -144,44 +272,91 @@ You should now just do boost::once_flag once; When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_ONCE_CXX11` if you want these features. -When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11` if you don't want these features. +When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11` if you don't want these features. [endsect] -[section:deprecated Deprecated] -Version 3.0.0 deprecates some Boost.Thread features. +[section:deprecated Signature parameter for packaged_task] -These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define `BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define `BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0`. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features. +C++11 packaged task class has a Signature template parameter. When `BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK ` is defined Boost.Thread provides this C++ feature. +[warning This is a breaking change respect to version 3.x.] + +When `BOOST_THREAD_VERSION<=3` define `BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK` if you want this feature. +When `BOOST_THREAD_VERSION>4` define `BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK` if you don't want this feature. [endsect] +[section:thread_const-var thread constructor with variadic rvalue parameters] + +C++11 thread constructor accep a variable number of rvalue argumentshas. When `BOOST_THREAD_PROVIDES_VARIADIC_THREAD ` is defined Boost.Thread provides this C++ feature if the following are not defined + +* BOOST_NO_CXX11_VARIADIC_TEMPLATES +* BOOST_NO_CXX11_DECLTYPE +* BOOST_NO_CXX11_RVALUE_REFERENCES +* BOOST_NO_CXX11_HDR_TUPLE + +When `BOOST_THREAD_VERSION>4` define `BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD ` if you don't want this feature. + +[endsect] + +[section:get_invalid future<>::get() invalidates the future] + +C++11 future<>::get() invalidates the future once its value has been obtained. When `BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET ` is defined Boost.Thread provides this C++ feature. + +[warning This is a breaking change respect to version 3.x.] + +When `BOOST_THREAD_VERSION<=3` define `BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET` if you want this feature. +When `BOOST_THREAD_VERSION>4` define `BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET` if you don't want this feature. + +[endsect] + +[section:intr Interruptions] + +Thread interruption, while useful, makes any interruption point less efficient than if the thread were not interruptible. + +When `BOOST_THREAD_PROVIDES_INTERRUPTIONS` is defined Boost.Thread provides interruptions. +When `BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS` is defined Boost.Thread don't provide interruption. + +Boost.Thread defines BOOST_THREAD_PROVIDES_INTERRUPTIONS if neither BOOST_THREAD_PROVIDES_INTERRUPTIONS nor BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS are defined, so that there is no compatibility break. + +[endsect] + [section:version Version] `BOOST_THREAD_VERSION` defines the Boost.Thread version. The default version is 2. In this case the following breaking or extending macros are defined if the opposite is not requested: * `BOOST_THREAD_PROVIDES_PROMISE_LAZY` -* `BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0` The user can request the version 3 by defining `BOOST_THREAD_VERSION` to 3. In this case the following breaking or extending macros are defined if the opposite is not requested: * Breaking change `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION ` -* Breaking change `BOOST_THREAD_PROVIDES_FUTURE` +* Conformity & Breaking change `BOOST_THREAD_PROVIDES_FUTURE` * Uniformity `BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN` * Extension `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` * Conformity `BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS` -* Breaking change BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE -* Breaking change BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE -* Breaking change `BOOST_THREAD_PROVIDES_ONCE_CXX11` +* Conformity & Breaking change BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE +* Conformity & Breaking change BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE +* Conformity & Breaking change `BOOST_THREAD_PROVIDES_ONCE_CXX11` * Breaking change `BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY` -* Breaking change `BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0` The default value for `BOOST_THREAD_VERSION` will be changed to 3 since Boost 1.53. +The user can request the version 4 by defining `BOOST_THREAD_VERSION` to 4. In this case the following breaking or extending macros are defined if the opposite is not requested: + +* Conformity & Breaking change `BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK ` +* Conformity & Breaking change `BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET ` +* Conformity `BOOST_THREAD_PROVIDES_VARIADIC_THREAD` +* Breaking change `BOOST_THREAD_DONT_PROVIDE_THREAD_EQ` +* Breaking change `BOOST_THREAD_DONT_USE_DATETIME` + + +The default value for `BOOST_THREAD_VERSION` will be changed to 4 since Boost 1.56. + [endsect] [endsect] @@ -207,8 +382,19 @@ If __SUNPRO_CC < 0x5100 the library defines If __IBMCPP__ < 1100 the library defines * `BOOST_THREAD_DONT_USE_CHRONO` +* `BOOST_THREAD_USES_DATE` And Boost.Thread doesn't links with Boost.Chrono. + [endsect] +[section:ce WCE] + +If _WIN32_WCE && _WIN32_WCE==0x501 the library defines + +* `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS` + + +[endsect] + [endsect] diff --git a/doc/future_ref.qbk b/doc/future_ref.qbk index 16e5d341..44ae2251 100644 --- a/doc/future_ref.qbk +++ b/doc/future_ref.qbk @@ -12,12 +12,10 @@ namespace boost { - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - namespace future_state + namespace future_state // EXTENSION { enum state {uninitialized, waiting, ready, moved}; } - #endif enum class future_errc { @@ -69,12 +67,12 @@ template class shared_future; - template + template class packaged_task; - template void swap(packaged_task&, packaged_task&) noexcept; + template void swap(packaged_task&, packaged_task&) noexcept; - template - struct uses_allocator, Alloc>; + template + struct uses_allocator, Alloc>; template future::type()>::type> @@ -83,27 +81,31 @@ future::type()>::type> async(launch policy, F f); - // template - // future::type(typename decay::type...)>::type> - // async(F&& f, Args&&... args); // NOT YET IMPLEMENTED - // template - // future::type(typename decay::type...)>::type> - // async(launch policy, F&& f, Args&&... args); // NOT YET IMPLEMENTED - - + template + future::type(typename decay::type...)>::type> + async(F&& f, Args&&... args); + template + future::type(typename decay::type...)>::type> + async(launch policy, F&& f, Args&&... args); + template void wait_for_all(Iterator begin,Iterator end); // EXTENSION - template void wait_for_all(F1& f1,Fs&... fs); // EXTENSION template Iterator wait_for_any(Iterator begin,Iterator end); - template unsigned wait_for_any(F1& f1,Fs&... fs); - - + + template + future::type> make_future(T&& value); // EXTENSION + future make_future(); // EXTENSION + + template + shared_future::type> make_shared_future(T&& value); // EXTENSION + shared_future make_shared_future(); // EXTENSION + [section:future_state Enumeration `state`] namespace future_state @@ -115,18 +117,21 @@ [endsect] -[section:future_errc Enumeration `future_errc `] +[section:future_errc Enumeration `future_errc`] enum class future_errc { - broken_promise, - future_already_retrieved, - promise_already_satisfied, - no_state + broken_promise = implementation defined, + future_already_retrieved = implementation defined, + promise_already_satisfied = implementation defined, + no_state = implementation defined } + + The enum values of future_errc are distinct and not zero. + [endsect] -[section:launch Enumeration `launch `] +[section:launch Enumeration `launch`] enum class launch { @@ -256,14 +261,23 @@ The object's `name` virtual function returns a pointer to the string "future".]] __unique_future__(__unique_future__ && other) noexcept; __unique_future__& operator=(__unique_future__ && other) noexcept; shared_future share(); - + template + __unique_future__::type> + then(F&& func); // EXTENSION + template + __unique_future__::type> + then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED + template + __unique_future__::type> + then(launch policy, F&& func); // EXTENSION NOT_YET_IMPLEMENTED + void swap(__unique_future__& other) noexcept; // EXTENSION // retrieving the value R&& get(); // functions to check state - bool valid() const; + bool valid() const noexcept; bool is_ready() const; // EXTENSION bool has_exception() const; // EXTENSION bool has_value() const; // EXTENSION @@ -275,15 +289,13 @@ The object's `name` virtual function returns a pointer to the string "future".]] template future_status wait_until(const chrono::time_point& abs_time) const; - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO + #if defined BOOST_THREAD_USES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO template - bool timed_wait(Duration const& rel_time) const; - bool timed_wait_until(boost::system_time const& abs_time) const; - #endif - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - typedef future_state::state state; - state get_state() const; + bool timed_wait(Duration const& rel_time) const; // DEPRECATED SINCE V3.0.0 + bool timed_wait_until(boost::system_time const& abs_time) const; // DEPRECATED SINCE V3.0.0 #endif + typedef future_state::state state; // EXTENSION + state get_state() const; // EXTENSION }; [section:default_constructor Default Constructor] @@ -395,9 +407,14 @@ value. Otherwise, returns an rvalue-reference to the value stored in the asynchr [[Postconditions:] [[unique_future_is_ready_link `this->is_ready()`] returns `true`. [unique_future_get_state_link `this->get_state()`] returns __ready__.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception stored in the -asynchronous result in place of a value.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception stored in the asynchronous result in place of a value. +]] [[Notes:] [`get()` is an ['interruption point].]] @@ -407,16 +424,21 @@ asynchronous result in place of a value.]] [section:wait Member function `wait()`] - void wait(); + void wait() const; [variablelist [[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result +associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [[unique_future_is_ready_link `this->is_ready()`] returns `true`. [unique_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -427,11 +449,19 @@ associated with `*this` is not ready at the point of the call, and the current t [endsect] -[section:timed_wait_duration Member function `timed_wait()`] +[section:timed_wait_duration Member function `timed_wait()` DEPRECATED SINCE V3.0.0] template bool timed_wait(Duration const& wait_duration); +[warning +DEPRECATED since 3.00. + +Available only up to Boost 1.56. + +Use instead __wait_for. +] + [variablelist [[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time specified by @@ -441,9 +471,13 @@ invoked prior to waiting.]] [[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has elapsed, `false` otherwise.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and [unique_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -454,10 +488,18 @@ associated with `*this` is not ready at the point of the call, and the current t [endsect] -[section:timed_wait_absolute Member function `timed_wait()`] +[section:timed_wait_absolute Member function `timed_wait()` DEPRECATED SINCE V3.0.0] bool timed_wait(boost::system_time const& wait_timeout); +[warning +DEPRECATED since 3.00. + +Available only up to Boost 1.56. + +Use instead __wait_until. +] + [variablelist [[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready, or the time point specified by @@ -467,9 +509,13 @@ prior to waiting.]] [[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has passed, `false` otherwise.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and [unique_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -501,9 +547,13 @@ invoked prior to waiting.]] ]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and [unique_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -535,9 +585,13 @@ prior to waiting.]] ]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [unique_future_is_ready_link `this->is_ready()`] returns `true` and [unique_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -551,7 +605,7 @@ associated with `*this` is not ready at the point of the call, and the current t [section:valid Member function `valid()`] - bool valid() const; + bool valid() const noexcept; [variablelist @@ -625,6 +679,60 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] [endsect] +[section:then Member function `then()`] + + template + __unique_future__::type> + then(F&& func); // EXTENSION + template + __unique_future__::type> + then(S& scheduler, F&& func); // EXTENSION + template + __unique_future__::type> + then(launch policy, F&& func); // EXTENSION + +[variablelist + +[[Notes:] [The three functions differ only by input parameters. The first only takes a callable object which accepts a +future object as a parameter. The second function takes a scheduler as the first parameter and a callable object as +the second parameter. The third function takes a launch policy as the first parameter and a callable object as the +second parameter.]] + +[[Effects:] [ + +- 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. + +- 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 std::promise or with a packaged_task (has no associated launch policy), the +continuation behaves the same as the third overload with a policy argument of launch::async | launch::deferred and +the same argument for func. + +- If the parent has a policy of launch::deferred and the continuation does not have a specified launch policy or +scheduler, then the parent is filled by immediately calling .wait(), and the policy of the antecedent is +launch::deferred + +]] + +[[Returns:] [An object of type future that refers to the shared state created by the continuation.]] + +[[Postconditions:] [ + +- The future object is moved to the parameter of the continuation function . + +- valid() == false on original future object immediately after it returns. + +]] + +] + +[endsect] + + + [endsect] @@ -667,14 +775,12 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] template future_status wait_until(const chrono::time_point& abs_time) const; - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO + #if defined BOOST_THREAD_USES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO template - bool timed_wait(Duration const& rel_time) const; - bool timed_wait_until(boost::system_time const& abs_time) const; - #endif - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - state get_state() const noexcept; + bool timed_wait(Duration const& rel_time) const; // DEPRECATED SINCE V3.0.0 + bool timed_wait_until(boost::system_time const& abs_time) const; // DEPRECATED SINCE V3.0.0 #endif + state get_state() const noexcept; // EXTENSION }; [section:default_constructor Default Constructor] @@ -706,8 +812,12 @@ __shared_future_wait__, and returns a `const` reference to the result.]] [[Returns:] [If the result type `R` is a reference, returns the stored reference. If `R` is `void`, there is no return value. Otherwise, returns a `const` reference to the value stored in the asynchronous result.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the -result associated with `*this` is not ready at the point of the call, and the current thread is interrupted.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. +]] [[Notes:] [`get()` is an ['interruption point].]] @@ -717,15 +827,19 @@ result associated with `*this` is not ready at the point of the call, and the cu [section:wait Member function `wait()`] - void wait(); + void wait() const; [variablelist [[Effects:] [If `*this` is associated with an asynchronous result, waits until the result is ready. If the result is not ready on entry, and the result has a ['wait callback] set, that callback is invoked prior to waiting.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the +[[Throws:] [ +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [[shared_future_is_ready_link `this->is_ready()`] returns `true`. [shared_future_get_state_link @@ -751,9 +865,13 @@ invoked prior to waiting.]] [[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has elapsed, `false` otherwise.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ + +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and [shared_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -777,9 +895,12 @@ prior to waiting.]] [[Returns:] [`true` if `*this` is associated with an asynchronous result, and that result is ready before the specified time has passed, `false` otherwise.]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and [shared_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -812,9 +933,12 @@ invoked prior to waiting.]] ]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called.]] [[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and [shared_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -846,9 +970,13 @@ prior to waiting.]] ]] -[[Throws:] [__future_uninitialized__ if `*this` is not associated with an asynchronous result. __thread_interrupted__ if the result -associated with `*this` is not ready at the point of the call, and the current thread is interrupted. Any exception thrown by the -['wait callback] if such a callback is called.]] +[[Throws:] [ +- __future_uninitialized__ if `*this` is not associated with an asynchronous result. + +- __thread_interrupted__ if the result associated with `*this` is not ready at the point of the call, and the current thread is interrupted. + +- Any exception thrown by the ['wait callback] if such a callback is called. +]] [[Postconditions:] [If this call returned `true`, then [shared_future_is_ready_link `this->is_ready()`] returns `true` and [shared_future_get_state_link `this->get_state()`] returns __ready__.]] @@ -861,7 +989,7 @@ associated with `*this` is not ready at the point of the call, and the current t [section:valid Member function `valid()`] - bool valid() const; + bool valid() const noexcept; [variablelist @@ -962,14 +1090,12 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]] __unique_future__ get_future(); // Set the value - void set_value(R& r); - void set_value(R&& r); + void set_value(see below); void set_exception(boost::exception_ptr e); // setting the result with deferred notification - // void set_value_at_thread_exit(const R& r); // NOT YET IMPLEMENTED - // void set_value_at_thread_exit(see below); // NOT YET IMPLEMENTED - // void set_exception_at_thread_exit(exception_ptr p); // NOT YET IMPLEMENTED + void set_value_at_thread_exit(see below); + void set_exception_at_thread_exit(exception_ptr p); template void set_wait_callback(F f); // EXTENSION @@ -1083,15 +1209,24 @@ memory necessary could not be allocated.]] [variablelist -[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with -`*this`. Store the value `r` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous -result are woken.]] +[[Effects:] [ +- If BOOST_THREAD_PROVIDES_PROMISE_LAZY is defined and if `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with `*this`. + +- Store the value `r` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous +result are woken. +]] [[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_value__ or __shared_future_has_value__ for those futures shall return `true`.]] -[[Throws:] [__promise_already_satisfied__ if the result associated with `*this` is already ['ready]. `std::bad_alloc` if the memory -required for storage of the result cannot be allocated. Any exception thrown by the copy or move-constructor of `R`.]] +[[Throws:] [ +- __promise_already_satisfied__ if the result associated with `*this` is already ['ready]. + +- __broken_promise__ if `*this` has no shared state. + +- `std::bad_alloc` if the memory required for storage of the result cannot be allocated. + +- Any exception thrown by the copy or move-constructor of `R`.]] ] @@ -1103,21 +1238,83 @@ required for storage of the result cannot be allocated. Any exception thrown by [variablelist -[[Effects:] [If `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with -`*this`. Store the exception `e` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous +[[Effects:] [ +- If BOOST_THREAD_PROVIDES_PROMISE_LAZY is defined and if `*this` was not associated with a result, allocate storage for a new asynchronous result and associate it with +`*this`. + +- Store the exception `e` in the asynchronous result associated with `*this`. Any threads blocked waiting for the asynchronous result are woken.]] [[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_exception__ or __shared_future_has_exception__ for those futures shall return `true`.]] -[[Throws:] [__promise_already_satisfied__ if the result associated with `*this` is already ['ready]. `std::bad_alloc` if the memory -required for storage of the result cannot be allocated.]] +[[Throws:] [ +- __promise_already_satisfied__ if the result associated with `*this` is already ['ready]. + +- __broken_promise__ if `*this` has no shared state. + +- `std::bad_alloc` if the memory required for storage of the result cannot be allocated. +]] ] [endsect] -[section:set_wait_callback Member Function `set_wait_callback()`] +[section:set_value_at_thread_exit Member Function `set_value_at_thread_exit()`] + + void set_value_at_thread_exit(R&& r); + void set_value_at_thread_exit(const R& r); + void promise::set_value_at_thread_exit(R& r); + void promise::set_value_at_thread_exit(); + +[variablelist + +[[Effects:] [ +Stores the value r in the shared state without making that state ready immediately. +Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration +associated with the current thread have been destroyed.]] + + +[[Throws:] [ +- __promise_already_satisfied__ if the result associated with `*this` is already ['ready]. + +- __broken_promise__ if `*this` has no shared state. + +- `std::bad_alloc` if the memory required for storage of the result cannot be allocated. + +- Any exception thrown by the copy or move-constructor of `R`. +]] + +] + +[endsect] + +[section:set_exception_at_thread_exit Member Function `set_exception_at_thread_exit()`] + + void set_exception_at_thread_exit(boost::exception_ptr e); + +[variablelist + +[[Effects:] [ +Stores the exception pointer p in the shared state without making that state ready immediately. +Schedules that state to be made ready when the current thread exits, after all objects of thread storage duration + associated with the current thread have been destroyed.]] + +[[Postconditions:] [All futures waiting on the asynchronous result are ['ready] and __unique_future_has_exception__ or +__shared_future_has_exception__ for those futures shall return `true`.]] + +[[Throws:] [ +- __promise_already_satisfied__ if the result associated with `*this` is already ['ready]. + +- __broken_promise__ if `*this` has no shared state. + +- `std::bad_alloc` if the memory required for storage of the result cannot be allocated. +]] + +] + +[endsect] +[section:set_wait_callback Member Function `set_wait_callback()` EXTENSION] template void set_wait_callback(F f); @@ -1141,25 +1338,27 @@ or __shared_future__ associated with this result, and the result is not ['ready] [section:packaged_task `packaged_task` class template] + template + class packaged_task; template - class packaged_task + class packaged_task { public: - typedef R result_type; - packaged_task(packaged_task&);// = delete; packaged_task& operator=(packaged_task&);// = delete; // construction and destruction packaged_task() noexcept; - explicit packaged_task(R(*f)()); + explicit packaged_task(R(*f)(ArgTypes...)); template explicit packaged_task(F&& f); + template + packaged_task(allocator_arg_t, Allocator a, R(*f)(ArgTypes...)); template packaged_task(allocator_arg_t, Allocator a, F&& f); @@ -1177,9 +1376,8 @@ or __shared_future__ associated with this result, and the result is not ['ready] __unique_future__ get_future(); // execution - void operator()(); - // void operator()(ArgTypes... ); // NOT YET IMPLEMENTED - // void make_ready_at_thread_exit(ArgTypes...); // NOT YET IMPLEMENTED + void operator()(ArgTypes... ); + void make_ready_at_thread_exit(ArgTypes...); void reset(); template @@ -1188,22 +1386,29 @@ or __shared_future__ associated with this result, and the result is not ['ready] [section:task_constructor Task Constructor] - packaged_task(R(*f)()); + packaged_task(R(*f)(ArgTypes...)); template packaged_task(F&&f); [variablelist -[[Preconditions:] [`f()` is a valid expression with a return type convertible to `R`. Invoking a copy of `f` shall behave the same +[[Preconditions:] [`f()` is a valid expression with a return type convertible to `R`. Invoking a copy of `f` must behave the same as invoking `f`.]] [[Effects:] [Constructs a new __packaged_task__ with `boost::forward(f)` stored as the associated task.]] -[[Throws:] [Any exceptions thrown by the copy (or move) constructor of `f`. `std::bad_alloc` if memory for the internal data -structures could not be allocated.]] +[[Throws:] [ + +- Any exceptions thrown by the copy (or move) constructor of `f`. + +- `std::bad_alloc` if memory for the internal data structures could not be allocated. +]] + +[[Notes:] [The R(*f)(ArgTypes...)) overload to allow passing a function without needing to use `&`.]] + +[[Remark:] [This constructor doesn't participate in overload resolution if decay::type is the same type as boost::packaged_task.]] -[[Notes:] [The R(*f)()) overload to allow passing a function without needing to use `&`.]] ] @@ -1212,7 +1417,7 @@ structures could not be allocated.]] [section:alloc_constructor Allocator Constructor] template - packaged_task(allocator_arg_t, Allocator a, R(*f)()); + packaged_task(allocator_arg_t, Allocator a, R(*f)(ArgTypes...)); template packaged_task(allocator_arg_t, Allocator a, F&& f); @@ -1227,7 +1432,7 @@ as invoking `f`.]] structures could not be allocated.]] [[Notes:] [Available only if BOOST_THREAD_FUTURE_USES_ALLOCATORS is defined.]] -[[Notes:] [The R(*f)()) overload to allow passing a function without needing to use `&`.]] +[[Notes:] [The R(*f)(ArgTypes...)) overload to allow passing a function without needing to use `&`.]] ] @@ -1311,13 +1516,40 @@ asynchronous result associated with this task are woken.]] [[Postconditions:] [All futures waiting on the asynchronous result are ['ready]]] -[[Throws:] [__task_moved__ if ownership of the task associated with `*this` has been moved to another instance of -__packaged_task__. __task_already_started__ if the task has already been invoked.]] +[[Throws:] [ + +- __task_moved__ if ownership of the task associated with `*this` has been moved to another instance of __packaged_task__. + +- __task_already_started__ if the task has already been invoked.]] ] [endsect] +[section:make_ready_at_thread_exit Member Function `make_ready_at_thread_exit()`] + + void make_ready_at_thread_exit(ArgTypes...); + +[variablelist + +[[Effects:] [Invoke the task associated with `*this` and store the result in the corresponding future. If the task returns normally, +the return value is stored as the asynchronous result, otherwise the exception thrown is stored. +In either case, this is done without making that state ready immediately. +Schedules the shared state to be made ready when the current thread exits, after all objects of thread storage +duration associated with the current thread have been destroyed.]] + +[[Throws:] [ + +- __task_moved__ if ownership of the task associated with `*this` has been moved to another instance of __packaged_task__. + +- __task_already_started__ if the task has already been invoked. +]] + +] + +[endsect] + + [section:reset Member Function `reset()`] void reset(); @@ -1371,17 +1603,28 @@ __packaged_task__.]] template __unique_future__::type()>::type> - async(F f); + async(F&& f); template __unique_future__::type()>::type> - async(launch policy, F f); + async(launch policy, F&& f); + template + __unique_future__::type(typename decay::type...)>::type> + async(F&& f, Args&&... args); + template + __unique_future__::type(typename decay::type...)>::type> + async(launch policy, F&& f, Args&&... args); + 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!] +[warning the variadic prototype is provided only on C++11 compilers supporting rvalue references, variadic templates, decltype and a standard library providing , and BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK is defined.] + +[heading Non-Variadic variant] + [variablelist [[Requires:] [ @@ -1414,7 +1657,7 @@ The further behavior of the second function depends on the policy argument as fo If the implementation chooses the `launch::async` policy, -- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined; +- a call to a non-timed waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined; - the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first. ]] @@ -1433,38 +1676,69 @@ If the implementation chooses the `launch::async` policy, ] -[/ +[heading Variadic variant] [variablelist -[[Requires:] [F and each Ti in Args shall satisfy the MoveConstructible requirements. INVOKE (DECAY_- COPY (boost::forward(f)), decay_copy (boost::forward(args))...) shall be a valid expression. +[[Requires:] [ +`F` and each `Ti` in `Args` shall satisfy the `MoveConstructible` requirements. + + invoke (decay_copy (boost::forward(f)), decay_copy (boost::forward(args))...) + +shall be a valid expression. ]] -[[Effects:] [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 and Args. The second function creates 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): -- if policy & launch::async is non-zero - calls INVOKE (decay_copy (boost::forward(f)), decay_copy (boost::forward(args))...) (20.8.2, 30.3.1.2) as if in a new thread of exe- cution represented by a thread object with the calls to decay_copy() being evaluated in the thread that called async. Any return value is stored as the result in the shared state. Any excep- tion propagated from the execution of INVOKE(decay_copy(boost::forward(f)), DECAY_- COPY (boost::forward(args))...) is stored as the exceptional result in the shared state. The thread object is stored in the shared state and affects the behavior of any asynchronous return objects that reference that state. -- if policy & launch::deferred is non-zero - Stores decay_copy (boost::forward(f)) and decay_copy (boost::forward(args))... in the shared state. These copies of f and args constitute a deferred function. Invocation of the deferred function evaluates INVOKE (boost::move(g), boost::move(xyz)) where g is the stored value of decay_copy (boost::forward(f)) and xyz is the stored copy of decay_copy (boost::forward(args)).... The shared state is not made ready until the function has completed. The first call to a non-timed waiting function (30.6.4) on an asynchronous return object referring to this shared state shall invoke the deferred func- tion in the thread that called the waiting function. Once evaluation of INVOKE (boost::move(g), boost::move(xyz)) begins, the function is no longer considered deferred. +[[Effects:] [ + +- 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` and `Args`. + +- The second function creates 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): + + - if `policy & launch::async` is non-zero - calls `invoke(decay_copy(forward(f)), decay_copy (forward(args))...)` + as if in a new thread of execution represented by a thread object with the calls to `decay_copy()` being evaluated in the thread that called `async`. + Any return value is stored as the result in the shared state. + Any exception propagated from the execution of `invoke(decay_copy(boost::forward(f)), decay_copy (boost::forward(args))...)` + is stored as the exceptional result in the shared state. The thread object is stored in the shared state and + affects the behavior of any asynchronous return objects that reference that state. + + - if `policy & launch::deferred` is non-zero - Stores `decay_copy(forward(f))` and `decay_copy(forward(args))...` in the shared state. + These copies of `f` and `args` constitute a deferred function. Invocation of the deferred function evaluates + `invoke(move(g), move(xyz))` where `g` is the stored value of `decay_copy(forward(f))` and `xyz` is the stored copy of `decay_copy(forward(args))...`. + 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 `invoke(move(g), move(xyz))` 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.]] -[[Returns:] [An object of type __unique_future__::type(typename de- cay::type...)>::type> that refers to the shared state created by this call to async.]] +[[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.]] + +[[Returns:] [An object of type `__unique_future__::type(typename decay::type...)>::type>` +that refers to the shared state created by this call to `async`.]] [[Synchronization:] [Regardless of the provided policy argument, -- the invocation of async synchronizes with (1.10) the invocation of f. (Note: This statement applies even when the corresponding future object is moved to another thread.); and -- the completion of the function f is sequenced before (1.10) the shared state is made ready. (Note: f might not be called at all, so its completion might never happen.) -If the implementation chooses the launch::async policy, -- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call shall block until the associated thread has completed, as if joined; -- the associated thread completion synchronizes with (1.10) the return from the first function that successfully detects the ready status of the shared state or with the return from the last function that releases the shared state, whichever happens first. +- the invocation of async synchronizes with the invocation of `f`. (Note: This statement applies even when the corresponding future object is moved to another thread.); and + +- the completion of the function `f` is sequenced before the shared state is made ready. (Note: f might not be called at all, so its completion might never happen.) +If the implementation chooses the `launch::async` policy, + +- a call to a waiting function on an asynchronous return object that shares the shared state created by this async call +shall block until the associated thread has completed, as if joined; + +- the associated thread completion synchronizes with the return from the first function that successfully detects the ready status of the shared state or +with the return from the last function that releases the shared state, whichever happens first. ]] -[[Throws:] [system_error if policy is launch::async and the implementation is unable to start a new thread. +[[Throws:] [`system_error` if policy is `launch::async` and the implementation is unable to start a new thread. ]] [[Error conditions:][ -- resource_unavailable_try_again - if policy is launch::async and the system is unable to start a new thread. +- `resource_unavailable_try_again` - if policy is `launch::async` and the system is unable to start a new thread. ]] [[Remarks:] [The first signature shall not participate in overload resolution if decay::type is boost::launch. @@ -1472,10 +1746,6 @@ If the implementation chooses the launch::async policy, ] -] - - - [endsect] @@ -1555,5 +1825,72 @@ __unique_future__ or __shared_future__.]] [endsect] +[section:make_future Non-member function `make_future()`] + + template + future::type> make_future(T&& value); // EXTENSION + future make_future(); // EXTENSION + + +[variablelist + +[[Effects:] [ +The value that is passed in to the function is moved to the shared state of the returned function if it is an rvalue. +Otherwise the value is copied to the shared state of the returned function. +.]] + +[[Returns:] [ + +- future, if function is given a value of type T + +- future, if the function is not given any inputs. + +]] + +[[Postcondition:] [ + +- Returned future, valid() == true + +- Returned future, is_ready() = true + +]] + +] + + +[endsect] +[section:make_shared_future Non-member function `make_shared_future()`] + + template + shared_future::type> make_shared_future(T&& value); // EXTENSION + shared_future make_shared_future(); // EXTENSION + +[variablelist + +[[Effects:] [ +The value that is passed in to the function is moved to the shared state of the returned function if it is an rvalue. +Otherwise the value is copied to the shared state of the returned function. +.]] + +[[Returns:] [ + +- shared_future, if function is given a value of type T + +- shared_future, if the function is not given any inputs. + +]] + +[[Postcondition:] [ + +- Returned shared_future, valid() == true + +- Returned shared_future, is_ready() = true + +]] + +] + +[endsect] + [endsect] diff --git a/doc/futures.qbk b/doc/futures.qbk index c42e7359..7a39c199 100755 --- a/doc/futures.qbk +++ b/doc/futures.qbk @@ -93,10 +93,13 @@ the result is ready, it is returned from __unique_future_get__ by rvalue-referen appropriate for the type. On the other hand, many instances of __shared_future__ may reference the same result. Instances can be freely copied and assigned, -and __shared_future_get__ returns a `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an +and __shared_future_get__ returns a non `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an instance of __unique_future__ into an instance of __shared_future__, thus transferring ownership of the associated asynchronous result, but not vice-versa. +`boost::async` is a simple way of running asynchronous tasks. A call to `boost::async` returns a __unique_future__ that will contain the result of the task. + + You can wait for futures either individually or with one of the __wait_for_any__ and __wait_for_all__ functions. [endsect] @@ -184,6 +187,280 @@ call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task t [endsect] +[section:at_thread_exit Handling Detached Threads and Thread Specific Variables] + +Detached threads pose a problem for objects with thread storage duration. +If we use a mechanism other than `thread::__join` to wait for a __thread to complete its work - such as waiting for a future to be ready - +then the destructors of thread specific variables will still be running after the waiting thread has resumed. +This section explain how the standard mechanism can be used to make such synchronization safe by ensuring that the +objects with thread storage duration are destroyed prior to the future being made ready. e.g. + + int find_the_answer(); // uses thread specific objects + void thread_func(boost::promise&& p) + { + p.set_value_at_thread_exit(find_the_answer()); + } + + int main() + { + boost::promise p; + boost::thread t(thread_func,boost::move(p)); + t.detach(); // we're going to wait on the future + std::cout< task,int param) + { + task.make_ready_at_thread_exit(param); // execute stored task + } // destroy thread specific and wake threads waiting on futures from task + +Other threads can wait on a future obtained from the task without having to worry about races due to the execution of +destructors of the thread specific objects from the task's thread. + + boost::condition_variable cv; + boost::mutex m; + complex_type the_data; + bool data_ready; + + void thread_func() + { + boost::unique_lock lk(m); + the_data=find_the_answer(); + data_ready=true; + boost::notify_all_at_thread_exit(cv,boost::move(lk)); + } // destroy thread specific objects, notify cv, unlock mutex + + void waiting_thread() + { + boost::unique_lock lk(m); + while(!data_ready) + { + cv.wait(lk); + } + process(the_data); + } + +The waiting thread is guaranteed that the thread specific objects used by `thread_func()` have been destroyed by the time +`process(the_data)` is called. If the lock on `m` is released and re-acquired after setting `data_ready` and before calling +`boost::notify_all_at_thread_exit()` then this does NOT hold, since the thread may return from the wait due to a +spurious wake-up. + +[endsect] + +[section:async Executing asynchronously] + +`boost::async` is a simple way of running asynchronous tasks to make use of the available hardware concurrency. +A call to `boost::async` returns a `boost::future` that will contain the result of the task. Depending on +the launch policy, the task is either run asynchronously on its own thread or synchronously on whichever thread +calls the `wait()` or `get()` member functions on that `future`. + +A launch policy of either boost::launch::async, which asks the runtime to create an asynchronous thread, +or boost::launch::deferred, which indicates you simply want to defer the function call until a later time (lazy evaluation). +This argument is optional - if you omit it your function will use the default policy. + +For example, consider computing the sum of a very large array. The first task is to not compute asynchronously when +the overhead would be significant. The second task is to split the work into two pieces, one executed by the host +thread and one executed asynchronously. + + + int parallel_sum(int* data, int size) + { + int sum = 0; + if ( size < 1000 ) + for ( int i = 0; i < size; ++i ) + sum += data[i]; + else { + auto handle = boost::async(parallel_sum, data+size/2, size-size/2); + sum += parallel_sum(data, size/2); + sum += handle.get(); + } + return sum; + } + + + +[endsect] + +[section:shared Shared Futures] + +`shared_future` is designed to be shared between threads, +that is to allow multiple concurrent get operations. + +[heading Multiple get] + +The second `get()` call in the following example future + + void bad_second_use( type arg ) { + + auto ftr = async( [=]{ return work( arg ); } ); + if ( cond1 ) + { + use1( ftr.get() ); + } else + { + use2( ftr.get() ); + } + use3( ftr.get() ); // second use is undefined + } + +Using a `shared_mutex` solves the issue + + void good_second_use( type arg ) { + + shared_future ftr = async( [=]{ return work( arg ); } ); + if ( cond1 ) + { + use1( ftr.get() ); + } else + { + use2( ftr.get() ); + } + use3( ftr.get() ); // second use is defined + } + +[heading share()] + +Namming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists. +Here `share()` could be used to simplify the code + + void better_second_use( type arg ) { + + auto ftr = async( [=]{ return work( arg ); } ).share(); + if ( cond1 ) + { + use1( ftr.get() ); + } else + { + use2( ftr.get() ); + } + use3( ftr.get() ); // second use is defined + } + +[heading Writting on get()] + +The user can either read or write the future avariable. + + void write_to_get( type arg ) { + + auto ftr = async( [=]{ return work( arg ); } ).share(); + if ( cond1 ) + { + use1( ftr.get() ); + } else + { + if ( cond2 ) + use2( ftr.get() ); + else + ftr.get() = something(); // assign to non-const reference. + } + use3( ftr.get() ); // second use is defined + } + +This works because the `shared_future<>::get()` function returns a non-const reference to the appropriate storage. +Of course the access to this storage must be ensured by the user. The library doesn't ensure the access to the internal storage is thread safe. + +There has been some work by the C++ standard committe on an `atomic_future` that behaves as an `atomic` variable, that is is thread_safe, +and a `shared_future` that can be shared between several threads, but there were not enough consensus and time to get it ready for C++11. + +[endsect] + +[section:make_future Making immediate futures easier] + +Some functions may know the value at the point of construction. In these cases the value is immediately available, +but needs to be returned as a future or shared_future. By using make_future (make_shared_future) a future (shared_future) +can be created which holds a pre-computed result in its shared state. + +Without these features it is non-trivial to create a future directly from a value. +First a promise must be created, then the promise is set, and lastly the future is retrieved from the promise. +This can now be done with one operation. + +[heading make_future / make_shared_future] + +This function creates a future for a given value. If no value is given then a future is returned. +This function is primarily useful in cases where sometimes, the return value is immediately available, but sometimes +it is not. The example below illustrates, that in an error path the value is known immediately, however in other paths +the function must return an eventual value represented as a future. + + + boost::future compute(int x) + { + if (x == 0) return boost::make_future(0); + if (x < 0) return boost::make_future(-1); + boost::future f1 = boost::async([]() { return x+1; }); + return f1; + } + +There are two variations of this function. The first takes a value of any type, and returns a future of that type. +The input value is passed to the shared state of the returned future. The second version takes no input and returns a future. +make_shared_future has the same functionality as make_future, except has a return type of shared_future. + + +[endsect] + +[section:then Associating future continuations] + +In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second +operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future. +With .then, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is +invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits +or wasting threads on polling, greatly improving the responsiveness and scalability of an application. + +future.then provides the ability to sequentially compose two futures by declaring one to be the continuation of another. +With .then the antecedent future is ready (has a value or exception stored in the shared state) before the continuation +starts as instructed by the lambda function. + +In the example below the future f2 is registered to be a continuation of future f1 using the .then member +function. This operation takes a lambda function which describes how f2 should proceed after f1 is ready. + + + #include + using namespace boost; + int main() + { + future f1 = async([]() { return 123; }); + future f2 = f1.then([](future f) { return f.get().to_string(); // here .get() won't block }); + } + +One key feature of this function is the ability to chain multiple asynchronous operations. In asynchronous programming, +it's common to define a sequence of operations, in which each continuation executes only when the previous one completes. +In some cases, the antecedent future produces a value that the continuation accepts as input. By using future.then, +creating a chain of continuations becomes straightforward and intuitive: + + myFuture.then(...).then(...).then(...). + +Some points to note are: + +* Each continuation will not begin until the preceding has completed. +* If an exception is thrown, the following continuation can handle it in a try-catch block + + +Input Parameters: + +* Lambda function2: One option which was considered was to follow JavaScript's approach and take two functions, one for +success and one for error handling. However this option is not viable in C++ as there is no single base type for +exceptions as there is in JavaScript. The lambda function takes a future as its input which carries the exception +through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations. +* Scheduler: Providing an overload to .then, to take a scheduler reference places great flexibility over the execution +of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful +asynchronous operations. The lifetime of the scheduler must outlive the continuation. +* Launch policy: if the additional flexibility that the scheduler provides is not required. + + +Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using +.then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning +a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A +shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future +to a shared_future when needed using future::share(). + + +[endsect] + + [include future_ref.qbk] [endsect] \ No newline at end of file diff --git a/doc/mutex_concepts.qbk b/doc/mutex_concepts.qbk index dbf41fb1..fd3206fb 100644 --- a/doc/mutex_concepts.qbk +++ b/doc/mutex_concepts.qbk @@ -20,8 +20,18 @@ do the various lock types. [section:basic_lockable `BasicLockable` Concept] + // #include + + namespace boost + { + + template + class BasicLockable; + } + + The __BasicLockable concept models exclusive ownership. -A type `L` meets the __BasicLockable requiremets if the following expressions are well-formed and have the specified semantics (`m` denotes a value of type `L`): +A type `L` meets the __BasicLockable requirements if the following expressions are well-formed and have the specified semantics (`m` denotes a value of type `L`): * `m.__lock();` * `m.__unlock();` @@ -38,7 +48,7 @@ Lock ownership acquired through a call to __lock_ref__ must be released through [[Return type:] [`void`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] [[Error Conditions:] [ @@ -59,22 +69,44 @@ Lock ownership acquired through a call to __lock_ref__ must be released through [variablelist -[[Precondition:] [The current thread owns `m`.]] +[[Requires:] [The current thread owns `m`.]] -[[Effects:] [Releases ownership by the current thread.]] +[[Effects:] [Releases a lock on `m` by the current thread.]] [[Return type:] [`void`.]] -[[Postcondition:] [The current thread no longer owns `m`.]] - [[Throws:] [Nothing.]] ] [endsect] +[section:is_basic_lockable `is_basic_lockable` trait] + + // #include + + namespace boost + { + namespace sync + { + template + class is_basic_lockable; + } + } + +Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of BasicLockable you could build. + [endsect] +[endsect] + [section:lockable `Lockable` Concept] + // #include + namespace boost + { + template + class Lockable; + } + A type `L` meets the __Lockable requirements if it meets the __BasicLockable requirements and the following expressions are well-formed and have the specified semantics (`m` denotes a value of type `L`): * `m.__try_lock()` @@ -98,10 +130,64 @@ Lock ownership acquired through a call to __try_lock_ref__ must be released thro ] [endsect] +[section:is_lockable `is_lockable` trait] + + // #include + namespace boost + { + namespace sync + { + template + class is_lockable; + } + } + +Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of Lockable you could build. + +[endsect] [endsect] +[section:recursive Recursive Lockable Concept] + +The user could require that the mutex passed to an algorithm is a recursive one. Whether a lockable is recursive or not can not be checked using template meta-programming. This is the motivation for the following trait. + + +[section:is_recursive_mutex_sur_parolle `is_recursive_mutex_sur_parolle` trait] + + // #include + + namespace boost + { + namespace sync + { + template + class is_recursive_mutex_sur_parolle: false_type; + template<> + class is_recursive_mutex_sur_parolle: true_type; + template<> + class is_recursive_mutex_sur_parolle: true_type; + } + } + +The trait `is_recursive_mutex_sur_parolle` is `false_type` by default and is specialized for the provide `recursive_mutex` and `timed_recursive_mutex`. + +It should be specialized by the user providing other model of recursive lockable. + +[endsect] + +[endsect] + + [section:timed_lockable `TimedLockable` Concept] + // #include + + namespace boost + { + template + class TimedLockable; + } + The __timed_lockable_concept__ refines the __lockable_concept__ to add support for timeouts when trying to acquire the lock. @@ -144,9 +230,14 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.] ] [endsect] -[heading Deprecated V3.0.0] +[warning +DEPRECATED since 3.00. The following expressions were required on version 2, but are now deprecated. + +Available only up to Boost 1.56. + +Use instead __try_lock_for, __try_lock_until. +] -The following expressions were required on version 2, but are now deprecated. [*Variables:] @@ -171,7 +262,7 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.] [[Postcondition:] [If the call returns `true`, the current thread owns `m`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -190,6 +281,15 @@ reached. If the specified time has already passed, behaves as __try_lock_ref__.] [section:shared_lockable `SharedLockable` Concept] + // #include + + namespace boost + { + template + class SharedLockable; + } + + The __shared_lockable_concept__ is a refinement of the __timed_lockable_concept__ that allows for ['shared ownership] as well as ['exclusive ownership]. This is the standard multiple-reader / single-write model: at most one thread can have @@ -223,7 +323,7 @@ Lock ownership acquired through a call to __lock_shared_ref__, __try_lock_shared [[Postcondition:] [The current thread has shared ownership of `m`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -238,7 +338,7 @@ Lock ownership acquired through a call to __lock_shared_ref__, __try_lock_shared [[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `m`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -255,7 +355,7 @@ specified duration is elapsed. If the specified duration is already elapsed, beh [[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `m`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -272,7 +372,7 @@ specified time is reached. If the specified time has already passed, behaves as [[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `m`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -292,9 +392,13 @@ ownership of `m`.]] ] [endsect] -[heading Deprecated V3] +[warning +DEPRECATED since 3.00. The following expressions were required on version 2, but are now deprecated. + +Available only up to Boost 1.56. -The following expressions were required on version 1, but are now deprecated. +Use instead __try_lock_shared_for, __try_lock_shared_until. +] [*Variables:] @@ -318,7 +422,7 @@ specified time is reached. If the specified time has already passed, behaves as [[Postcondition:] [If the call returns `true`, the current thread has shared ownership of `m`.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -329,6 +433,15 @@ ownership of `m`.]] [section:upgrade_lockable `UpgradeLockable` Concept] + // #include + + namespace boost + { + template + class UpgradeLockable; + } + + The __upgrade_lockable_concept__ is a refinement of the __shared_lockable_concept__ that allows for ['upgradable ownership] as well as ['shared ownership] and ['exclusive ownership]. This is an extension to the multiple-reader / single-write model provided by the __shared_lockable_concept__: a single thread may have ['upgradable ownership] at the same time as others have ['shared @@ -395,7 +508,7 @@ call to the unlock function corresponding to the new level of ownership. [[Synchronization:] [Prior `__unlock_upgrade()` operations on the same object synchronize with this operation.]] -[[Throws:] [__thread_resource_error__ if an error occurs.]] +[[Throws:] [__lock_error__ if an error occurs.]] ] [endsect] @@ -789,9 +902,10 @@ blocking.]] [endsect] -[section:locks Lock Types] +[section:lock_option Lock Options] - //#include + // #include + // #include namespace boost { @@ -801,28 +915,11 @@ blocking.]] constexpr defer_lock_t defer_lock; constexpr try_to_lock_t try_to_lock; constexpr adopt_lock_t adopt_lock; - - template - class lock_guard - template - class unique_lock; - template - void swap(unique_lock & lhs, unique_lock & rhs); - template - class shared_lock; - template - void swap(shared_lock& lhs,shared_lock& rhs); - template - class upgrade_lock; - template - void swap(upgrade_lock & lhs, upgrade_lock & rhs); - template - class upgrade_to_unique_lock; - } [section:lock_tags Lock option tags] #include + #include struct defer_lock_t {}; struct try_to_lock_t {}; @@ -839,9 +936,28 @@ These tags are used in scoped locks constructors to specify a specific behavior. [endsect] +[endsect] + +[section:lock_guard Lock Guard] + + // #include + // #include + + namespace boost + { + + template + class lock_guard + template + lock_guard make_lock_guard(Lockable& mtx); // EXTENSION + template + lock_guard make_lock_guard(Lockable& mtx, adopt_lock_t); // EXTENSION + } + [section:lock_guard Class template `lock_guard`] - //#include + // #include + // #include template class lock_guard @@ -858,7 +974,7 @@ acquires ownership of the implementation of the __lockable_concept__ supplied as the constructor parameter. On destruction, the ownership is released. This provides simple RAII-style locking of a __lockable_concept_type__ object, to facilitate exception-safe locking and unlocking. In addition, the [link -thread.synchronization.locks.lock_guard.constructor_adopt `lock_guard(Lockable & +thread.synchronization.lock_guard.lock_guard.constructor_adopt `lock_guard(Lockable & m,boost::adopt_lock_t)` constructor] allows the __lock_guard__ object to take ownership of a lock already held by the current thread. @@ -904,10 +1020,141 @@ object passed to the constructor.]] [endsect] [endsect] + +[section:make_lock_guard Non Member Function `make_lock_guard`] + + template + lock_guard make_lock_guard(Lockable& m); // EXTENSION + + +[variablelist + +[[Returns:] [a lock_guard as if initialized with `{m}`.]] + +[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]] + +] + + +[endsect] +[section:make_lock_guard_adopt Non Member Function `make_lock_guard`] + + template + lock_guard make_lock_guard(Lockable& m, adopt_lock_t); // EXTENSION + + +[variablelist + +[[Returns:] [a lock_guard as if initialized with `{m, adopt_lock}`.]] + +[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]] + +] + + +[endsect] +[endsect] + +[section:lock_concepts Lock Concepts] +[section:StrictLock StrictLock] + + // #include + + namespace boost + { + + template + class StrictLock; + } + + +A StrictLock is a lock that ensures that the associated mutex is locked during the lifetime if the lock. + +A type `L` meets the StrictLock requirements if the following expressions are well-formed and have the specified semantics + +* `L::mutex_type` +* `is_strict_lock` +* `cl.owns_lock(m);` + +and BasicLockable + +where + +* `cl` denotes a value of type `L const&`, +* `m` denotes a value of type `L::mutex_type const*`, + +[section: mutex_type `L::mutex_type`] + +The type L::mutex_type denotes the mutex that is locked by this lock. + +[endsect] [/ mutex_type] + +[section:is_strict_lock_sur_parolle `is_strict_lock_sur_parolle`] + +As the semantic "ensures that the associated mutex is locked during the lifetime if the lock. " can not be described by syntactic requirements a `is_strict_lock_sur_parolle` trait must be specialized by the user defining the lock so that the following assertion is true: + + is_strict_lock_sur_parolle::value == true + +[endsect] [/ is_strict_lock_sur_parolle] + +[section:mutex `cl.mutex();`] + +[variablelist + +[[Return Type:] [`L::mutex_type`]] +[[Returns:] [A pointer to the `L::mutex_type` object that this lock `l` is locking]] + +[[Throws:] [Nothing.]] + +] + + +[endsect] [/ mutex] + +[section Models] + +The following classes are models of `StrictLock`: + +* strict_lock: ensured by construction, +* nested_strict_lock: ensured by construction, +* __lock_guard__: "sur parolle" as the user could use adopt_lock_t constructor overload without having locked the mutex. + +[endsect] [/ Models] + +[endsect] [/ Strict Lock] + +[endsect] [/ Lock Concepts] + +[section:locks Lock Types] + + // #include + // #include + + namespace boost + { + + template + class unique_lock; + template + void swap(unique_lock & lhs, unique_lock & rhs); + template + class shared_lock; + template + void swap(shared_lock& lhs,shared_lock& rhs); + template + class upgrade_lock; + template + void swap(upgrade_lock & lhs, upgrade_lock & rhs); + template + class upgrade_to_unique_lock; + } + + [section:unique_lock Class template `unique_lock`] - //#include + // #include + // #include template class unique_lock @@ -961,7 +1208,7 @@ object passed to the constructor.]] Lockable* mutex() const noexcept; - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO + #if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO unique_lock(Lockable& m_,system_time const& target_time); template bool timed_lock(TimeDuration const& relative_time); @@ -1271,7 +1518,8 @@ __owns_lock_ref__ returns `false`.]] [section:shared_lock Class template `shared_lock`] - //#include + // #include + // #include template class shared_lock @@ -1320,7 +1568,7 @@ __owns_lock_ref__ returns `false`.]] bool owns_lock() const; mutex_type mutex() const; - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO + #if defined BOOST_THREAD_USE_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO shared_lock(Lockable& m_,system_time const& target_time); bool timed_lock(boost::system_time const& target_time); #endif @@ -1512,7 +1760,8 @@ __owns_lock_shared_ref__ returns `false`.]] [section:upgrade_lock Class template `upgrade_lock`] - //#include + // #include + // #include template class upgrade_lock @@ -1593,7 +1842,8 @@ state (including the destructor) must be called by the same thread that acquired [section:upgrade_to_unique_lock Class template `upgrade_to_unique_lock`] - #include + // #include + // #include template class upgrade_to_unique_lock @@ -1696,6 +1946,69 @@ __reverse_mutex reverse the operations of a __BasicLockable, that unlocks the lo [section:other_locks Other Lock Types] +[section:strict_lock Strict Lock] + + // #include + // #include + + namespace boost + { + + template + class strict_lock; + } + +[section:strict_lock Class template `strict_lock`] + + // #include + // #include + + template + class strict_lock + { + public: + typedef BasicLockable mutex_type; + explicit strict_lock(mutex_type& m_); + ~strict_lock(); + + mutex_type* mutex() const; + }; + +__strict_lock is a model of __StrictLock. + +__strict_lock is the simplest __StrictLock: on construction it acquires ownership of the implementation of the __BasicLockable concept supplied as the constructor parameter. On destruction, the ownership is released. This provides simple RAII-style locking of a __BasicLockable object, to facilitate exception-safe locking and unlocking. + +[heading See also __lock_guard__] + +[section:constructor `strict_lock(Lockable & m)`] + +[variablelist + +[[Effects:] [Stores a reference to `m`. Invokes [lock_ref_link `m.lock()`].]] + +[[Throws:] [Any exception thrown by the call to [lock_ref_link `m.lock()`].]] + +] + +[endsect] + +[section:destructor `~strict_lock()`] + +[variablelist + +[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__ +object passed to the constructor.]] + +[[Throws:] [Nothing.]] + +] + +[endsect] + +[endsect] + +[endsect] + [section:shared_lock_guard Class template `shared_lock_guard`] @@ -1816,7 +2129,7 @@ An instance of __reverse_lock doesn't ['own] the lock never. [endsect] -[endsect] +[endsect] [/ reverse_lock<>] [endsect] @@ -1826,6 +2139,7 @@ An instance of __reverse_lock doesn't ['own] the lock never. [section:lock_multiple Non-member function `lock(Lockable1,Lockable2,...)`] // #include + // #include namespace boost { diff --git a/doc/mutexes.qbk b/doc/mutexes.qbk index d42892c9..0dfd9747 100644 --- a/doc/mutexes.qbk +++ b/doc/mutexes.qbk @@ -89,7 +89,7 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility typedef unspecified-type scoped_try_lock; typedef scoped_timed_lock scoped_lock; - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO + #if defined BOOST_THREAD_PROVIDES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO bool timed_lock(system_time const & abs_time); template bool timed_lock(TimeDuration const & relative_time); @@ -203,7 +203,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back typedef unspecified-type scoped_try_lock; typedef scoped_lock scoped_timed_lock; - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO + #if defined BOOST_THREAD_PROVIDES_DATE_TIME || defined BOOST_THREAD_DONT_USE_CHRONO bool timed_lock(system_time const & abs_time); template bool timed_lock(TimeDuration const & relative_time); diff --git a/doc/scoped_thread.qbk b/doc/scoped_thread.qbk new file mode 100644 index 00000000..c35cf84b --- /dev/null +++ b/doc/scoped_thread.qbk @@ -0,0 +1,473 @@ +[/ + (C) Copyright 2008-9 Anthony Williams. + (C) Copyright 12 Vicente J. Botet Escriba. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt). +] + +[section:ScopedThreads Scoped Threads] + +[heading Synopsis] + + //#include + + struct detach; + struct join_if_joinable; + struct interrupt_and_join_if_joinable; + template + class strict_scoped_thread; + template + class scoped_thread; + void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept; + +[section:motovation Motivation] +Based on the scoped_thread class defined in C++ Concurrency in Action Boost.Thread defines a thread wrapper class that instead of calling terminate if the thread is joinable on destruction, call a specific action given as template parameter. + +While the scoped_thread class defined in C++ Concurrency in Action is closer to strict_scoped_thread class that doesn't allows any change in the wrapped thread, Boost.Thread provides a class scoped_thread that provides the same non-deprecated interface than __thread. + +[endsect] + +[section:tutorial Tutorial] + +Scoped Threads are wrappers around a thread that allows the user to state what to do at destruction time. One of the common uses is to join the thread at destruction time so this is the default behavior. This is the single difference respect to a thread. While thread call std::terminate() on the destructor is the thread is joinable, strict_scoped_thread<> or scoped_thread<> join the thread if joinable. + +The difference between strict_scoped_thread and scoped_thread is that the strict_scoped_thread hides completely the owned thread and so the user can do nothing with the owned thread other than the specific action given as parameter, while scoped_thread provide the same interface than __thread and forwards all the operations. + + boost::strict_scoped_thread<> t1((boost::thread(F))); + boost::strict_scoped_thread<> t2((boost::thread(F))); + t2.interrupt(); + +[endsect] + +[section:thread_functors Free Thread Functors] + + //#include + + struct detach; + struct join_if_joinable; + struct interrupt_and_join_if_joinable; + + +[section:detach Functor `detach`] + + struct detach + { + void operator()(thread& t) + { + t.detach(); + } + }; +[endsect] +[section:join_if_joinable Functor `join_if_joinable`] + + struct join_if_joinable + { + void operator()(thread& t) + { + if (t.joinable()) + { + t.join(); + } + } + }; + +[endsect] + +[section:interrupt_and_join_if_joinable Functor `interrupt_and_join_if_joinable`] + + struct interrupt_and_join_if_joinable + { + void operator()(thread& t) + { + t.interrupt(); + if (t.joinable()) + { + t.join(); + } + } + }; +[endsect] + +[endsect] + +[section:strict_scoped_thread Class `strict_scoped_thread`] + + // #include + + template + class strict_scoped_thread + { + thread t_; // for exposition purposes only + public: + + strict_scoped_thread(strict_scoped_thread const&) = delete; + strict_scoped_thread& operator=(strict_scoped_thread const&) = delete; + + explicit strict_scoped_thread(thread&& t) noexcept; + + ~strict_scoped_thread(); + + }; + + +RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. + +CallableThread: A callable void(thread&) . + +The default is a join_if_joinable. + + +thread std/boost::thread destructor terminates the program if the thread is not joinable. +This wrapper can be used to join the thread before destroying it seems a natural need. + +[heading Example] + + boost::strict_scoped_thread<> t((boost::thread(F))); + +[section:default_constructor Default Constructor] + + explicit strict_scoped_thread(thread&& t) noexcept; + +[variablelist + +[[Effects:] [move the thread to own @c t]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:destructor Destructor] + + ~strict_scoped_thread(); + +[variablelist + +[[Effects:] [Equivalent to `CallableThread()(t_)`. ]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[endsect] + +[section:scoped_thread Class `scoped_thread`] + + #include + + class scoped_thread + { + public: + scoped_thread() noexcept; + scoped_thread(const scoped_thread&) = delete; + scoped_thread& operator=(const scoped_thread&) = delete; + + explicit scoped_thread(thread&& th); + + ~scoped_thread(); + + // move support + scoped_thread(scoped_thread && x) noexcept; + scoped_thread& operator=(scoped_thread && x) noexcept; + + void swap(scoped_thread& x) noexcept; + + typedef thread::id id; + + id get_id() const noexcept; + + bool joinable() const noexcept; + void join(); + template + bool try_join_for(const chrono::duration& rel_time); + template + bool try_join_until(const chrono::time_point& t); + + void detach(); + + static unsigned hardware_concurrency() noexcept; + + typedef thread::native_handle_type native_handle_type; + native_handle_type native_handle(); + + void interrupt(); + bool interruption_requested() const noexcept; + + + #if defined BOOST_THREAD_USES_DATETIME + bool timed_join(const system_time& wait_until); // DEPRECATED + template + bool timed_join(TimeDuration const& rel_time); // DEPRECATED + static void sleep(const system_time& xt);// DEPRECATED + #endif + + #if defined BOOST_THREAD_PROVIDES_THREAD_EQ + bool operator==(const scoped_thread& other) const; // DEPRECATED + bool operator!=(const scoped_thread& other) const; // DEPRECATED + + #endif + static void yield() noexcept; // DEPRECATED + + }; + + void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept; + + +RAI __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. + +CallableThread: A callable void(thread&). +The default is join_if_joinable. + +thread std::thread destructor terminates the program if the thread is not joinable. +Having a wrapper that can join the thread before destroying it seems a natural need. + +Remark: scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. + +Anyway scoped_thread can be used in most of the contexts a @c thread could be used as it has the +same non-deprecated interface with the exception of the construction. + +[heading Example] + + boost::scoped_thread<> t((boost::thread(F))); + t.interrupt(); + + +[section:default_constructor Default Constructor] + + scoped_thread() noexcept; + +[variablelist + +[[Effects:] [Constructs a scoped_thread instance that wraps to __not_a_thread__.]] + +[[Postconditions:] [`this->get_id()==thread::id()`]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:move_constructor Move Constructor] + + scoped_thread(scoped_thread&& other) noexcept; + +[variablelist + +[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if any) to the newly constructed scoped_thread instance.]] + +[[Postconditions:] [`other.get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the construction]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:move_assignment Move assignment operator] + + scoped_thread& operator=(scoped_thread&& other) noexcept; + +[variablelist + +[[Effects:] [Transfers ownership of the scoped_thread managed by `other` (if +any) to `*this`. + +_ if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If there was a scoped_thread previously associated with `*this` then that scoped_thread is detached, DEPRECATED + +- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the scoped_thread is joinable calls to std::terminate. +]] + +[[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + +[section:thread_constructor Move Constructor from a __thread] + + scoped_thread(thread&& t); + +[variablelist + +[[Effects:] [move the thread to own @c t.]] + +[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]] + +[[Throws:] [Nothing]] + +] + +[endsect] + + +[section:destructor Destructor] + + ~scoped_thread(); + +[variablelist + +[[Effects:] [Equivalent to `CallableThread()(t_)`. ]] + +[[Throws:] [Nothing]] + +] + +[endsect] + + +[section:joinable Member function `joinable()`] + + bool joinable() const noexcept; + +[variablelist + +[[Returns:] [Equivalent to return t_.joinable().]] + +[[Throws:] [Nothing]] + +] + + +[endsect] + +[section:join Member function `join()`] + + void join(); + +[variablelist + +[[Effects:] [Equivalent to t_.join().]] + +]] + +] + +[endsect] + +[section:try_join_for Member function `try_join_for()`] + + template + bool try_join_for(const chrono::duration& rel_time); + +[variablelist + +[[Effects:] [Equivalent to return `t_.try_join_for(rel_time)`.]] + +] + +[endsect] + +[section:try_join_until Member function `try_join_until()`] + + template + bool try_join_until(const chrono::time_point& abs_time); + +[variablelist + +[[Effects:] [Equivalent to return `t_.try_join_until(abs_time)`.]] + +] + +[endsect] + + + +[section:detach Member function `detach()`] + + void detach(); + +[variablelist + +[[Effects:] [Equivalent to `t_.detach()`.]] + +] + +[endsect] + + +[section:get_id Member function `get_id()`] + + thread::id get_id() const noexcept; + +[variablelist + +[[Effects:] [Equivalent to return `t_.get_id()`.]] + +] + +[endsect] + +[section:interrupt Member function `interrupt()`] + + void interrupt(); + +[variablelist + +[[Effects:] [Equivalent to `t_.interrupt()`.]] + +] + + +[endsect] + +[section:hardware_concurrency Static member function `hardware_concurrency()`] + + unsigned hardware_concurrency() noexecpt; + +[variablelist + +[[Effects:] [Equivalent to return `thread::hardware_concurrency()`.]] + +] + +[endsect] + +[section:nativehandle Member function `native_handle()`] + + typedef thread::native_handle_type native_handle_type; + native_handle_type native_handle(); + +[variablelist + +[[Effects:] [Equivalent to return `t_.native_handle()`.]] + +] + +[endsect] + +[section:swap Member function `swap()`] + + void swap(scoped_thread& other) noexcept; + +[variablelist + +[[Effects:] [Equivalent `t_.swap(other.t_)`.]] + +] + +[endsect] + + + +[endsect] +[section:non_member_swap Non-member function `swap(scoped_thread&,scoped_thread&)`] + + #include + + void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept; + +[variablelist + +[[Effects:] [`lhs.swap(rhs)`.]] + +] + +[endsect] +[endsect] diff --git a/doc/shared_mutex_ref.qbk b/doc/shared_mutex_ref.qbk index c7a2ee46..adcda6cc 100644 --- a/doc/shared_mutex_ref.qbk +++ b/doc/shared_mutex_ref.qbk @@ -142,3 +142,87 @@ Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`, [endsect] + +[section:null_mutex Class `null_mutex`] + + #include + + class null_mutex + { + public: + null_mutex(null_mutex const&) = delete; + null_mutex& operator=(null_mutex const&) = delete; + + null_mutex(); + ~null_mutex(); + + void lock_shared(); + bool try_lock_shared(); + #ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_shared_for(const chrono::duration& rel_time); + template + bool try_lock_shared_until(const chrono::time_point& abs_time); + #endif + void unlock_shared(); + + void lock(); + bool try_lock(); + #ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time); + template + bool try_lock_until(const chrono::time_point& abs_time); + #endif + void unlock(); + + void lock_upgrade(); + #ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_upgrade_for(const chrono::duration& rel_time); + template + bool try_lock_upgrade_until(const chrono::time_point& abs_time); + #endif + void unlock_upgrade(); + + // Shared <-> Exclusive + + bool try_unlock_shared_and_lock(); + #ifdef BOOST_THREAD_USES_CHRONO + template + bool try_unlock_shared_and_lock_for(const chrono::duration& rel_time); + template + bool try_unlock_shared_and_lock_until(const chrono::time_point& abs_time); + #endif + void unlock_and_lock_shared(); + + // Shared <-> Upgrade + + bool try_unlock_shared_and_lock_upgrade(); + #ifdef BOOST_THREAD_USES_CHRONO + template + bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration& rel_time); + template + bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point& abs_time); + #endif + void unlock_upgrade_and_lock_shared(); + + // Upgrade <-> Exclusive + + void unlock_upgrade_and_lock(); + bool try_unlock_upgrade_and_lock(); + #ifdef BOOST_THREAD_USES_CHRONO + template + bool try_unlock_upgrade_and_lock_for(const chrono::duration& rel_time); + template + bool try_unlock_upgrade_and_lock_until(const chrono::time_point& abs_time); + #endif + void unlock_and_lock_upgrade(); + }; + +The class `boost::null_mutex` provides a no-op implementation of a multiple-reader / single-writer mutex. It is a model of the +__UpgradeLockable concept. + + +[endsect] + diff --git a/doc/sync_tutorial.qbk b/doc/sync_tutorial.qbk index 70d61d77..984c6ccd 100644 --- a/doc/sync_tutorial.qbk +++ b/doc/sync_tutorial.qbk @@ -11,4 +11,29 @@ [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2406.html Mutex, Lock, Condition Variable Rationale] adds rationale for the design decisions made for mutexes, locks and condition variables. -[endsect] +[section:locks Locks] + +In addition to the C++11 standard locks, Boost.Thread provides other locks and some utilities that help the user to make their code thread-safe. + +In particular, the library provides some lock factories. + + template + auto with_lock_guard(Lockable& m, Function f) -> decltype(fn()) + { + auto&& _ = boost::make_lock_guard(f); + f(); + } + + +that can be used as + + int i = with_lock_guard(mtx, {}() -> bool + { + // access the protected state + return true; + }); + + +[endsect] [/ Locks] + +[endsect] [/ Tutorial] diff --git a/doc/thread.qbk b/doc/thread.qbk index 85dba86d..4b21fbb3 100644 --- a/doc/thread.qbk +++ b/doc/thread.qbk @@ -8,7 +8,7 @@ [library Thread [quickbook 1.5] - [version 3.1.0] + [version 4.0.0] [authors [Williams, Anthony] [Botet Escriba, Vicente J.]] [copyright 2007-11 Anthony Williams] [copyright 2011-12 Vicente J. Botet Escriba] @@ -26,9 +26,9 @@ [def __lockable_concept_type__ [lockable_concept_link `Lockable`]] [def __BasicLockable [link thread.synchronization.mutex_concepts.basic_lockable `BasicLockable`]] [def __Lockable [link thread.synchronization.mutex_concepts.lockable `Lockable`]] -[def __TimedLockable [link thread.synchronization.mutex_concepts.timed_lockable `TimedLockable `]] -[def __SharedLockable [link thread.synchronization.mutex_concepts.shared_lockable `SharedLockable `]] -[def __UpgradeLockable [link thread.synchronization.mutex_concepts.upgrade_lockable `UpgradeLockable `]] +[def __TimedLockable [link thread.synchronization.mutex_concepts.timed_lockable `TimedLockable`]] +[def __SharedLockable [link thread.synchronization.mutex_concepts.shared_lockable `SharedLockable`]] +[def __UpgradeLockable [link thread.synchronization.mutex_concepts.upgrade_lockable `UpgradeLockable`]] [template timed_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable [link_text]]] [def __timed_lockable_concept__ [timed_lockable_concept_link `TimedLockable` concept]] @@ -155,9 +155,12 @@ [def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]] [def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]] + +[def __StrictLock [link thread.synchronization.lock_concepts.StrictLock `StrictLock`]] + [template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]] -[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]] +[def __lock_guard__ [link thread.synchronization.lock_guard.lock_guard `boost::lock_guard`]] [def __unique_lock__ [unique_lock_link `boost::unique_lock`]] [def __unique_lock [unique_lock_link `boost::unique_lock`]] [def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]] @@ -167,6 +170,8 @@ [def __shared_lock_guard [link thread.synchronization.other_locks.shared_lock_guard `shared_lock_guard`]] [def __shared_lock_guard_constructor_adopt [link thread.synchronization.other_locks.shared_lock_guard `shared_lock_guard`]] +[def __strict_lock [link thread.synchronization.other_locks.strict_lock `strict_lock`]] + [def __thread__ [link thread.thread_management.thread `boost::thread`]] [def __thread [link thread.thread_management.thread `thread`]] @@ -177,7 +182,6 @@ [def __try_join_for [link thread.thread_management.thread.try_join_for `try_join_for`]] [def __try_join_until [link thread.thread_management.thread.try_join_until `try_join_until`]] - [template timed_join_link[link_text] [link thread.thread_management.thread.timed_join [link_text]]] [def __timed_join__ [timed_join_link `timed_join()`]] [def __detach__ [link thread.thread_management.thread.detach `detach()`]] @@ -223,6 +227,7 @@ [include changes.qbk] [include thread_ref.qbk] +[include scoped_thread.qbk] [section:synchronization Synchronization] [include sync_tutorial.qbk] diff --git a/doc/thread_ref.qbk b/doc/thread_ref.qbk index 491385e8..7458448c 100644 --- a/doc/thread_ref.qbk +++ b/doc/thread_ref.qbk @@ -21,7 +21,7 @@ { thread::id get_id() noexcept; template - void yield() noexcept; + void yield() noexcept; // DEPRECATED template void sleep_until(const chrono::time_point& abs_time); template @@ -36,9 +36,10 @@ class disable_interruption; // EXTENSION class restore_interruption; // EXTENSION - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - void sleep(TimeDuration const& rel_time); - void sleep(system_time const& abs_time); + #if defined BOOST_THREAD_USES_DATETIME + template + void sleep(TimeDuration const& rel_time); // DEPRECATED + void sleep(system_time const& abs_time); // DEPRECATED #endif } class thread_group; // EXTENSION @@ -200,18 +201,81 @@ __thread_interrupted__, `std::terminate()` is called. [endsect] -[section:join Joining and detaching] +[section:detac Detaching thread] + +A thread can be detached by explicitly invoking the __detach__ member function on the __thread__ +object. In this case, the __thread__ object ceases to represent the now-detached thread, and instead represents __not_a_thread__. + + int main() + { + boost::thread t(my_func); + t.detach(); + } + +[endsect] + +[section:join Joining a thread] + +In order to wait for a thread of execution to finish, the __join__, __join_for or __join_until (__timed_join__ deprecated) member functions of the __thread__ object must be +used. __join__ will block the calling thread until the thread represented by the __thread__ object has completed. + + int main() + { + boost::thread t(my_func); + t.join(); + } + + +If the thread of +execution represented by the __thread__ object has already completed, or the __thread__ object represents __not_a_thread__, then __join__ +returns immediately. + + int main() + { + boost::thread t; + t.join(); // do nothing + } + +Timed based join are similar, except that a call to __join_for or __join_until will also return if the thread being waited for +does not complete when the specified time has elapsed or reached respectively. + + int main() + { + boost::thread t; + if ( t.join_for(boost::chrono::milliseconds(500)) ) + // do something else + t.join(); // join anyway + } + +[endsect] + +[section:destructor1 Destructor V1] When the __thread__ object that represents a thread of execution is destroyed the thread becomes ['detached]. Once a thread is detached, it will continue executing until the invocation of the function or callable object supplied on construction has completed, or the program is terminated. A thread can also be detached by explicitly invoking the __detach__ member function on the __thread__ object. In this case, the __thread__ object ceases to represent the now-detached thread, and instead represents __not_a_thread__. -In order to wait for a thread of execution to finish, the __join__ or __timed_join__ member functions of the __thread__ object must be -used. __join__ will block the calling thread until the thread represented by the __thread__ object has completed. If the thread of -execution represented by the __thread__ object has already completed, or the __thread__ object represents __not_a_thread__, then __join__ -returns immediately. __timed_join__ is similar, except that a call to __timed_join__ will also return if the thread being waited for -does not complete when the specified time has elapsed. +[endsect] + +[section:destructor2 Destructor V2] + +When the __thread__ object that represents a thread of execution is destroyed the program terminates if the thread is __joinable__. + + int main() + { + boost::thread t(my_func); + } // calls std::terminate() + +You can use a thread_joiner to ensure that the thread has been joined at the thread destructor. + + + int main() + { + boost::thread t(my_func); + boost::thread_joiner g(t); + // do someting else + } // here the thread_joiner destructor will join the thread before it is destroyed. [endsect] @@ -359,6 +423,8 @@ This behavior is incompatible with the current Boost.Thread design, so the use o class thread { public: + class attributes; // EXTENSION + thread() noexcept; thread(const thread&) = delete; thread& operator=(const thread&) = delete; @@ -374,15 +440,15 @@ This behavior is incompatible with the current Boost.Thread design, so the use o template thread(F f,A1 a1,A2 a2,...); - // template - // explicit thread(F&& f, Args&&... args); // NOT YET IMPLEMENTED + template + explicit thread(F&& f, Args&&... args); template explicit thread(attributes& attrs, F f); // EXTENSION template thread(attributes& attrs, F &&f); // EXTENSION - // template - // explicit thread(attributes& attrs, F&& f, Args&&... args); // NOT YET IMPLEMENTED + template + explicit thread(attributes& attrs, F&& f, Args&&... args); // move support thread(thread && x) noexcept; @@ -391,7 +457,6 @@ This behavior is incompatible with the current Boost.Thread design, so the use o void swap(thread& x) noexcept; class id; - class attributes; // EXTENSION id get_id() const noexcept; @@ -413,19 +478,19 @@ This behavior is incompatible with the current Boost.Thread design, so the use o bool interruption_requested() const noexcept; // EXTENSION - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO - bool timed_join(const system_time& wait_until); + #if defined BOOST_THREAD_USES_DATETIME + bool timed_join(const system_time& wait_until); // DEPRECATED template - bool timed_join(TimeDuration const& rel_time); + bool timed_join(TimeDuration const& rel_time); // DEPRECATED + static void sleep(const system_time& xt);// DEPRECATED #endif - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 - bool operator==(const thread& other) const; - bool operator!=(const thread& other) const; + #if defined BOOST_THREAD_PROVIDES_THREAD_EQ + bool operator==(const thread& other) const; // DEPRECATED + bool operator!=(const thread& other) const; // DEPRECATED - static void yield(); - static void sleep(const system_time& xt); #endif + static void yield() noexcept; // DEPRECATED }; @@ -467,11 +532,25 @@ This behavior is incompatible with the current Boost.Thread design, so the use o thread& operator=(thread&& other) noexcept; + +[warning +DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE behavior. + +Available only up to Boost 1.56. + +Join the thread before moving. +] + + [variablelist [[Effects:] [Transfers ownership of the thread managed by `other` (if -any) to `*this`. Version 2: If there was a thread previously associated with -`*this` then that thread is detached, Version 3: If the thread is joinable calls to std::terminate.]] +any) to `*this`. + +_ if defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If there was a thread previously associated with `*this` then that thread is detached, DEPRECATED + +- if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate. +]] [[Postconditions:] [`other->get_id()==thread::id()` and `get_id()` returns the value of `other.get_id()` prior to the assignment.]] @@ -479,6 +558,7 @@ any) to `*this`. Version 2: If there was a thread previously associated with ] + [endsect] [section:callable_constructor Thread Constructor] @@ -626,34 +706,29 @@ are copied into internal storage for access by the new thread.]]] ~thread(); -[variablelist - -[[Effects:] [Version 2: If `*this` has an associated thread of execution, calls __detach__, Version 3: If the thread is joinable calls to std::terminate. Destroys `*this`.]] - -[[Throws:] [Nothing.]] +[warning +DEPRECATED since 3.0.0: BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE behavior. + +Available only up to Boost 1.56. +Join the thread before destroying or use a scoped thread. ] -[endsect] - -[/ -[section:v2_destructor V3 Thread Destructor] - - ~thread(); - [variablelist -[[Effects:] [If `*this` has an associated thread of execution, calls terminate. Destroys `*this`.]] +[[Effects:] [ +- if defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If `*this` has an associated thread of execution, calls __detach__, DEPRECATED + +- BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE: If the thread is joinable calls to std::terminate. Destroys `*this`.]] + +[[Throws:] [Nothing.]] [[Note:] [Either implicitly detaching or joining a `joinable()` thread in its destructor could result in difficult to debug correctness (for `detach`) or performance (for `join`) bugs encountered only when an exception is raised. Thus the programmer must ensure that the destructor is never executed while the thread is still joinable.]] - -[[Throws:] [Nothing.]] - ] [endsect] -] + [section:joinable Member function `joinable()`] @@ -686,9 +761,9 @@ are copied into internal storage for access by the new thread.]]] [[Error Conditions:] [ -[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id(). +[*resource_deadlock_would_occur]: if deadlock is detected or `this->get_id() == boost::this_thread::get_id()` and `BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED` is defined.. -[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. +[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED` is defined. [/ @@ -704,13 +779,21 @@ are copied into internal storage for access by the new thread.]]] [endsect] -[section:timed_join Member function `timed_join()`] +[section:timed_join Member function `timed_join()` DEPRECATED] bool timed_join(const system_time& wait_until); template bool timed_join(TimeDuration const& rel_time); +[warning +DEPRECATED since 3.00. + +Available only up to Boost 1.56. + +Use instead __try_join_for, __try_join_until. +] + [variablelist [[Preconditions:] [the thread is joinable.]] @@ -731,7 +814,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_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined. [/ @@ -771,7 +854,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_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined. [/ @@ -811,7 +894,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_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined. [/ @@ -847,7 +930,7 @@ unchanged.]] [*no_such_process]: if the thread is not valid. -[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRROW_IF_PRECONDITION_NOT_SATISFIED is defined. +[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined. ]] @@ -871,7 +954,7 @@ a default-constructed __thread_id__.]] [endsect] -[section:interrupt Member function `interrupt()`] +[section:interrupt Member function `interrupt()` EXTENSION] void interrupt(); @@ -919,38 +1002,61 @@ implementation. If no such instance exists, `native_handle()` and `native_handle [endsect] -[section:equals `operator==` DEPRECATED V3] +[section:equals `operator==` DEPRECATED] bool operator==(const thread& other) const; +[warning +DEPRECATED since 4.0.0. + +Available only up to Boost 1.58. + +Use `a.__get_id()==b.__get_id()` instead`. +] + + [variablelist [[Returns:] [`get_id()==other.get_id()`]] -[[See:] [Use `a.__get_id()==b.__get_id()` instead]] ] [endsect] -[section:not_equals `operator!=` DEPRECATED V3] +[section:not_equals `operator!=` DEPRECATED] bool operator!=(const thread& other) const; +[warning +DEPRECATED since 4.0.0. + +Available only up to Boost 1.58. + +Use `a.__get_id()!=b.__get_id()` instead`. +] + [variablelist [[Returns:] [`get_id()!=other.get_id()`]] -[[See:] [Use `a.__get_id()!=b.__get_id()` instead`]] - ] [endsect] -[section:sleep Static member function `sleep()`] +[section:sleep Static member function `sleep()` DEPRECATED] void sleep(system_time const& abs_time); +[warning +DEPRECATED since 3.0.0. + +Available only up to Boost 1.56. + +Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`. +] + + [variablelist [[Effects:] [Suspends the current thread until the specified time has been reached.]] @@ -959,22 +1065,26 @@ implementation. If no such instance exists, `native_handle()` and `native_handle [[Notes:] [`sleep()` is one of the predefined __interruption_points__.]] -[[See:] [Use `this_thread::__sleep_for()` or `this_thread::__sleep_until()`]] - ] [endsect] -[section:yield Static member function `yield()`] +[section:yield Static member function `yield()` DEPRECATED] void yield(); +[warning +DEPRECATED since 3.0.0. + +Available only up to Boost 1.56. + +Use `this_thread::__yield()`. +] + [variablelist [[Effects:] [See [link thread.thread_management.this_thread.yield `boost::this_thread::yield()`].]] -[[See:] [Use `this_thread::__yield()`]] - ] [endsect] @@ -1262,9 +1372,9 @@ thread attributes implementation. If no such instance exists, `native_handle()` class disable_interruption; // EXTENSION class restore_interruption; // EXTENSION - #if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO - void sleep(TimeDuration const& rel_time); - void sleep(system_time const& abs_time) + #if defined BOOST_THREAD_USES_DATETIME + void sleep(TimeDuration const& rel_time); // DEPRECATED + void sleep(system_time const& abs_time); // DEPRECATED #endif } } @@ -1345,7 +1455,7 @@ thread attributes implementation. If no such instance exists, `native_handle()` [endsect] -[section:sleep Non-member function `sleep()`] +[section:sleep Non-member function `sleep()` DEPRECATED] #include @@ -1356,6 +1466,15 @@ thread attributes implementation. If no such instance exists, `native_handle()` void sleep(system_time const& abs_time) } +[warning +DEPRECATED since 3.0.0. + +Available only up to Boost 1.56. + +Use `__sleep_for()` and `__sleep_until()` instead. +] + + [variablelist [[Effects:] [Suspends the current thread until the time period @@ -1366,8 +1485,6 @@ specified by `rel_time` has elapsed or the time point specified by [[Notes:] [`sleep()` is one of the predefined __interruption_points__.]] -[[See:] [Use `__sleep_for()` and `__sleep_until()` instead.]] - ] [endsect] @@ -1584,14 +1701,17 @@ registered with `at_thread_exit()`]] [endsect] -[section:threadgroup Class `thread_group`] +[section:threadgroup Class `thread_group` EXTENSION] #include + #include - class thread_group: - private noncopyable + class thread_group { public: + thread_group(const thread_group&) = delete; + thread_group& operator=(const thread_group&) = delete; + thread_group(); ~thread_group(); @@ -1599,6 +1719,8 @@ registered with `at_thread_exit()`]] thread* create_thread(F threadfunc); void add_thread(thread* thrd); void remove_thread(thread* thrd); + bool is_this_thread_in(); + bool is_thread_in(thread* thrd); void join_all(); void interrupt_all(); int size() const; @@ -1654,7 +1776,7 @@ registered with `at_thread_exit()`]] [variablelist -[[Precondition:] [The expression `delete thrd` is well-formed and will not result in undefined behaviour.]] +[[Precondition:] [The expression `delete thrd` is well-formed and will not result in undefined behaviour and `is_thread_in(thrd) == false`.]] [[Effects:] [Take ownership of the __thread__ object pointed to by `thrd` and add it to the group.]] @@ -1684,12 +1806,40 @@ registered with `at_thread_exit()`]] [variablelist +[[Requires:] [`is_this_thread_in() == false`.]] + [[Effects:] [Call `join()` on each __thread__ object in the group.]] [[Postcondition:] [Every thread in the group has terminated.]] [[Note:] [Since __join__ is one of the predefined __interruption_points__, `join_all()` is also an interruption point.]] +] + +[endsect] + +[section:is_this_thread_in Member function `is_this_thread_in()`] + + bool is_this_thread_in(); + +[variablelist + +[[Returns:] [true if there is a thread `th` in the group such that `th.get_id() == this_thread::get_id()`.]] + + +] + +[endsect] + +[section:is_thread_in Member function `is_thread_in()`] + + bool is_thread_in(thread* thrd); + +[variablelist + +[[Returns:] [true if there is a thread `th` in the group such that `th.get_id() == thrd->get_id()`.]] + + ] [endsect] diff --git a/example/ba_externallly_locked.cpp b/example/ba_externallly_locked.cpp new file mode 100644 index 00000000..d4454ae6 --- /dev/null +++ b/example/ba_externallly_locked.cpp @@ -0,0 +1,116 @@ +// 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) + +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include +#include +#include +#include + +using namespace boost; + +class BankAccount +{ + int balance_; +public: + void Deposit(int amount) + { + balance_ += amount; + } + void Withdraw(int amount) + { + balance_ -= amount; + } + int GetBalance() + { + return balance_; + } +}; + +//[AccountManager +class AccountManager: public basic_lockable_adapter +{ +public: + typedef basic_lockable_adapter lockable_base_type; + AccountManager() : + lockable_base_type(), checkingAcct_(*this), savingsAcct_(*this) + { + } + inline void Checking2Savings(int amount); + inline void AMoreComplicatedChecking2Savings(int amount); +private: + /*<-*/ + bool some_condition() + { + return true; + } /*->*/ + externally_locked checkingAcct_; + externally_locked savingsAcct_; +}; +//] + +//[Checking2Savings +void AccountManager::Checking2Savings(int amount) +{ + strict_lock guard(*this); + checkingAcct_.get(guard).Withdraw(amount); + savingsAcct_.get(guard).Deposit(amount); +} +//] + +//#if DO_NOT_COMPILE +////[AMoreComplicatedChecking2Savings_DO_NOT_COMPILE +//void AccountManager::AMoreComplicatedChecking2Savings(int amount) { +// unique_lock guard(*this); +// if (some_condition()) { +// guard.lock(); +// } +// checkingAcct_.get(guard).Withdraw(amount); +// savingsAcct_.get(guard).Deposit(amount); +// guard1.unlock(); +//} +////] +//#elif DO_NOT_COMPILE_2 +////[AMoreComplicatedChecking2Savings_DO_NOT_COMPILE2 +//void AccountManager::AMoreComplicatedChecking2Savings(int amount) { +// unique_lock guard1(*this); +// if (some_condition()) { +// guard1.lock(); +// } +// { +// strict_lock guard(guard1); +// checkingAcct_.get(guard).Withdraw(amount); +// savingsAcct_.get(guard).Deposit(amount); +// } +// guard1.unlock(); +//} +////] +//#else +////[AMoreComplicatedChecking2Savings +void AccountManager::AMoreComplicatedChecking2Savings(int amount) { + unique_lock guard1(*this); + if (some_condition()) { + guard1.lock(); + } + { + nested_strict_lock > guard(guard1); + checkingAcct_.get(guard).Withdraw(amount); + savingsAcct_.get(guard).Deposit(amount); + } + guard1.unlock(); +} +////] +//#endif + +int main() +{ + AccountManager mgr; + mgr.Checking2Savings(100); + return 0; +} + diff --git a/example/condition.cpp b/example/condition.cpp index 52475d6c..2cde1c02 100644 --- a/example/condition.cpp +++ b/example/condition.cpp @@ -7,13 +7,14 @@ #include #include #include -#include +#include #include +#include "../test/remove_error_code_unused_warning.hpp" class bounded_buffer : private boost::noncopyable { public: - typedef boost::mutex::scoped_lock lock; + typedef boost::unique_lock lock; bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { } @@ -38,9 +39,10 @@ public: } private: - int begin, end, buffered; + int begin, end; + std::vector::size_type buffered; std::vector circular_buf; - boost::condition buffer_not_full, buffer_not_empty; + boost::condition_variable_any buffer_not_full, buffer_not_empty; boost::mutex monitor; }; @@ -54,7 +56,7 @@ void sender() { buf.send(n); if(!(n%10000)) { - boost::mutex::scoped_lock io_lock(io_mutex); + boost::unique_lock io_lock(io_mutex); std::cout << "sent: " << n << std::endl; } ++n; @@ -68,7 +70,7 @@ void receiver() { n = buf.receive(); if(!(n%10000)) { - boost::mutex::scoped_lock io_lock(io_mutex); + boost::unique_lock io_lock(io_mutex); std::cout << "received: " << n << std::endl; } } while (n != -1); // -1 indicates end of buffer diff --git a/example/future_then.cpp b/example/future_then.cpp new file mode 100644 index 00000000..05aa47ef --- /dev/null +++ b/example/future_then.cpp @@ -0,0 +1,72 @@ +// 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) + +//#define BOOST_THREAD_VERSION 4 +#define BOOST_THREAD_USES_LOG +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET + +#include +#include +#include +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + +int p1() +{ + BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG; + return 123; +} + +int p2(boost::future& f) +{ + BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG; +} + +int main() +{ + BOOST_THREAD_LOG << " f1 = boost::async(&p1); + BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; + boost::future f2 = f1.then(&p2); + BOOST_THREAD_LOG << BOOST_THREAD_END_LOG; + BOOST_THREAD_LOG << f2.get() << BOOST_THREAD_END_LOG; + } + catch (std::exception& ex) + { + BOOST_THREAD_LOG << "ERRORRRRR "<" << BOOST_THREAD_END_LOG; + return 0; +} +#else + +int main() +{ + return 0; +} +#endif diff --git a/example/make_future.cpp b/example/make_future.cpp new file mode 100644 index 00000000..e9fd587e --- /dev/null +++ b/example/make_future.cpp @@ -0,0 +1,42 @@ +// 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) + +#define BOOST_THREAD_VERSION 4 + +#include +#include + +int p1() { return 5; } + +boost::future compute(int x) +{ + if (x == 0) return boost::make_future(0); + if (x < 0) return boost::make_future(-1); + //boost::future f1 = boost::async([]() { return x+1; }); + boost::future f1 = boost::async(boost::launch::async, p1); + return boost::move(f1); +} +boost::shared_future shared_compute(int x) +{ + if (x == 0) return boost::make_shared_future(0); + if (x < 0) return boost::make_shared_future(-1); + //boost::future f1 = boost::async([]() { return x+1; }); + boost::shared_future f1 = boost::async(p1).share(); + return boost::move(f1); +} + + +int main() +{ + { + boost::future f = compute(2); + std::cout << f.get() << std::endl; + } + { + boost::shared_future f = shared_compute(2); + std::cout << f.get() << std::endl; + } + return 0; +} diff --git a/example/monitor.cpp b/example/monitor.cpp index ff02f5b6..d8855d27 100644 --- a/example/monitor.cpp +++ b/example/monitor.cpp @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include #include @@ -20,7 +20,7 @@ template class buffer_t { public: - typedef typename M::scoped_lock scoped_lock; + typedef boost::unique_lock scoped_lock; buffer_t(int n) : p(0), c(0), full(0), buf(n) @@ -60,7 +60,7 @@ public: for (int n = 0; n < ITERS; ++n) { { - boost::mutex::scoped_lock lock(io_mutex); + boost::unique_lock lock(io_mutex); std::cout << "sending: " << n << std::endl; } get_buffer().send(n); @@ -73,7 +73,7 @@ public: { int n = get_buffer().receive(); { - boost::mutex::scoped_lock lock(io_mutex); + boost::unique_lock lock(io_mutex); std::cout << "received: " << n << std::endl; } } @@ -81,7 +81,7 @@ public: private: M mutex; - boost::condition cond; + boost::condition_variable_any cond; unsigned int p, c, full; std::vector buf; }; diff --git a/example/mutex.cpp b/example/mutex.cpp index b276d549..9e476208 100644 --- a/example/mutex.cpp +++ b/example/mutex.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2001-2003 // William E. Kempf // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// Distributed under the 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 @@ -16,7 +16,7 @@ public: counter() : count(0) { } int increment() { - boost::mutex::scoped_lock scoped_lock(mutex); + boost::unique_lock scoped_lock(mutex); return ++count; } @@ -30,7 +30,7 @@ counter c; void change_count() { int i = c.increment(); - boost::mutex::scoped_lock scoped_lock(io_mutex); + boost::unique_lock scoped_lock(io_mutex); std::cout << "count == " << i << std::endl; } diff --git a/example/not_interleaved.cpp b/example/not_interleaved.cpp new file mode 100644 index 00000000..b3ac3a66 --- /dev/null +++ b/example/not_interleaved.cpp @@ -0,0 +1,42 @@ +// (C) Copyright 2012 Howard Hinnant +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// adapted from the example given by Howard Hinnant in + + +#include +#include +#include + +void use_cerr(boost::externally_locked_stream &mcerr) +{ + using namespace boost; + auto tf = chrono::steady_clock::now() + chrono::seconds(10); + while (chrono::steady_clock::now() < tf) + { + mcerr << "logging data to cerr\n"; + this_thread::sleep_for(milliseconds(500)); + } +} + +int main() +{ + using namespace boost; + + externally_locked_stream mcerr(std::cerr, terminal_mutex()); + externally_locked_stream mcout(std::cerr, terminal_mutex()); + externally_locked_stream mcin(std::cerr, terminal_mutex()); + + thread t1(use_cerr, mcerr); + this_thread::sleep_for(boost::chrono::seconds(2)); + std::string nm; + mcout << "Enter name: "; + mcin >> nm; + t1.join(); + mcout << nm << '\n'; + return 0; +} + diff --git a/example/recursive_mutex.cpp b/example/recursive_mutex.cpp index c5199545..a5894832 100644 --- a/example/recursive_mutex.cpp +++ b/example/recursive_mutex.cpp @@ -1,7 +1,7 @@ // Copyright (C) 2001-2003 // William E. Kempf // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// Distributed under the 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 @@ -14,12 +14,12 @@ public: counter() : count(0) { } int add(int val) { - boost::recursive_mutex::scoped_lock scoped_lock(mutex); + boost::unique_lock scoped_lock(mutex); count += val; return count; } int increment() { - boost::recursive_mutex::scoped_lock scoped_lock(mutex); + boost::unique_lock scoped_lock(mutex); return add(1); } diff --git a/example/scoped_thread.cpp b/example/scoped_thread.cpp new file mode 100644 index 00000000..a6d8814f --- /dev/null +++ b/example/scoped_thread.cpp @@ -0,0 +1,69 @@ +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_THREAD_VERSION 3 + +#include +#include + +void do_something(int& i) +{ + ++i; +} + +struct func +{ + int& i; + + func(int& i_) : + i(i_) + { + } + + void operator()() + { + for (unsigned j = 0; j < 1000000; ++j) + { + do_something(i); + } + } +}; + +void do_something_in_current_thread() +{ +} + +//void do_something_with_current_thread(boost::thread&& th) +//{ +// th.join(); +//} + +int main() +{ + { + int some_local_state; + boost::strict_scoped_thread<> t( (boost::thread(func(some_local_state)))); + + do_something_in_current_thread(); + } + { + int some_local_state; + boost::thread t(( func(some_local_state) )); + boost::strict_scoped_thread<> g( (boost::move(t)) ); + + do_something_in_current_thread(); + } +// { +// int some_local_state; +// boost::thread t(( func(some_local_state) )); +// boost::strict_scoped_thread<> g( (boost::move(t)) ); +// +// do_something_in_current_thread(); +// do_something_with_current_thread(boost::thread(g)); +// } + return 0; +} + diff --git a/example/shared_monitor.cpp b/example/shared_monitor.cpp index c00cc3c0..e8378270 100644 --- a/example/shared_monitor.cpp +++ b/example/shared_monitor.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #if defined BOOST_THREAD_DONT_USE_CHRONO #include diff --git a/example/shared_mutex.cpp b/example/shared_mutex.cpp index ead68c2d..13246d96 100644 --- a/example/shared_mutex.cpp +++ b/example/shared_mutex.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include diff --git a/example/starvephil.cpp b/example/starvephil.cpp index 85e8c892..37752980 100644 --- a/example/starvephil.cpp +++ b/example/starvephil.cpp @@ -4,6 +4,8 @@ // Distributed under the 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 2 + #include #include #include @@ -23,18 +25,18 @@ public: void get(int id) { - boost::mutex::scoped_lock lock(m_mutex); + boost::unique_lock lock(m_mutex); while (m_chickens == 0) { { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lk(iomx); std::cout << "(" << clock() << ") Phil" << id << ": wot, no chickens? I'll WAIT ..." << std::endl; } m_condition.wait(lock); } { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lk(iomx); std::cout << "(" << clock() << ") Phil" << id << ": those chickens look good ... one please ..." << std::endl; } @@ -42,9 +44,9 @@ public: } void put(int value) { - boost::mutex::scoped_lock lock(m_mutex); + boost::unique_lock lock(m_mutex); { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lk(iomx); std::cout << "(" << clock() << ") Chef: ouch ... make room ... this dish is " << "very hot ..." << std::endl; @@ -55,7 +57,7 @@ public: boost::thread::sleep(xt); m_chickens += value; { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lk(iomx); std::cout << "(" << clock() << ") Chef: more chickens ... " << m_chickens << " now available ... NOTIFYING ..." << std::endl; @@ -75,13 +77,13 @@ void chef() { const int chickens = 4; { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lock(iomx); std::cout << "(" << clock() << ") Chef: starting ..." << std::endl; } for (;;) { { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lock(iomx); std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl; } boost::xtime xt; @@ -89,7 +91,7 @@ void chef() xt.sec += 2; boost::thread::sleep(xt); { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lock(iomx); std::cout << "(" << clock() << ") Chef: " << chickens << " chickens, ready-to-go ..." << std::endl; } @@ -102,7 +104,7 @@ struct phil phil(int id) : m_id(id) { } void run() { { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lock(iomx); std::cout << "(" << clock() << ") Phil" << m_id << ": starting ..." << std::endl; } @@ -116,13 +118,13 @@ struct phil boost::thread::sleep(xt); } { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lk(iomx); std::cout << "(" << clock() << ") Phil" << m_id << ": gotta eat ..." << std::endl; } g_canteen.get(m_id); { - boost::mutex::scoped_lock lock(iomx); + boost::unique_lock lk(iomx); std::cout << "(" << clock() << ") Phil" << m_id << ": mmm ... that's good ..." << std::endl; } diff --git a/example/strict_lock.cpp b/example/strict_lock.cpp new file mode 100644 index 00000000..43cfe5df --- /dev/null +++ b/example/strict_lock.cpp @@ -0,0 +1,40 @@ +// 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) + +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include +#include +#include +#include + + +BOOST_STATIC_ASSERT(boost::is_strict_lock >::value); +BOOST_CONCEPT_ASSERT(( boost::BasicLockable )); +BOOST_CONCEPT_ASSERT(( boost::StrictLock > )); + +int main() +{ + { + boost::mutex mtx; + boost::strict_lock lk(mtx); + std::cout << __FILE__ << std::endl; + } + { + boost::timed_mutex mtx; + boost::unique_lock lk(mtx); + boost::nested_strict_lock > nlk(lk); + std::cout << __FILE__ << std::endl; + } + { + boost::mutex mtx; + boost::unique_lock lk(mtx, boost::defer_lock); + boost::nested_strict_lock > nlk(lk); + std::cout << __FILE__ << std::endl; + } + return 0; +} diff --git a/example/synchronized_person.cpp b/example/synchronized_person.cpp new file mode 100644 index 00000000..66c372da --- /dev/null +++ b/example/synchronized_person.cpp @@ -0,0 +1,246 @@ +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//#define BOOST_THREAD_VERSION 4 + +// There is yet a limitation when BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET is defined +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET + +#include +#include +#include + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && ! defined BOOST_NO_CXX11_AUTO + + +//class SafePerson { +//public: +// std::string GetName() const { +// const_unique_access name(nameGuard); +// return *name; +// } +// void SetName(const std::string& newName) { +// unique_access name(nameGuard); +// *name = newName; +// } +//private: +// unique_access_guard nameGuard; +//}; + +class SafePerson { +public: + std::string GetName() const { + return *name; + } + void SetName(const std::string& newName) { + *name = newName; + } + +private: + boost::synchronized_value name; +}; + +class Person { +public: + std::string GetName() const { + return name; + } + void SetName(const std::string& newName) { + name = newName; + } +private: + std::string name; +}; +typedef boost::synchronized_value Person_ts; + + +//class SafeMemberPerson { +//public: +// SafeMemberPerson(unsigned int age) : +// memberGuard(age) +// { } +// std::string GetName() const { +// const_unique_access member(memberGuard); +// return member->name; +// } +// void SetName(const std::string& newName) { +// unique_access member(memberGuard); +// member->name = newName; +// } +//private: +// struct Member +// { +// Member(unsigned int age) : +// age(age) +// { } +// std::string name; +// unsigned int age; +// }; +// unique_access_guard memberGuard; +//}; + +class SafeMemberPerson { +public: + SafeMemberPerson(unsigned int age) : + member(Member(age)) + { } + std::string GetName() const { + return member->name; + } + void SetName(const std::string& newName) { + member->name = newName; + } +private: + struct Member { + Member(unsigned int age) : + age(age) + { } + std::string name; + unsigned int age; + }; + boost::synchronized_value member; +}; + + +class Person2 { +public: + Person2(unsigned int age) : age_(age) + {} + std::string GetName() const { + return name_; + } + void SetName(const std::string& newName) { + name_ = newName; + } + unsigned int GetAge() const { + return age_; + } + +private: + std::string name_; + unsigned int age_; +}; +typedef boost::synchronized_value Person2_ts; + +//=================== + +//class HelperPerson { +//public: +// HelperPerson(unsigned int age) : +// memberGuard(age) +// { } +// std::string GetName() const { +// const_unique_access member(memberGuard); +// Invariant(member); +// return member->name; +// } +// void SetName(const std::string& newName) { +// unique_access member(memberGuard); +// Invariant(member); +// member->name = newName; +// } +//private: +// void Invariant(const_unique_access& member) const { +// if (member->age < 0) throw std::runtime_error("Age cannot be negative"); +// } +// struct Member { +// Member(unsigned int age) : +// age(age) +// { } +// std::string name; +// unsigned int age; +// }; +// unique_access_guard memberGuard; +//}; + +class HelperPerson { +public: + HelperPerson(unsigned int age) : + member(age) + { } + std::string GetName() const { + auto&& memberSync = member.synchronize(); + Invariant(memberSync); + return memberSync->name; + } + void SetName(const std::string& newName) { + auto&& memberSync = member.synchronize(); + Invariant(memberSync); + memberSync->name = newName; + } +private: + struct Member { + Member(unsigned int age) : + age(age) + { } + std::string name; + unsigned int age; + }; + void Invariant(boost::synchronized_value::const_strict_synchronizer & mbr) const + { + if (mbr->age < 1) throw std::runtime_error("Age cannot be negative"); + } + boost::synchronized_value member; +}; + +class Person3 { +public: + Person3(unsigned int age) : + age_(age) + { } + std::string GetName() const { + Invariant(); + return name_; + } + void SetName(const std::string& newName) { + Invariant(); + name_ = newName; + } +private: + std::string name_; + unsigned int age_; + void Invariant() const { + if (age_ < 1) throw std::runtime_error("Age cannot be negative"); + } +}; + +typedef boost::synchronized_value Person3_ts; + +int main() +{ + { + SafePerson p; + p.SetName("Vicente"); + } + { + Person_ts p; + p->SetName("Vicente"); + } + { + SafeMemberPerson p(1); + p.SetName("Vicente"); + } + { + Person2_ts p(1); + p->SetName("Vicente"); + } + { + HelperPerson p(1); + p.SetName("Vicente"); + } + { + Person3_ts p(1); + p->SetName("Vicente"); + } + return 0; +} + +#else + +int main() +{ + return 0; +} +#endif diff --git a/example/synchronized_value.cpp b/example/synchronized_value.cpp new file mode 100644 index 00000000..19c6aaf6 --- /dev/null +++ b/example/synchronized_value.cpp @@ -0,0 +1,95 @@ +// (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//#define BOOST_THREAD_VERSION 4 + +// There is yet a limitation when BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET is defined +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET + +#include +#include +#include + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + +void addTrailingSlashIfMissing(boost::synchronized_value & path) +{ + boost::synchronized_value::strict_synchronizer u=path.synchronize(); + + if(u->empty() || (*u->rbegin()!='/')) + { + *u+='/'; + } +} + +void f(const boost::synchronized_value &v) { + std::cout<<"v="<<*v<::const_strict_synchronizer &v) { + std::cout<<"v="<<*v< & path) +{ + boost::synchronized_value::strict_synchronizer u=path.synchronize(); + + return (u->empty() || (*u->rbegin()!='/')); +} + +int main() +{ + { + boost::synchronized_value v1; + *v1=42; + std::cout<<"v1="<<*v1<append("foo"); +#endif + addTrailingSlashIfMissing(s); + std::cout<<"s="< s; +#if 1 + s->append("foo"); +#else + s.synchronize()->append("foo"); +#endif + addTrailingSlashIfMissing(s); + std::cout<<"s="< lock(mutex); int active = (int)param; int other = active == PLAYER_A ? PLAYER_B : PLAYER_A; @@ -108,7 +108,7 @@ int main(int argc, char* argv[]) xt.sec += 1; boost::thread::sleep(xt); { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); std::cout << "---Noise ON..." << std::endl; } @@ -116,7 +116,7 @@ int main(int argc, char* argv[]) cond.notify_all(); { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); std::cout << "---Noise OFF..." << std::endl; state = GAME_OVER; cond.notify_all(); diff --git a/example/thread.cpp b/example/thread.cpp index ebd77977..02dc4ac4 100644 --- a/example/thread.cpp +++ b/example/thread.cpp @@ -4,6 +4,8 @@ // Distributed under the 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 2 + #include #include #include diff --git a/example/thread_group.cpp b/example/thread_group.cpp index fd11a57c..56e39c51 100644 --- a/example/thread_group.cpp +++ b/example/thread_group.cpp @@ -6,20 +6,65 @@ #include #include +#include int count = 0; boost::mutex mutex; void increment_count() { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); + std::cout << "count = " << ++count << std::endl; +} + +boost::thread_group threads2; +boost::thread* th2 = 0; + +void increment_count_2() +{ + boost::unique_lock lock(mutex); + BOOST_TEST(threads2.is_this_thread_in()); std::cout << "count = " << ++count << std::endl; } int main() { + { boost::thread_group threads; - for (int i = 0; i < 10; ++i) + for (int i = 0; i < 3; ++i) threads.create_thread(&increment_count); threads.join_all(); + } + { + boost::thread_group threads; + for (int i = 0; i < 3; ++i) + threads.create_thread(&increment_count); + threads.interrupt_all(); + threads.join_all(); + } + { + boost::thread_group threads; + boost::thread* th = new boost::thread(&increment_count); + threads.add_thread(th); + BOOST_TEST(! threads.is_this_thread_in()); + threads.join_all(); + } + { + boost::thread_group threads; + boost::thread* th = new boost::thread(&increment_count); + threads.add_thread(th); + BOOST_TEST(threads.is_thread_in(th)); + threads.remove_thread(th); + BOOST_TEST(! threads.is_thread_in(th)); + th->join(); + } + { + { + boost::unique_lock lock(mutex); + boost::thread* th2 = new boost::thread(&increment_count_2); + threads2.add_thread(th2); + } + threads2.join_all(); + } + return boost::report_errors(); } diff --git a/example/thread_guard.cpp b/example/thread_guard.cpp new file mode 100644 index 00000000..0e83b6c8 --- /dev/null +++ b/example/thread_guard.cpp @@ -0,0 +1,57 @@ +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + +#include +#include +#include +#include + +void do_something(int& i) +{ + ++i; +} + +struct func +{ + int& i; + + func(int& i_):i(i_){} + + void operator()() + { + for(unsigned j=0;j<1000000;++j) + { + do_something(i); + } + } + +private: + func& operator=(func const&); + +}; + +void do_something_in_current_thread() +{} + + +void f() +{ + int some_local_state; + func my_func(some_local_state); + boost::thread t(my_func); + boost::thread_guard<> g(t); + + do_something_in_current_thread(); +} + +int main() +{ + f(); + return 0; +} + + diff --git a/example/xtime.cpp b/example/xtime.cpp index 91646e6b..58d741ca 100644 --- a/example/xtime.cpp +++ b/example/xtime.cpp @@ -4,6 +4,8 @@ // Distributed under the 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 2 + #include #include diff --git a/include/boost/thread/barrier.hpp b/include/boost/thread/barrier.hpp index 4fd89883..e041ffab 100644 --- a/include/boost/thread/barrier.hpp +++ b/include/boost/thread/barrier.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,7 @@ namespace boost bool wait() { - boost::mutex::scoped_lock lock(m_mutex); + boost::unique_lock lock(m_mutex); unsigned int gen = m_generation; if (--m_count == 0) diff --git a/include/boost/thread/condition.hpp b/include/boost/thread/condition.hpp index 35b879fe..9567df98 100644 --- a/include/boost/thread/condition.hpp +++ b/include/boost/thread/condition.hpp @@ -1,11 +1,15 @@ #ifndef BOOST_THREAD_CONDITION_HPP #define BOOST_THREAD_CONDITION_HPP -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include + +#if defined BOOST_THREAD_PROVIDES_CONDITION + #include namespace boost @@ -14,3 +18,4 @@ namespace boost } #endif +#endif diff --git a/include/boost/thread/detail/async_func.hpp b/include/boost/thread/detail/async_func.hpp new file mode 100644 index 00000000..4e2fbf96 --- /dev/null +++ b/include/boost/thread/detail/async_func.hpp @@ -0,0 +1,101 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The async_func code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP +#define BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP + +#include + +#include +#include +#include +#include + +#if ! defined(BOOST_NO_CXX11_HDR_TUPLE) +#include +#endif + +namespace boost +{ + namespace detail + { + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ + ! defined(BOOST_NO_CXX11_HDR_TUPLE) + + template + class async_func + { + std::tuple f_; + + public: + //typedef typename invoke_of<_Fp, _Args...>::type Rp; + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit async_func(Fp&& f, Args&&... args) + : f_(boost::move(f), boost::move(args)...) {} + + BOOST_SYMBOL_VISIBLE + async_func(async_func&& f) : f_(boost::move(f.f_)) {} + + result_type operator()() + { + typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index; + return execute(Index()); + } + private: + template + result_type + execute(tuple_indices) + { + return invoke(boost::move(std::get<0>(f_)), boost::move(std::get(f_))...); + } + }; +#else + template + class async_func + { + Fp f_; + + public: + BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func) + + typedef typename result_of::type result_type; + + BOOST_SYMBOL_VISIBLE + explicit async_func(BOOST_THREAD_FWD_REF(Fp) f) + : f_(boost::move(f)) {} + + BOOST_SYMBOL_VISIBLE + async_func(BOOST_THREAD_FWD_REF(async_func) f) : f_(boost::move(f.f_)) {} + + result_type operator()() + { + return execute(); + } + private: + result_type + execute() + { + return f_(); + } + }; +#endif + } +} + +#endif // header diff --git a/include/boost/thread/detail/config.hpp b/include/boost/thread/detail/config.hpp index 87bad341..fd89f211 100644 --- a/include/boost/thread/detail/config.hpp +++ b/include/boost/thread/detail/config.hpp @@ -15,104 +15,153 @@ #include #include +#include -#ifdef BOOST_NO_NOEXCEPT +#if ! defined BOOST_THREAD_NOEXCEPT_OR_THROW +#ifdef BOOST_NO_CXX11_NOEXCEPT # define BOOST_THREAD_NOEXCEPT_OR_THROW throw() #else # define BOOST_THREAD_NOEXCEPT_OR_THROW noexcept #endif +#endif + +#if defined BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED +#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) \ + if (EXPR) {} else boost::throw_exception(EX) +#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \ + if (EXPR) {} else boost::throw_exception(EX) +#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \ + boost::throw_exception(EX) +#else +#define BOOST_THREAD_ASSERT_PRECONDITION(EXPR, EX) +#define BOOST_THREAD_VERIFY_PRECONDITION(EXPR, EX) \ + (void)(EXPR) +#define BOOST_THREAD_THROW_ELSE_RETURN(EX, RET) \ + return (RET) +#endif // This compiler doesn't support Boost.Chrono -#if defined __IBMCPP__ && (__IBMCPP__ < 1100) && ! defined BOOST_THREAD_DONT_USE_CHRONO +#if defined __IBMCPP__ && (__IBMCPP__ < 1100) \ + && ! defined BOOST_THREAD_DONT_USE_CHRONO #define BOOST_THREAD_DONT_USE_CHRONO +#if ! defined BOOST_THREAD_USE_DATE +#define BOOST_THREAD_USE_DATE +#endif #endif // This compiler doesn't support Boost.Move -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) && ! defined BOOST_THREAD_DONT_USE_MOVE +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) \ + && ! defined BOOST_THREAD_DONT_USE_MOVE #define BOOST_THREAD_DONT_USE_MOVE #endif // This compiler doesn't support Boost.Container Allocators files -#if defined __SUNPRO_CC && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#if defined __SUNPRO_CC \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #endif -#if defined _WIN32_WCE && _WIN32_WCE==0x501 && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS +#if defined _WIN32_WCE && _WIN32_WCE==0x501 \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS #endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID && ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID +/// BASIC_THREAD_ID +// todo to be removed for 1.54 +#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID \ + && ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID #endif +/// RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES || defined BOOST_MSVC +#define BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR +#endif + // Default version is 2 #if !defined BOOST_THREAD_VERSION #define BOOST_THREAD_VERSION 2 #else -#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 -#error "BOOST_THREAD_VERSION must be 2 or 3" +#if BOOST_THREAD_VERSION!=2 && BOOST_THREAD_VERSION!=3 && BOOST_THREAD_VERSION!=4 +#error "BOOST_THREAD_VERSION must be 2, 3 or 4" #endif #endif +// CHRONO // Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO -#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_USES_CHRONO +#if ! defined BOOST_THREAD_DONT_USE_CHRONO \ + && ! defined BOOST_THREAD_USES_CHRONO #define BOOST_THREAD_USES_CHRONO #endif -// Don't provided by default in version 1. -#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION -#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit -#else -#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION -#endif - - #if BOOST_THREAD_VERSION==2 -#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY && ! defined BOOST_THREAD_PROMISE_LAZY -#define BOOST_THREAD_PROMISE_LAZY -#endif -#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 -#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 -#endif + +// PROVIDE_PROMISE_LAZY +#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \ + && ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY +#define BOOST_THREAD_PROVIDES_PROMISE_LAZY #endif -#if BOOST_THREAD_VERSION==3 +// PROVIDE_THREAD_EQ +#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_EQ \ + && ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ +#endif + +#endif + +#if BOOST_THREAD_VERSION>=3 + +// ONCE_CXX11 +// fixme BOOST_THREAD_PROVIDES_ONCE_CXX11 doesn't works when thread.cpp is compiled BOOST_THREAD_VERSION 3 #if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 \ && ! defined BOOST_THREAD_PROVIDES_ONCE_CXX11 -#define BOOST_THREAD_PROVIDES_ONCE_CXX11 +#define BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11 #endif + +// THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE \ && ! defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE #endif + +// THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE \ && ! defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE #endif + +// PROVIDE_FUTURE #if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE \ && ! defined BOOST_THREAD_PROVIDES_FUTURE #define BOOST_THREAD_PROVIDES_FUTURE #endif + +// FUTURE_CTOR_ALLOCATORS #if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS \ && ! defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #endif + +// SHARED_MUTEX_UPWARDS_CONVERSIONS #if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS \ && ! defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #endif + +// PROVIDE_EXPLICIT_LOCK_CONVERSION #if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION \ && ! defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #endif + +// GENERIC_SHARED_MUTEX_ON_WIN #if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN \ && ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN #endif -#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 \ - && ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_ -#define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 -#endif + +// USE_MOVE #if ! defined BOOST_THREAD_DONT_USE_MOVE \ && ! defined BOOST_THREAD_USES_MOVE #define BOOST_THREAD_USES_MOVE @@ -120,6 +169,93 @@ #endif +// deprecated since version 4 +#if BOOST_THREAD_VERSION < 4 + +// NESTED_LOCKS +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#define BOOST_THREAD_PROVIDES_NESTED_LOCKS +#endif + +// CONDITION +#if ! defined BOOST_THREAD_PROVIDES_CONDITION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION +#define BOOST_THREAD_PROVIDES_CONDITION +#endif + +// USE_DATETIME +#if ! defined BOOST_THREAD_DONT_USE_DATETIME \ + && ! defined BOOST_THREAD_USES_DATETIME +#define BOOST_THREAD_USES_DATETIME +#endif +#endif + +#if BOOST_THREAD_VERSION>=4 + +// SIGNATURE_PACKAGED_TASK +#if ! defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK \ + && ! defined BOOST_THREAD_DONT_PROVIDE_SIGNATURE_PACKAGED_TASK +#define BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#endif + +// VARIADIC_THREAD +#if ! defined BOOST_THREAD_PROVIDES_VARIADIC_THREAD \ + && ! defined BOOST_THREAD_DONT_PROVIDE_VARIADIC_THREAD + +#if ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \ + ! defined(BOOST_NO_CXX11_AUTO) && \ + ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \ + ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD +#endif +#endif + +// FUTURE_CONTINUATION +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION +#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION +#endif + +// FUTURE_INVALID_AFTER_GET +#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \ + && ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET +#define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET +#endif + +// NESTED_LOCKS +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#define BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS +#endif + +// CONDITION +#if ! defined BOOST_THREAD_PROVIDES_CONDITION \ + && ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION +#define BOOST_THREAD_DONT_PROVIDE_CONDITION +#endif + +#endif // BOOST_THREAD_VERSION>=4 + +// INTERRUPTIONS +#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \ + && ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS +#endif + +// CORRELATIONS + +// EXPLICIT_LOCK_CONVERSION. +#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit +#else +#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION +#endif + // BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS #if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \ && ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN @@ -128,9 +264,12 @@ // BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52 // BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55 -#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 \ -&& ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 -#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 + +#if ! defined BOOST_THREAD_PROVIDES_THREAD_EQ +#define BOOST_THREAD_PROVIDES_THREAD_EQ +#endif + #endif #if BOOST_WORKAROUND(__BORLANDC__, < 0x600) @@ -142,6 +281,13 @@ #include +#if defined(BOOST_THREAD_PLATFORM_WIN32) +#else + # if defined(BOOST_HAS_PTHREAD_DELAY_NP) || defined(BOOST_HAS_NANOSLEEP) + # define BOOST_THREAD_SLEEP_FOR_IS_STEADY + # endif +#endif + // provided for backwards compatibility, since this // macro was used for several releases by mistake. #if defined(BOOST_THREAD_DYN_DLL) && ! defined BOOST_THREAD_DYN_LINK diff --git a/include/boost/thread/detail/invoke.hpp b/include/boost/thread/detail/invoke.hpp new file mode 100644 index 00000000..9257cc0e --- /dev/null +++ b/include/boost/thread/detail/invoke.hpp @@ -0,0 +1,88 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The invoke code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_INVOKE_HPP +#define BOOST_THREAD_DETAIL_INVOKE_HPP + +#include +#include + +namespace boost +{ + namespace detail + { + +#if ! defined(BOOST_NO_SFINAE_EXPR) && \ + ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE) && \ + ! defined(BOOST_NO_CXX11_DECLTYPE_N3276) && \ + ! defined(BOOST_NO_CXX11_AUTO) && \ + ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + // // bullets 1 and 2 + + template + inline + auto + invoke(Fp&& f, A0&& a0, Args&& ...args) + -> decltype((boost::forward(a0).*f)(boost::forward(args)...)) + { + return (boost::forward(a0).*f)(boost::forward(args)...); + } + + template + inline + auto + invoke(Fp&& f, A0&& a0, Args&& ...args) + -> decltype(((*boost::forward(a0)).*f)(boost::forward(args)...)) + { + return ((*boost::forward(a0)).*f)(boost::forward(args)...); + } + + // bullets 3 and 4 + + template + inline + auto + invoke(Fp&& f, A0&& a0) + -> decltype(boost::forward(a0).*f) + { + return boost::forward(a0).*f; + } + + template + inline + auto + invoke(Fp&& f, A0&& a0) + -> decltype((*boost::forward(a0)).*f) + { + return (*boost::forward(a0)).*f; + } + + // bullet 5 + + template + inline + auto invoke(Fp&& f, Args&& ...args) + -> decltype(boost::forward(f)(boost::forward(args)...)) + { + return boost::forward(f)(boost::forward(args)...); + } + +#endif + } + } + +#endif // header diff --git a/include/boost/thread/detail/is_convertible.hpp b/include/boost/thread/detail/is_convertible.hpp new file mode 100644 index 00000000..dbc29cf2 --- /dev/null +++ b/include/boost/thread/detail/is_convertible.hpp @@ -0,0 +1,48 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright 2011-2012 Vicente J. Botet Escriba +// Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// See http://www.boost.org/libs/thread for documentation. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP +#define BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP + +#include +#include + +namespace boost +{ + namespace thread_detail + { + template + struct is_convertible : boost::is_convertible {}; + +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES + +#if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION <= 1001) + +#if defined BOOST_THREAD_USES_MOVE + template + struct is_convertible< + rv &, + rv > & + > : false_type {}; +#endif + +#elif defined __GNUC__ && (__GNUC__ < 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ <= 4 )) + + template + struct is_convertible : boost::is_convertible {}; +#endif + +#endif + } + +} // namespace boost + + +#endif // BOOST_THREAD_DETAIL_MEMORY_HPP diff --git a/include/boost/thread/detail/log.hpp b/include/boost/thread/detail/log.hpp new file mode 100644 index 00000000..84dcc8cb --- /dev/null +++ b/include/boost/thread/detail/log.hpp @@ -0,0 +1,83 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_DETAIL_LOG_HPP +#define BOOST_THREAD_DETAIL_LOG_HPP + +#include +#if defined BOOST_THREAD_USES_LOG +#include +#include +#if defined BOOST_THREAD_USES_LOG_THREAD_ID +#include +#endif +#include + +namespace boost +{ + namespace thread_detail + { + inline boost::recursive_mutex& terminal_mutex() + { + static boost::recursive_mutex mtx; + return mtx; + } + + } +} +#if defined BOOST_THREAD_USES_LOG_THREAD_ID + +#define BOOST_THREAD_LOG \ + { \ + boost::lock_guard _lk_(boost::thread_detail::terminal_mutex()); \ + std::cout << boost::this_thread::get_id() << " - "<<__FILE__<<"["<<__LINE__<<"] " < _lk_(boost::thread_detail::terminal_mutex()); \ + std::cout << __FILE__<<"["<<__LINE__<<"] " < + inline dummy_stream_t const& operator<<(dummy_stream_t const& os, T) + { + return os; + } + + inline dummy_stream_t const& operator<<(dummy_stream_t const& os, dummy_stream_t const&) + { + return os; + } + + + BOOST_CONSTEXPR_OR_CONST dummy_stream_t dummy_stream = {}; + + } +} + +#define BOOST_THREAD_LOG if (true) {} else boost::thread_detail::dummy_stream +#define BOOST_THREAD_END_LOG boost::thread_detail::dummy_stream + +#endif + +#define BOOST_THREAD_TRACE BOOST_THREAD_LOG << BOOST_THREAD_END_LOG + + +#endif // header diff --git a/include/boost/thread/detail/make_tuple_indices.hpp b/include/boost/thread/detail/make_tuple_indices.hpp new file mode 100644 index 00000000..0839fe02 --- /dev/null +++ b/include/boost/thread/detail/make_tuple_indices.hpp @@ -0,0 +1,60 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +// The make_tuple_indices code is based on the one from libcxx. +//===----------------------------------------------------------------------===// + +#ifndef BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP +#define BOOST_THREAD_DETAIL_MAKE_TUPLE_INDICES_HPP + +#include +#include + +namespace boost +{ + namespace detail + { + +#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + + // make_tuple_indices + + template struct tuple_indices + {}; + + template + struct make_indices_imp; + + template + struct make_indices_imp, Ep> + { + typedef typename make_indices_imp, Ep>::type type; + }; + + template + struct make_indices_imp, Ep> + { + typedef tuple_indices type; + }; + + template + struct make_tuple_indices + { + BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error"); + typedef typename make_indices_imp, Ep>::type type; + }; +#endif + } +} + +#endif // header diff --git a/include/boost/thread/detail/move.hpp b/include/boost/thread/detail/move.hpp index f2665e6c..6db55c43 100644 --- a/include/boost/thread/detail/move.hpp +++ b/include/boost/thread/detail/move.hpp @@ -17,7 +17,7 @@ #endif #include -#include +#include #include namespace boost @@ -26,7 +26,7 @@ namespace boost namespace detail { template - struct has_move_emulation_enabled_aux_dummy_specialization; + struct enable_move_utility_emulation_dummy_specialization; template struct thread_move_t { @@ -49,6 +49,7 @@ namespace boost }; } +#if !defined BOOST_THREAD_USES_MOVE #ifndef BOOST_NO_SFINAE template @@ -63,11 +64,14 @@ namespace boost { return t; } + +#endif //#if !defined BOOST_THREAD_USES_MOVE } #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES #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 #define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END #define BOOST_THREAD_RV(V) V @@ -77,16 +81,17 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ namespace detail { \ template \ - struct has_move_emulation_enabled_aux_dummy_specialization< + struct enable_move_utility_emulation_dummy_specialization< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : integral_constant \ + : integral_constant \ {}; \ } #elif ! defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_MSVC #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 #define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END #define BOOST_THREAD_RV(V) V @@ -96,10 +101,10 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ namespace detail { \ template \ - struct has_move_emulation_enabled_aux_dummy_specialization< + struct enable_move_utility_emulation_dummy_specialization< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : integral_constant \ + : integral_constant \ {}; \ } @@ -107,6 +112,7 @@ namespace boost #if defined BOOST_THREAD_USES_MOVE #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 #define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END #define BOOST_THREAD_RV(V) V @@ -115,10 +121,10 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ namespace detail { \ template \ - struct has_move_emulation_enabled_aux_dummy_specialization< + struct enable_move_utility_emulation_dummy_specialization< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : integral_constant \ + : integral_constant \ {}; \ } @@ -132,17 +138,19 @@ namespace boost #define BOOST_THREAD_DCL_MOVABLE(TYPE) \ template <> \ -struct has_move_emulation_enabled_aux< TYPE > \ - : BOOST_MOVE_BOOST_NS::integral_constant \ -{}; +struct enable_move_utility_emulation< TYPE > \ +{ \ + static const bool value = false; \ +}; #define BOOST_THREAD_DCL_MOVABLE_BEG(T) \ template \ -struct has_move_emulation_enabled_aux< +struct enable_move_utility_emulation< #define BOOST_THREAD_DCL_MOVABLE_END > \ - : BOOST_MOVE_BOOST_NS::integral_constant \ -{}; +{ \ + static const bool value = false; \ +}; #endif @@ -227,19 +235,26 @@ namespace detail -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES namespace boost { namespace thread_detail { +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template typename decay::type decay_copy(T&& t) { return boost::forward(t); } +#else + template + typename decay::type + decay_copy(BOOST_THREAD_FWD_REF(T) t) + { + return boost::forward(t); + } +#endif } } -#endif #include diff --git a/include/boost/thread/detail/thread.hpp b/include/boost/thread/detail/thread.hpp index 2590f45c..e90d7e3f 100644 --- a/include/boost/thread/detail/thread.hpp +++ b/include/boost/thread/detail/thread.hpp @@ -3,18 +3,24 @@ // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -// (C) Copyright 2007-10 Anthony Williams -// (C) Copyright 20011-12 Vicente J. Botet Escriba +// (C) Copyright 2007-2010 Anthony Williams +// (C) Copyright 20011-2012 Vicente J. Botet Escriba #include + #include #ifndef BOOST_NO_IOSTREAM #include #endif #include #include +#if defined BOOST_THREAD_USES_DATETIME #include +#endif #include +#include +#include +#include #include #include #include @@ -23,8 +29,6 @@ #include #include #include -//#include -//#include #include #include #include @@ -36,6 +40,9 @@ #include #endif +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#include +#endif #include #ifdef BOOST_MSVC @@ -48,6 +55,38 @@ namespace boost namespace detail { + +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + class thread_data: + public detail::thread_data_base + { + public: + BOOST_THREAD_NO_COPYABLE(thread_data) +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + thread_data(BOOST_THREAD_RV_REF(F) f_, BOOST_THREAD_RV_REF(ArgTypes)... args_): + fp(boost::forward(f_), boost::forward(args_)...) + {} +#endif + template + void run2(tuple_indices) + { + + invoke(std::move(std::get<0>(fp)), std::move(std::get(fp))...); + } + void run() + { + typedef typename make_tuple_indices >::value, 1>::type index_type; + + run2(index_type()); + } + + private: + std::tuple::type, typename decay::type...> fp; + }; +#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template class thread_data: public detail::thread_data_base @@ -115,6 +154,7 @@ namespace boost f(); } }; +#endif } class BOOST_THREAD_DECL thread @@ -125,24 +165,55 @@ namespace boost BOOST_THREAD_MOVABLE_ONLY(thread) private: + struct dummy; + void release_handle(); detail::thread_data_ptr thread_info; - void start_thread(); - void start_thread(const attributes& attr); + private: + bool start_thread_noexcept(); + bool start_thread_noexcept(const attributes& attr); + public: + void start_thread() + { + if (!start_thread_noexcept()) + { + boost::throw_exception(thread_resource_error()); + } + } + void start_thread(const attributes& attr) + { + if (!start_thread_noexcept(attr)) + { + boost::throw_exception(thread_resource_error()); + } + } explicit thread(detail::thread_data_ptr data); detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const; #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f, BOOST_THREAD_RV_REF(ArgTypes)... args) + { + return detail::thread_data_ptr(detail::heap_new< + detail::thread_data::type, ArgTypes...> + >( + boost::forward(f), boost::forward(args)... + ) + ); + } +#else template static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f) { return detail::thread_data_ptr(detail::heap_new::type> >( boost::forward(f))); } +#endif static inline detail::thread_data_ptr make_thread_info(void (*f)()) { return detail::thread_data_ptr(detail::heap_new >( @@ -150,7 +221,12 @@ namespace boost } #else template - static inline detail::thread_data_ptr make_thread_info(F f) + static inline detail::thread_data_ptr make_thread_info(F f + , typename disable_if_c< + //boost::thread_detail::is_convertible::value || + is_same::type, thread>::value, + dummy* >::type=0 + ) { return detail::thread_data_ptr(detail::heap_new >(f)); } @@ -161,7 +237,6 @@ namespace boost } #endif - struct dummy; public: #if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. #if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) @@ -171,6 +246,7 @@ namespace boost thread() BOOST_NOEXCEPT; ~thread() { + #if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE if (joinable()) { std::terminate(); @@ -184,7 +260,7 @@ namespace boost class F > explicit thread(BOOST_THREAD_RV_REF(F) f - , typename disable_if::type, thread>, dummy* >::type=0 + //, typename disable_if::type, thread>, dummy* >::type=0 ): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) { @@ -193,7 +269,7 @@ namespace boost template < class F > - thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): + thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): thread_info(make_thread_info(thread_detail::decay_copy(boost::forward(f)))) { start_thread(attrs); @@ -208,7 +284,7 @@ namespace boost start_thread(); } template - thread(attributes& attrs, F f): + thread(attributes const& attrs, F f): thread_info(make_thread_info(f)) { start_thread(attrs); @@ -216,15 +292,19 @@ namespace boost #else template explicit thread(F f - // todo Disable also if Or is_same::type, thread> - , typename disable_if, dummy* >::type=0): + , typename disable_if_c< + boost::thread_detail::is_convertible::value + //|| is_same::type, thread>::value + , dummy* >::type=0 + ): thread_info(make_thread_info(f)) { start_thread(); } template - thread(attributes& attrs, F f - , typename disable_if, dummy* >::type=0): + thread(attributes const& attrs, F f + , typename disable_if, dummy* >::type=0 + ): thread_info(make_thread_info(f)) { start_thread(attrs); @@ -234,14 +314,22 @@ namespace boost explicit thread(BOOST_THREAD_RV_REF(F) f , typename disable_if::type, thread>, dummy* >::type=0 ): - thread_info(make_thread_info(f)) +#ifdef BOOST_THREAD_USES_MOVE + thread_info(make_thread_info(boost::move(f))) // todo : Add forward +#else + thread_info(make_thread_info(f)) // todo : Add forward +#endif { start_thread(); } template - thread(attributes& attrs, BOOST_THREAD_RV_REF(F) f): - thread_info(make_thread_info(f)) + thread(attributes const& attrs, BOOST_THREAD_RV_REF(F) f): +#ifdef BOOST_THREAD_USES_MOVE + thread_info(make_thread_info(boost::move(f))) // todo : Add forward +#else + thread_info(make_thread_info(f)) // todo : Add forward +#endif { start_thread(attrs); } @@ -272,8 +360,32 @@ namespace boost return *this; } +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + thread(F&& f, Arg&& arg, Args&&... args) : + thread_info(make_thread_info( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(arg)), + thread_detail::decay_copy(boost::forward(args))...) + ) + + { + start_thread(); + } + template + thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) : + thread_info(make_thread_info( + thread_detail::decay_copy(boost::forward(f)), + thread_detail::decay_copy(boost::forward(arg)), + thread_detail::decay_copy(boost::forward(args))...) + ) + + { + start_thread(attrs); + } +#else template - thread(F f,A1 a1,typename disable_if, dummy* >::type=0): + thread(F f,A1 a1,typename disable_if, dummy* >::type=0): thread_info(make_thread_info(boost::bind(boost::type(),f,a1))) { start_thread(); @@ -333,18 +445,26 @@ namespace boost { start_thread(); } - +#endif void swap(thread& x) BOOST_NOEXCEPT { thread_info.swap(x.thread_info); } class BOOST_SYMBOL_VISIBLE id; +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + inline id get_id() const BOOST_NOEXCEPT; +#else id get_id() const BOOST_NOEXCEPT; +#endif bool joinable() const BOOST_NOEXCEPT; - void join(); + private: + bool join_noexcept(); + public: + inline void join(); + #ifdef BOOST_THREAD_USES_CHRONO template bool try_join_for(const chrono::duration& rel_time) @@ -368,10 +488,15 @@ namespace boost } #endif #if defined(BOOST_THREAD_PLATFORM_WIN32) - bool timed_join(const system_time& abs_time); private: - bool do_try_join_until(uintmax_t milli); + bool do_try_join_until_noexcept(uintmax_t milli, bool& res); + inline bool do_try_join_until(uintmax_t milli); public: + bool timed_join(const system_time& abs_time); + //{ + // return do_try_join_until(get_milliseconds_until(wait_until)); + //} + #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { @@ -382,35 +507,37 @@ namespace boost #else + private: + bool do_try_join_until_noexcept(struct timespec const &timeout, bool& res); + inline bool do_try_join_until(struct timespec const &timeout); + public: +#if defined BOOST_THREAD_USES_DATETIME bool timed_join(const system_time& abs_time) { - struct timespec const ts=detail::get_timespec(abs_time); + struct timespec const ts=detail::to_timespec(abs_time); return do_try_join_until(ts); } +#endif #ifdef BOOST_THREAD_USES_CHRONO bool try_join_until(const chrono::time_point& tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast(d); - ts.tv_sec = static_cast(s.count()); - ts.tv_nsec = static_cast((d - s).count()); + timespec ts = boost::detail::to_timespec(d); return do_try_join_until(ts); } #endif - private: - bool do_try_join_until(struct timespec const &timeout); - public: #endif + public: +#if defined BOOST_THREAD_USES_DATETIME template inline bool timed_join(TimeDuration const& rel_time) { return timed_join(get_system_time()+rel_time); } - +#endif void detach(); static unsigned hardware_concurrency() BOOST_NOEXCEPT; @@ -419,12 +546,13 @@ namespace boost typedef detail::thread_data_base::native_handle_type native_handle_type; native_handle_type native_handle(); -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ // Use thread::id when comparisions are needed // backwards compatibility bool operator==(const thread& other) const; bool operator!=(const thread& other) const; #endif +#if defined BOOST_THREAD_USES_DATETIME static inline void yield() BOOST_NOEXCEPT { this_thread::yield(); @@ -434,10 +562,13 @@ namespace boost { this_thread::sleep(xt); } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS // extensions void interrupt(); bool interruption_requested() const BOOST_NOEXCEPT; +#endif }; inline void swap(thread& lhs,thread& rhs) BOOST_NOEXCEPT @@ -456,16 +587,24 @@ namespace boost namespace this_thread { +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + inline thread::id get_id() BOOST_NOEXCEPT; +#else thread::id BOOST_THREAD_DECL get_id() BOOST_NOEXCEPT; +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void BOOST_THREAD_DECL interruption_point(); bool BOOST_THREAD_DECL interruption_enabled() BOOST_NOEXCEPT; bool BOOST_THREAD_DECL interruption_requested() BOOST_NOEXCEPT; +#endif +#if defined BOOST_THREAD_USES_DATETIME inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); } +#endif } class BOOST_SYMBOL_VISIBLE thread::id @@ -501,11 +640,7 @@ namespace boost public: id() BOOST_NOEXCEPT: #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID -#if defined(BOOST_THREAD_PLATFORM_WIN32) thread_data(0) -#else - thread_data(0) -#endif #else thread_data() #endif @@ -583,6 +718,62 @@ namespace boost #endif }; +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + thread::id thread::get_id() const BOOST_NOEXCEPT + { + #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return const_cast(this)->native_handle(); + #else + detail::thread_data_ptr const local_thread_info=(get_thread_info)(); + return (local_thread_info? id(local_thread_info) id()); + #endif + } + + namespace this_thread + { + thread::id get_id() BOOST_NOEXCEPT + { + #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID + return pthread_self(); + #else + boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); + return (thread_info?thread::id(thread_info->shared_from_this()):thread::id()); + #endif + } + } +#endif + void thread::join() { + BOOST_THREAD_ASSERT_PRECONDITION( this_thread::get_id() != get_id(), + thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself") + ); + BOOST_THREAD_VERIFY_PRECONDITION( join_noexcept(), + thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable") + ); + } + +#ifdef BOOST_THREAD_PLATFORM_PTHREAD + bool thread::do_try_join_until(struct timespec const &timeout) +#else + bool thread::do_try_join_until(uintmax_t timeout) +#endif + { + BOOST_THREAD_ASSERT_PRECONDITION( this_thread::get_id() != get_id(), + thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself") + ); + bool res; + if (do_try_join_until_noexcept(timeout, res)) + { + return res; + } + else + { + BOOST_THREAD_THROW_ELSE_RETURN( + thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable"), + false + ); + } + } + #if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS) template BOOST_SYMBOL_VISIBLE @@ -593,7 +784,7 @@ namespace boost } #endif -#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 +#if defined BOOST_THREAD_PROVIDES_THREAD_EQ inline bool thread::operator==(const thread& other) const { return get_id()==other.get_id(); diff --git a/include/boost/thread/detail/thread_group.hpp b/include/boost/thread/detail/thread_group.hpp index f1ccdf84..3c0ee861 100644 --- a/include/boost/thread/detail/thread_group.hpp +++ b/include/boost/thread/detail/thread_group.hpp @@ -8,6 +8,7 @@ #include #include #include +#include #include @@ -22,7 +23,7 @@ namespace boost { private: thread_group(thread_group const&); - thread_group& operator=(thread_group const&); + thread_group& operator=(thread_group const&); public: thread_group() {} ~thread_group() @@ -35,6 +36,41 @@ namespace boost } } + bool is_this_thread_in() + { + thread::id id = this_thread::get_id(); + boost::shared_lock guard(m); + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + + bool is_thread_in(thread* thrd) + { + if(thrd) + { + thread::id id = thrd->get_id(); + boost::shared_lock guard(m); + for(std::list::iterator it=threads.begin(),end=threads.end(); + it!=end; + ++it) + { + if ((*it)->get_id() == id) + return true; + } + return false; + } + else + { + return false; + } + } + template thread* create_thread(F threadfunc) { @@ -43,16 +79,20 @@ namespace boost threads.push_back(new_thread.get()); return new_thread.release(); } - + void add_thread(thread* thrd) { if(thrd) { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_thread_in(thrd) , + thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying to add a duplicated thread") + ); + boost::lock_guard guard(m); threads.push_back(thrd); } } - + void remove_thread(thread* thrd) { boost::lock_guard guard(m); @@ -62,23 +102,28 @@ namespace boost threads.erase(it); } } - + void join_all() { + BOOST_THREAD_ASSERT_PRECONDITION( ! is_this_thread_in() , + thread_resource_error(system::errc::resource_deadlock_would_occur, "boost::thread_group: trying joining itself") + ); boost::shared_lock guard(m); - + for(std::list::iterator it=threads.begin(),end=threads.end(); it!=end; ++it) { + if ((*it)->joinable()) (*it)->join(); } } - + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void interrupt_all() { boost::shared_lock guard(m); - + for(std::list::iterator it=threads.begin(),end=threads.end(); it!=end; ++it) @@ -86,13 +131,14 @@ namespace boost (*it)->interrupt(); } } - +#endif + size_t size() const { boost::shared_lock guard(m); return threads.size(); } - + private: std::list threads; mutable shared_mutex m; diff --git a/include/boost/thread/detail/thread_interruption.hpp b/include/boost/thread/detail/thread_interruption.hpp index f1a165c3..5d7d10fe 100644 --- a/include/boost/thread/detail/thread_interruption.hpp +++ b/include/boost/thread/detail/thread_interruption.hpp @@ -9,6 +9,8 @@ #include #include +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + namespace boost { namespace this_thread @@ -33,4 +35,5 @@ namespace boost } } -#endif +#endif // BOOST_THREAD_PROVIDES_INTERRUPTIONS +#endif // header diff --git a/include/boost/thread/exceptions.hpp b/include/boost/thread/exceptions.hpp index 08c28d3d..2d129cff 100644 --- a/include/boost/thread/exceptions.hpp +++ b/include/boost/thread/exceptions.hpp @@ -28,8 +28,10 @@ namespace boost { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS class BOOST_SYMBOL_VISIBLE thread_interrupted {}; +#endif class BOOST_SYMBOL_VISIBLE thread_exception: public system::system_error diff --git a/include/boost/thread/externally_locked.hpp b/include/boost/thread/externally_locked.hpp new file mode 100644 index 00000000..4d98fed5 --- /dev/null +++ b/include/boost/thread/externally_locked.hpp @@ -0,0 +1,304 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_HPP +#define BOOST_THREAD_EXTERNALLY_LOCKED_HPP + +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +namespace boost +{ + + /** + * externally_locked cloaks an object of type T, and actually provides full + * access to that object through the get and set member functions, provided you + * pass a reference to a strict lock object + */ + + //[externally_locked + template + class externally_locked + { + //BOOST_CONCEPT_ASSERT(( CopyConstructible )); + BOOST_CONCEPT_ASSERT(( BasicLockable )); + + public: + typedef MutexType mutex_type; + + BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked ) + /** + * Requires: T is a model of CopyConstructible. + * Effects: Constructs an externally locked object copying the cloaked type. + */ + BOOST_CONSTEXPR externally_locked(mutex_type& mtx, const T& obj) : + obj_(obj), mtx_(&mtx) + { + } + + /** + * Requires: T is a model of Movable. + * Effects: Constructs an externally locked object copying the cloaked type. + */ + BOOST_CONSTEXPR externally_locked(mutex_type& mtx, BOOST_THREAD_RV_REF(T) obj) : + obj_(move(obj)), mtx_(&mtx) + { + } + + /** + * Requires: T is a model of DefaultConstructible. + * Effects: Constructs an externally locked object initializing the cloaked type with the default constructor. + */ + externally_locked(mutex_type& mtx) : + obj_(), mtx_(&mtx) + { + } + + /** + * Move constructor + */ + externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) : + obj_(move(rhs.obj_)), mtx_(rhs.mtx_) + { + rhs.mtx_=0; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME is not defined and the lk parameter doesn't satisfy the preconditions + */ + T& get(strict_lock& lk) + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + const T& get(strict_lock& lk) const + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + template + T& get(nested_strict_lock& lk) + { + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + template + const T& get(nested_strict_lock& lk) const + { + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return obj_; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME is not defined and the lk parameter doesn't satisfy the preconditions + */ + template + T& get(Lock& lk) + { + BOOST_CONCEPT_ASSERT(( StrictLock )); + BOOST_STATIC_ASSERT( (is_strict_lock::value)); /*< lk is a strict lock "sur parolle" >*/ + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(), lock_error() ); /*< run time check throw if no locked >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + + return obj_; + } + + mutex_type* mutex() + { + return mtx_; + } + + // modifiers + + void lock() + { + mtx_->lock(); + } + void unlock() + { + mtx_->unlock(); + } + bool try_lock() + { + return mtx_->try_lock(); + } + // todo add time related functions + + private: + T obj_; + mutex_type* mtx_; + }; + //] + + /** + * externally_locked specialization for T& that cloaks an reference to an object of type T, and actually + * provides full access to that object through the get and set member functions, provided you + * pass a reference to a strict lock object. + */ + + //[externally_locked_ref + template + class externally_locked + { + //BOOST_CONCEPT_ASSERT(( CopyConstructible )); + BOOST_CONCEPT_ASSERT(( BasicLockable )); + + public: + typedef MutexType mutex_type; + + BOOST_THREAD_MOVABLE_ONLY( externally_locked ) + + /** + * Effects: Constructs an externally locked object storing the cloaked reference object. + */ + externally_locked(T& obj, mutex_type& mtx) : + obj_(&obj), mtx_(&mtx) + { + } + + /// move constructor + externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) : + obj_(rhs.obj_), mtx_(rhs.mtx_) + { + rhs.obj_=0; + rhs.mtx_=0; + } + + void swap(externally_locked& rhs) + { + swap(obj_, rhs.obj_); + swap(mtx_, rhs.mtx_); + } + /** + * Requires: The lk parameter must be locking the associated mtx. + * + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME is not defined and the lk parameter doesn't satisfy the preconditions + */ + T& get(strict_lock const& lk) + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + const T& get(strict_lock const& lk) const + { + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + template + T& get(nested_strict_lock const& lk) + { + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + template + const T& get(nested_strict_lock const& lk) const + { + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME is not defined and the lk parameter doesn't satisfy the preconditions + */ + template + T& get(Lock const& lk) + { + BOOST_CONCEPT_ASSERT(( StrictLock )); + BOOST_STATIC_ASSERT( (is_strict_lock::value)); /*< lk is a strict lock "sur parolle" >*/ + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(), lock_error() ); /*< run time check throw if no locked >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + + /** + * Requires: The lk parameter must be locking the associated mtx. + * Returns: The address of the cloaked object.. + * + * Throws: lock_error if BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME is not defined and the lk parameter doesn't satisfy the preconditions + */ + template + T const& get(Lock const& lk) const + { + BOOST_CONCEPT_ASSERT(( StrictLock )); + BOOST_STATIC_ASSERT( (is_strict_lock::value)); /*< lk is a strict lock "sur parolle" >*/ + BOOST_STATIC_ASSERT( (is_same::value)); /*< that locks the same type >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(), lock_error() ); /*< run time check throw if no locked >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/ + return *obj_; + } + mutex_type* mutex() + { + return mtx_; + } + + void lock() + { + mtx_->lock(); + } + void unlock() + { + mtx_->unlock(); + } + bool try_lock() + { + return mtx_->try_lock(); + } + // todo add time related functions + + protected: + T* obj_; + mutex_type* mtx_; + }; + //] + + template + void swap(externally_locked & lhs, externally_locked & rhs) + { + lhs.swap(rhs); + } + +} + +#include + +#endif // header diff --git a/include/boost/thread/externally_locked_stream.hpp b/include/boost/thread/externally_locked_stream.hpp new file mode 100644 index 00000000..23f5cee4 --- /dev/null +++ b/include/boost/thread/externally_locked_stream.hpp @@ -0,0 +1,149 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_HPP +#define BOOST_THREAD_EXTERNALLY_LOCKED_HPP + +#include + +#include +#include + +#include + +namespace boost +{ + + static recursive_mutex& terminal_mutex() + { + static recursive-mutex mtx; + return mtx; + } + + template + class externally_locked_stream; + + template + class stream_guard + { + stream_guard(externally_locked_stream& mtx, adopt_lock_t) + : mtx_(mtx) + { + } + + Stream& get() const + { + mtx_.get(*this); + } + + friend class externally_locked_stream; + public: + typedef typename externally_locked_stream::mutex_type mutex_type; + + BOOST_THREAD_NO_COPYABLE( externally_locked_stream ) + + stream_guard(externally_locked_stream& mtx) + : mtx_(mtx) + { + mtx.lock(); + } + + ~stream_guard() + { + mtx_.unlock(); + } + + + private: + externally_locked_stream& mtx_; + }; + + template + struct is_strict_lock_sur_parolle > : true_type + { + }; + + /** + * externally_locked_stream_stream cloaks a reference to an stream of type Stream, and actually + * provides full access to that object through the get and set member functions, provided you + * pass a reference to a strict lock object. + */ + + //[externally_locked_stream + template + class externally_locked_stream: public externally_locked + { + typedef externally_locked base_type; + public: + /** + * Effects: Constructs an externally locked object storing the cloaked reference object. + */ + externally_locked_stream(Stream& stream, recursive_mutex& mtx) : + base_type(stream, mtx) + { + } + + + stream_guard hold() + { + return stream_guard(*this); + } + + }; +//] + + template + const stream_guard& operator<<(const stream_guard& lck, T arg) + { + lck.get() << arg; + return lck; + } + + template + const stream_guard& operator<<(const stream_guard& lck, + Stream& (*arg)(Stream&)) + { + lck.get() << arg; + return lck; + } + + template + const stream_guard& operator>>(const stream_guard& lck, T& arg) + { + lck.get() >> arg; + return lck; + } + + template + stream_guard operator<<(externally_locked_stream& mtx, T arg) + { + mtx.lock(); + mtx.get() << arg; + return stream_guard(mtx, adopt_lock); + } + + template + stream_guard operator<<(externally_locked_stream& mtx, + Stream& (*arg)(Stream&)) + { + mtx.lock(); + mtx.get() << arg; + return stream_guard(mtx, adopt_lock); + } + + template + stream_guard operator>>(externally_locked_stream& mtx, T& arg) + { + mtx.lock(); + mtx.get() >> arg; + return stream_guard(mtx, adopt_lock); + } + +} + +#include + +#endif // header diff --git a/include/boost/thread/future.hpp b/include/boost/thread/future.hpp index 6bf5cf6a..69816a3a 100644 --- a/include/boost/thread/future.hpp +++ b/include/boost/thread/future.hpp @@ -18,14 +18,17 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include #include -#include +#include #include #include #include @@ -36,10 +39,12 @@ #include #include #include +#include #include #include #include #include + #include #ifdef BOOST_THREAD_USES_CHRONO #include @@ -58,14 +63,14 @@ #define BOOST_THREAD_FUTURE unique_future #endif - namespace boost { + //enum class future_errc BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc) { - broken_promise, + broken_promise = 1, future_already_retrieved, promise_already_satisfied, no_state @@ -205,29 +210,92 @@ namespace boost namespace future_state { - enum state { uninitialized, waiting, ready, moved }; + enum state { uninitialized, waiting, ready, moved, deferred }; } namespace detail { - struct future_object_base +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + struct future_continuation_base { + future_continuation_base() {} + virtual ~future_continuation_base() {} + + virtual void do_continuation(boost::unique_lock& ) {}; + private: + future_continuation_base(future_continuation_base const&); + future_continuation_base& operator=(future_continuation_base const&); + }; + + template + struct future_continuation; + +#endif + + struct relocker + { + boost::unique_lock& lock_; + bool unlocked_; + + relocker(boost::unique_lock& lk): + lock_(lk) + { + lock_.unlock(); + unlocked_=true; + } + ~relocker() + { + if (unlocked_) { + lock_.lock(); + } + } + void lock() { + if (unlocked_) { + lock_.lock(); + unlocked_=false; + } + } + private: + relocker& operator=(relocker const&); + }; + + struct future_object_base : enable_shared_from_this + { + boost::exception_ptr exception; bool done; + bool is_deferred_; + launch policy_; + bool is_constructed; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS bool thread_was_interrupted; +#endif boost::mutex mutex; boost::condition_variable waiters; typedef std::list waiter_list; waiter_list external_waiters; boost::function callback; - +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + shared_ptr continuation_ptr; +#endif future_object_base(): done(false), - thread_was_interrupted(false) + is_deferred_(false), + policy_(launch::any), + is_constructed(false) +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + , thread_was_interrupted(false) +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + , continuation_ptr() +#endif {} virtual ~future_object_base() {} + void set_deferred() {is_deferred_ = true;} + void set_launch_policy(launch policy) {policy_ = policy;} + waiter_list::iterator register_external_waiter(boost::condition_variable_any& cv) { boost::unique_lock lock(mutex); @@ -241,7 +309,28 @@ namespace boost external_waiters.erase(it); } - void mark_finished_internal() +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void do_continuation(boost::unique_lock& lock) + { + if (continuation_ptr) { + continuation_ptr->do_continuation(lock); + } + } +#else + void do_continuation(boost::unique_lock&) + { + } +#endif +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + void set_continuation_ptr(future_continuation_base* continuation, boost::unique_lock& lock) + { + continuation_ptr.reset(continuation); + if (done) { + do_continuation(lock); + } + } +#endif + void mark_finished_internal(boost::unique_lock& lock) { done=true; waiters.notify_all(); @@ -250,24 +339,13 @@ namespace boost { (*it)->notify_all(); } + do_continuation(lock); } - - struct relocker + void make_ready() { - boost::unique_lock& lock; - - relocker(boost::unique_lock& lock_): - lock(lock_) - { - lock.unlock(); - } - ~relocker() - { - lock.lock(); - } - private: - relocker& operator=(relocker const&); - }; + boost::unique_lock lock(mutex); + mark_finished_internal(lock); + } void do_callback(boost::unique_lock& lock) { @@ -280,27 +358,49 @@ namespace boost } + void wait_internal(boost::unique_lock &lock, bool rethrow=true) + { + do_callback(lock); + //if (!done) // fixme why this doesn't works? + { + if (is_deferred_) + { + is_deferred_=false; + execute(lock); + //lock.unlock(); + } + else + { + while(!done) + { + waiters.wait(lock); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + if(rethrow && thread_was_interrupted) + { + throw boost::thread_interrupted(); + } +#endif + if(rethrow && exception) + { + boost::rethrow_exception(exception); + } + } + } + } void wait(bool rethrow=true) { boost::unique_lock lock(mutex); - do_callback(lock); - while(!done) - { - waiters.wait(lock); - } - if(rethrow && thread_was_interrupted) - { - throw boost::thread_interrupted(); - } - if(rethrow && exception) - { - boost::rethrow_exception(exception); - } + wait_internal(lock, rethrow); } +#if defined BOOST_THREAD_USES_DATETIME bool timed_wait_until(boost::system_time const& target_time) { boost::unique_lock lock(mutex); + if (is_deferred_) + return false; + do_callback(lock); while(!done) { @@ -312,7 +412,7 @@ namespace boost } return true; } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -320,6 +420,8 @@ namespace boost wait_until(const chrono::time_point& abs_time) { boost::unique_lock lock(mutex); + if (is_deferred_) + return future_status::deferred; do_callback(lock); while(!done) { @@ -332,31 +434,83 @@ namespace boost return future_status::ready; } #endif - void mark_exceptional_finish_internal(boost::exception_ptr const& e) + void mark_exceptional_finish_internal(boost::exception_ptr const& e, boost::unique_lock& lock) { exception=e; - mark_finished_internal(); + mark_finished_internal(lock); } void mark_exceptional_finish() { - boost::lock_guard lock(mutex); - mark_exceptional_finish_internal(boost::current_exception()); + boost::unique_lock lock(mutex); + mark_exceptional_finish_internal(boost::current_exception(), lock); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void mark_interrupted_finish() { - boost::lock_guard lock(mutex); + boost::unique_lock lock(mutex); thread_was_interrupted=true; - mark_finished_internal(); + mark_finished_internal(lock); + } + void set_interrupted_at_thread_exit() + { + unique_lock lk(mutex); + thread_was_interrupted=true; + if (has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } +#endif + void set_exception_at_thread_exit(exception_ptr e) + { + unique_lock lk(mutex); + if (has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + exception=e; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); } bool has_value() { boost::lock_guard lock(mutex); - return done && !(exception || thread_was_interrupted); + return done && !(exception +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + || thread_was_interrupted +#endif + ); + } + bool has_value(unique_lock& ) + { + return done && !(exception +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + || thread_was_interrupted +#endif + ); } bool has_exception() { boost::lock_guard lock(mutex); - return done && (exception || thread_was_interrupted); + return done && (exception +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + || thread_was_interrupted +#endif + ); + } + bool has_exception(unique_lock&) + { + return done && (exception +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + || thread_was_interrupted +#endif + ); + } + void is_deferred() {is_deferred_ = true;} + + launch launch_policy() const BOOST_NOEXCEPT + { + return policy_; } template @@ -364,6 +518,7 @@ namespace boost { callback=boost::bind(f,boost::ref(*u)); } + virtual void execute(boost::unique_lock&) {} private: future_object_base(future_object_base const&); @@ -385,8 +540,8 @@ namespace boost typedef typename boost::mpl::if_,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; #else typedef T& source_reference_type; - typedef typename boost::mpl::if_,BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; - typedef typename boost::mpl::if_,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; + typedef typename boost::mpl::if_,BOOST_THREAD_RV_REF(T),T const&>::type rvalue_source_type; + typedef typename boost::mpl::if_,BOOST_THREAD_RV_REF(T),T>::type move_dest_type; #endif typedef const T& shared_future_get_result_type; @@ -447,6 +602,7 @@ namespace boost }; + // Used to create stand-alone futures template struct future_object: detail::future_object_base @@ -463,30 +619,35 @@ namespace boost result(0) {} - void mark_finished_with_result_internal(source_reference_type result_) + ~future_object() { - future_traits::init(result,result_); - mark_finished_internal(); } - void mark_finished_with_result_internal(rvalue_source_type result_) + void mark_finished_with_result_internal(source_reference_type result_, boost::unique_lock& lock) + { + future_traits::init(result,result_); + mark_finished_internal(lock); + } + + void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock& lock) { future_traits::init(result,static_cast(result_)); - mark_finished_internal(); + mark_finished_internal(lock); } void mark_finished_with_result(source_reference_type result_) { - boost::lock_guard lock(mutex); - mark_finished_with_result_internal(result_); + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(result_, lock); } void mark_finished_with_result(rvalue_source_type result_) { - boost::lock_guard lock(mutex); - mark_finished_with_result_internal(static_cast(result_)); + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(static_cast(result_), lock); } + move_dest_type get() { wait(); @@ -499,6 +660,7 @@ namespace boost return static_cast(*result); } + // todo move this to detail::future_object_base future_state::state get_state() { boost::lock_guard guard(mutex); @@ -512,6 +674,130 @@ namespace boost } } + + void set_value_at_thread_exit(const T & result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + future_traits::init(result,result_); + this->is_constructed = true; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } + void set_value_at_thread_exit(BOOST_THREAD_RV_REF(T) result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + throw_exception(promise_already_satisfied()); + result.reset(new T(boost::move(result_))); + //future_traits::init(result,static_cast(result_)); + this->is_constructed = true; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } + + + private: + future_object(future_object const&); + future_object& operator=(future_object const&); + }; + + template + struct future_object: + detail::future_object_base + { + typedef typename future_traits::storage_type storage_type; + typedef typename future_traits::source_reference_type source_reference_type; + typedef typename future_traits::rvalue_source_type rvalue_source_type; + typedef typename future_traits::move_dest_type move_dest_type; + typedef typename future_traits::shared_future_get_result_type shared_future_get_result_type; + + T* result; + + future_object(): + result(0) + {} + + ~future_object() + { + } + + void mark_finished_with_result_internal(T& result_, boost::unique_lock& lock) + { + //future_traits::init(result,result_); + result= &result_; + mark_finished_internal(lock); + } + +// void mark_finished_with_result_internal(rvalue_source_type result_, boost::unique_lock& lock) +// { +// future_traits::init(result,static_cast(result_)); +// mark_finished_internal(lock); +// } + + void mark_finished_with_result(T& result_) + { + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(result_, lock); + } + +// void mark_finished_with_result(rvalue_source_type result_) +// { +// boost::unique_lock lock(mutex); +// mark_finished_with_result_internal(static_cast(result_), lock); +// } + + + T& get() + { + wait(); + //return static_cast(*result); + return *result; + } + + T& get_sh() + { + wait(); + //return static_cast(*result); + return *result; + } + + // todo move this to detail::future_object_base + future_state::state get_state() + { + boost::lock_guard guard(mutex); + if(!done) + { + return future_state::waiting; + } + else + { + return future_state::ready; + } + } + + void set_value_at_thread_exit(T& result_) + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + throw_exception(promise_already_satisfied()); + //future_traits::init(result,result_); + result= &result_; + this->is_constructed = true; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } +// void set_value_at_thread_exit(rvalue_source_type result_) +// { +// unique_lock lk(this->mutex); +// if (this->has_value()) +// throw_exception(promise_already_satisfied()); +// future_traits::init(result,static_cast(result_)); +// this->is_constructed = true; +// get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); +// } + + private: future_object(future_object const&); future_object& operator=(future_object const&); @@ -526,25 +812,26 @@ namespace boost future_object() {} - void mark_finished_with_result_internal() + void mark_finished_with_result_internal(boost::unique_lock& lock) { - mark_finished_internal(); + mark_finished_internal(lock); } void mark_finished_with_result() { - boost::lock_guard lock(mutex); - mark_finished_with_result_internal(); + boost::unique_lock lock(mutex); + mark_finished_with_result_internal(lock); } void get() { - wait(); + this->wait(); } void get_sh() { wait(); } + // todo move this to detail::future_object_base future_state::state get_state() { boost::lock_guard guard(mutex); @@ -557,11 +844,176 @@ namespace boost return future_state::ready; } } + void set_value_at_thread_exit() + { + unique_lock lk(this->mutex); + if (this->has_value(lk)) + { + throw_exception(promise_already_satisfied()); + } + this->is_constructed = true; + get_current_thread_data()->make_ready_at_thread_exit(shared_from_this()); + } private: future_object(future_object const&); future_object& operator=(future_object const&); }; + /// future_async_object + template + struct future_async_object: future_object + { + typedef future_object base_type; + boost::thread thr_; + + public: + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + explicit future_async_object(Fp&& f) + : + #else + explicit future_async_object(BOOST_THREAD_FWD_REF(Fp) f) + : + #endif + thr_(&future_async_object::run, this, boost::forward(f)) + { + } + + ~future_async_object() + { + thr_.join(); + } + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + static void run(future_async_object* that, Fp&& f) +#else + static void run(future_async_object* that, BOOST_THREAD_FWD_REF(Fp) f) +#endif + { + try + { + that->mark_finished_with_result(f()); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + that->mark_interrupted_finish(); + } +#endif + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; + + template + struct future_async_object: public future_object + { + typedef future_object base_type; + boost::thread thr_; + + public: + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + explicit future_async_object(Fp&& f) + : + #else + explicit future_async_object(BOOST_THREAD_FWD_REF(Fp) f) + : + #endif + thr_(&future_async_object::run, this, boost::forward(f)) + { + } + + ~future_async_object() + { + thr_.join(); + } + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + static void run(future_async_object* that, Fp&& f) +#else + static void run(future_async_object* that, BOOST_THREAD_FWD_REF(Fp) f) +#endif + { + try + { + f(); + that->mark_finished_with_result(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + that->mark_interrupted_finish(); + } +#endif + catch(...) + { + that->mark_exceptional_finish(); + } + } + }; + /// future_deferred_object + template + struct future_deferred_object: future_object + { + typedef future_object base_type; + Fp func_; + + public: + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + explicit future_deferred_object(Fp&& f) + : func_(boost::forward(f)) + #else + explicit future_deferred_object(Fp f) + : func_(f) + #endif + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lck) { + try + { + this->mark_finished_with_result_internal(func_(), lck); + } + catch (...) + { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + + template + struct future_deferred_object: future_object + { + typedef future_object base_type; + Fp func_; + + public: + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + explicit future_deferred_object(Fp&& f) + : func_(boost::forward(f)) + #else + explicit future_deferred_object(Fp f) + : func_(f) + #endif + { + this->set_deferred(); + } + + virtual void execute(boost::unique_lock& lck) { + try + { + func_(); + this->mark_finished_with_result_internal(lck); + } + catch (...) + { + this->mark_exceptional_finish_internal(current_exception(), lck); + } + } + }; + // template // struct future_object_alloc: public future_object // { @@ -589,18 +1041,17 @@ namespace boost count_type index_): future_(a_future),wait_iterator(wait_iterator_),index(index_) {} - }; struct all_futures_lock { #ifdef _MANAGED - typedef std::ptrdiff_t count_type_portable; + typedef std::ptrdiff_t count_type_portable; #else - typedef count_type count_type_portable; + typedef count_type count_type_portable; #endif - count_type_portable count; - boost::scoped_array > locks; + count_type_portable count; + boost::scoped_array > locks; all_futures_lock(std::vector& futures): count(futures.size()),locks(new boost::unique_lock[count]) @@ -610,7 +1061,7 @@ namespace boost #if defined __DECCXX || defined __SUNPRO_CC || defined __hpux locks[i]=boost::unique_lock(futures[i].future_->mutex).move(); #else - locks[i]=boost::unique_lock(futures[i].future_->mutex); + locks[i]=boost::unique_lock(futures[i].future_->mutex); // TODO shouldn't be moved explicitly #endif } } @@ -805,70 +1256,53 @@ namespace boost template class packaged_task; - template - class BOOST_THREAD_FUTURE + namespace detail { - private: + /// Common implementation for all the futures independently of the return type + class base_future + { + //BOOST_THREAD_MOVABLE(base_future) + + }; + /// Common implementation for future and shared_future. + template + class basic_future : public base_future + { + protected: typedef boost::shared_ptr > future_ptr; future_ptr future_; - friend class shared_future; - friend class promise; - friend class packaged_task; - friend class detail::future_waiter; + basic_future(future_ptr a_future): + future_(a_future) + { + } + // Copy construction from a shared_future + explicit basic_future(const shared_future&) BOOST_NOEXCEPT; - typedef typename detail::future_traits::move_dest_type move_dest_type; - - BOOST_THREAD_FUTURE(future_ptr a_future): - future_(a_future) - {} - - public: - BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + public: typedef future_state::state state; - BOOST_THREAD_FUTURE() - {} + BOOST_THREAD_MOVABLE(basic_future) + basic_future(): future_() {} + ~basic_future() {} - ~BOOST_THREAD_FUTURE() - {} - - BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: - future_(BOOST_THREAD_RV(other).future_) + basic_future(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT: + future_(BOOST_THREAD_RV(other).future_) { BOOST_THREAD_RV(other).future_.reset(); } - - BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT + basic_future& operator=(BOOST_THREAD_RV_REF(basic_future) other) BOOST_NOEXCEPT { future_=BOOST_THREAD_RV(other).future_; BOOST_THREAD_RV(other).future_.reset(); return *this; } - - shared_future share() + void swap(basic_future& that) BOOST_NOEXCEPT { - return shared_future(::boost::move(*this)); + future_.swap(that.future_); } - - void swap(BOOST_THREAD_FUTURE& other) - { - future_.swap(other.future_); - } - - // retrieving the value - move_dest_type get() - { - if(!future_) - { - boost::throw_exception(future_uninitialized()); - } - - return future_->get(); - } - // functions to check state, and wait for ready state get_state() const BOOST_NOEXCEPT { @@ -894,6 +1328,12 @@ namespace boost return future_ && future_->has_value(); } + launch launch_policy() const BOOST_NOEXCEPT + { + if ( future_ ) return future_->launch_policy(); + else return launch(launch::any); + } + bool valid() const BOOST_NOEXCEPT { return future_ != 0; @@ -909,6 +1349,7 @@ namespace boost future_->wait(false); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_wait(Duration const& rel_time) const { @@ -923,6 +1364,7 @@ namespace boost } return future_->timed_wait_until(abs_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template future_status @@ -942,30 +1384,166 @@ namespace boost return future_->wait_until(abs_time); } #endif + + }; + + } // detail + BOOST_THREAD_DCL_MOVABLE_BEG(R) detail::basic_future BOOST_THREAD_DCL_MOVABLE_END + + namespace detail + { + template + BOOST_THREAD_FUTURE + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + make_future_async_object(Fp&& f); + #else + make_future_async_object(BOOST_THREAD_FWD_REF(Fp) f); + #endif + + template + BOOST_THREAD_FUTURE + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + make_future_deferred_object(Fp&& f); + #else + make_future_deferred_object(BOOST_THREAD_FWD_REF(Fp) f); + #endif + } + + template + class BOOST_THREAD_FUTURE : public detail::basic_future + { + private: + typedef detail::basic_future base_type; + typedef typename base_type::future_ptr future_ptr; + + friend class shared_future; + friend class promise; +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + template + friend struct detail::future_continuation; +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template friend class packaged_task; // todo check if this works in windows +#else + friend class packaged_task; +#endif + friend class detail::future_waiter; + + template + friend BOOST_THREAD_FUTURE + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + detail::make_future_async_object(Fp&& f); + #else + detail::make_future_async_object(BOOST_THREAD_FWD_REF(Fp) f); + #endif + + template + friend BOOST_THREAD_FUTURE + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + detail::make_future_deferred_object(Fp&& f); + #else + detail::make_future_deferred_object(BOOST_THREAD_FWD_REF(Fp) f); + #endif + + typedef typename detail::future_traits::move_dest_type move_dest_type; + + BOOST_THREAD_FUTURE(future_ptr a_future): + base_type(a_future) + { + } + + public: + BOOST_THREAD_MOVABLE_ONLY(BOOST_THREAD_FUTURE) + typedef future_state::state state; + + BOOST_THREAD_FUTURE() {} + + ~BOOST_THREAD_FUTURE() {} + + BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT: + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) + { + } + + BOOST_THREAD_FUTURE& operator=(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE) other) BOOST_NOEXCEPT + { + base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); + return *this; + } + + shared_future share() + { + return shared_future(::boost::move(*this)); + } + + void swap(BOOST_THREAD_FUTURE& other) + { + static_cast(this)->swap(other); + } + + // retrieving the value + move_dest_type get() + { + if(!this->future_) + { + boost::throw_exception(future_uninitialized()); + } +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + future_ptr fut_=this->future_; + this->future_.reset(); + return fut_->get(); +#else + return this->future_->get(); +#endif + } + + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + +// template +// auto then(F&& func) -> BOOST_THREAD_FUTURE; + +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + template + inline BOOST_THREAD_FUTURE then(RF(*func)(BOOST_THREAD_FUTURE&)); + template + inline BOOST_THREAD_FUTURE then(launch policy, RF(*func)(BOOST_THREAD_FUTURE&)); +#endif + template + inline BOOST_THREAD_FUTURE::type> + then(BOOST_THREAD_RV_REF(F) func); + template + inline BOOST_THREAD_FUTURE::type> + then(launch policy, BOOST_THREAD_RV_REF(F) func); +#endif }; BOOST_THREAD_DCL_MOVABLE_BEG(T) BOOST_THREAD_FUTURE BOOST_THREAD_DCL_MOVABLE_END template - class shared_future + class shared_future : public detail::basic_future { - typedef boost::shared_ptr > future_ptr; - future_ptr future_; + typedef detail::basic_future base_type; + typedef typename base_type::future_ptr future_ptr; friend class detail::future_waiter; friend class promise; - friend class packaged_task; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template friend class packaged_task;// todo check if this works in windows +#else + friend class packaged_task; +#endif shared_future(future_ptr a_future): - future_(a_future) + base_type(a_future) {} public: BOOST_THREAD_MOVABLE(shared_future) shared_future(shared_future const& other): - future_(other.future_) + base_type(other) {} typedef future_state::state state; @@ -978,125 +1556,63 @@ namespace boost shared_future& operator=(shared_future const& other) { - future_=other.future_; + shared_future(other).swap(*this); return *this; } shared_future(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT : - future_(BOOST_THREAD_RV(other).future_) + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) { BOOST_THREAD_RV(other).future_.reset(); } - shared_future(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT : - future_(BOOST_THREAD_RV(other).future_) + shared_future(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE ) other) BOOST_NOEXCEPT : + base_type(boost::move(static_cast(BOOST_THREAD_RV(other)))) { - BOOST_THREAD_RV(other).future_.reset(); } + shared_future& operator=(BOOST_THREAD_RV_REF(shared_future) other) BOOST_NOEXCEPT { - future_.swap(BOOST_THREAD_RV(other).future_); - BOOST_THREAD_RV(other).future_.reset(); + base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); return *this; } - shared_future& operator=(BOOST_THREAD_RV_REF_BEG BOOST_THREAD_FUTURE BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT + shared_future& operator=(BOOST_THREAD_RV_REF( BOOST_THREAD_FUTURE ) other) BOOST_NOEXCEPT { - future_.swap(BOOST_THREAD_RV(other).future_); - BOOST_THREAD_RV(other).future_.reset(); + base_type::operator=(boost::move(static_cast(BOOST_THREAD_RV(other)))); + //shared_future(boost::move(other)).swap(*this); + //this->future_.swap(BOOST_THREAD_RV(other).future_); + //BOOST_THREAD_RV(other).future_.reset(); return *this; } void swap(shared_future& other) BOOST_NOEXCEPT { - future_.swap(other.future_); + static_cast(this)->swap(other); } // retrieving the value typename detail::future_object::shared_future_get_result_type get() { - if(!future_) + if(!this->future_) { boost::throw_exception(future_uninitialized()); } - return future_->get_sh(); + return this->future_->get_sh(); } - // functions to check state, and wait for ready - state get_state() const BOOST_NOEXCEPT - { - if(!future_) - { - return future_state::uninitialized; - } - return future_->get_state(); - } - - bool valid() const BOOST_NOEXCEPT - { - return future_ != 0; - } - - bool is_ready() const BOOST_NOEXCEPT - { - return get_state()==future_state::ready; - } - - bool has_exception() const BOOST_NOEXCEPT - { - return future_ && future_->has_exception(); - } - - bool has_value() const BOOST_NOEXCEPT - { - return future_ && future_->has_value(); - } - - void wait() const - { - if(!future_) - { - boost::throw_exception(future_uninitialized()); - } - future_->wait(false); - } - - template - bool timed_wait(Duration const& rel_time) const - { - return timed_wait_until(boost::get_system_time()+rel_time); - } - - bool timed_wait_until(boost::system_time const& abs_time) const - { - if(!future_) - { - boost::throw_exception(future_uninitialized()); - } - return future_->timed_wait_until(abs_time); - } -#ifdef BOOST_THREAD_USES_CHRONO - - template - future_status - wait_for(const chrono::duration& rel_time) const - { - return wait_until(chrono::steady_clock::now() + rel_time); - - } - template - future_status - wait_until(const chrono::time_point& abs_time) const - { - if(!future_) - { - boost::throw_exception(future_uninitialized()); - } - return future_->wait_until(abs_time); - } -#endif }; BOOST_THREAD_DCL_MOVABLE_BEG(T) shared_future BOOST_THREAD_DCL_MOVABLE_END + namespace detail + { + /// Copy construction from a shared_future + template + inline basic_future::basic_future(const shared_future& other) BOOST_NOEXCEPT + : future_(other.future_) + { + } + } + template class promise { @@ -1107,7 +1623,7 @@ namespace boost void lazy_init() { -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY if(!atomic_load(&future_)) { future_ptr blank; @@ -1131,7 +1647,7 @@ namespace boost } #endif promise(): -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY future_(), #else future_(new detail::future_object()), @@ -1143,11 +1659,11 @@ namespace boost { if(future_) { - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(!future_->done) { - future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); } } } @@ -1193,41 +1709,63 @@ namespace boost void set_value(typename detail::future_traits::source_reference_type r) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(r); + future_->mark_finished_with_result_internal(r, lock); } // void set_value(R && r); void set_value(typename detail::future_traits::rvalue_source_type r) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(static_cast::rvalue_source_type>(r)); + future_->mark_finished_with_result_internal(static_cast::rvalue_source_type>(r), lock); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p, lock); } // setting the result with deferred notification - //void set_value_at_thread_exit(const R& r); // NOT YET IMPLEMENTED - //void set_value_at_thread_exit(see below); // NOT YET IMPLEMENTED - //void set_exception_at_thread_exit(exception_ptr p); // NOT YET IMPLEMENTED + void set_value_at_thread_exit(const R& r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } + + void set_value_at_thread_exit(BOOST_THREAD_RV_REF(R) r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(boost::move(r)); + } + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } template void set_wait_callback(F f) @@ -1238,6 +1776,148 @@ namespace boost }; + template + class promise + { + typedef boost::shared_ptr > future_ptr; + + future_ptr future_; + bool future_obtained; + + void lazy_init() + { +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + if(!atomic_load(&future_)) + { + future_ptr blank; + atomic_compare_exchange(&future_,&blank,future_ptr(new detail::future_object)); + } +#endif + } + + public: + BOOST_THREAD_MOVABLE_ONLY(promise) +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + template + promise(boost::allocator_arg_t, Allocator a) + { + typedef typename Allocator::template rebind >::other A2; + A2 a2(a); + typedef thread_detail::allocator_destructor D; + + future_ = future_ptr(::new(a2.allocate(1)) detail::future_object(), D(a2, 1) ); + future_obtained = false; + } +#endif + promise(): +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY + future_(), +#else + future_(new detail::future_object()), +#endif + future_obtained(false) + {} + + ~promise() + { + if(future_) + { + boost::unique_lock lock(future_->mutex); + + if(!future_->done) + { + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); + } + } + } + + // Assignment + promise(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT : + future_(BOOST_THREAD_RV(rhs).future_),future_obtained(BOOST_THREAD_RV(rhs).future_obtained) + { + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + } + promise & operator=(BOOST_THREAD_RV_REF(promise) rhs) BOOST_NOEXCEPT + { + future_=BOOST_THREAD_RV(rhs).future_; + future_obtained=BOOST_THREAD_RV(rhs).future_obtained; + BOOST_THREAD_RV(rhs).future_.reset(); + BOOST_THREAD_RV(rhs).future_obtained=false; + return *this; + } + + void swap(promise& other) + { + future_.swap(other.future_); + std::swap(future_obtained,other.future_obtained); + } + + // Result retrieval + BOOST_THREAD_FUTURE get_future() + { + lazy_init(); + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + if (future_obtained) + { + boost::throw_exception(future_already_retrieved()); + } + future_obtained=true; + return BOOST_THREAD_FUTURE(future_); + } + + void set_value(R& r) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_finished_with_result_internal(r, lock); + } + + void set_exception(boost::exception_ptr p) + { + lazy_init(); + boost::unique_lock lock(future_->mutex); + if(future_->done) + { + boost::throw_exception(promise_already_satisfied()); + } + future_->mark_exceptional_finish_internal(p, lock); + } + + // setting the result with deferred notification + void set_value_at_thread_exit(R& r) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(r); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); + } + + template + void set_wait_callback(F f) + { + lazy_init(); + future_->set_wait_callback(f,this); + } + + }; template <> class promise { @@ -1248,7 +1928,7 @@ namespace boost void lazy_init() { -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY if(!atomic_load(&future_)) { future_ptr blank; @@ -1272,7 +1952,7 @@ namespace boost } #endif promise(): -#if defined BOOST_THREAD_PROMISE_LAZY +#if defined BOOST_THREAD_PROVIDES_PROMISE_LAZY future_(), #else future_(new detail::future_object), @@ -1284,11 +1964,11 @@ namespace boost { if(future_) { - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(!future_->done) { - future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise())); + future_->mark_exceptional_finish_internal(boost::copy_exception(broken_promise()), lock); } } } @@ -1337,23 +2017,42 @@ namespace boost void set_value() { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_finished_with_result_internal(); + future_->mark_finished_with_result_internal(lock); } void set_exception(boost::exception_ptr p) { lazy_init(); - boost::lock_guard lock(future_->mutex); + boost::unique_lock lock(future_->mutex); if(future_->done) { boost::throw_exception(promise_already_satisfied()); } - future_->mark_exceptional_finish_internal(p); + future_->mark_exceptional_finish_internal(p,lock); + } + + // setting the result with deferred notification + void set_value_at_thread_exit() + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_value_at_thread_exit(); + } + + void set_exception_at_thread_exit(exception_ptr e) + { + if (future_.get()==0) + { + boost::throw_exception(promise_moved()); + } + future_->set_exception_at_thread_exit(e); } template @@ -1379,8 +2078,20 @@ namespace boost namespace detail { - template - struct task_base: +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template + struct task_base; +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_base: +#else + template + struct task_base: +#endif +#else + template + struct task_base: +#endif detail::future_object { bool started; @@ -1393,7 +2104,13 @@ namespace boost { started=false; } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + virtual void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; + void run(BOOST_THREAD_RV_REF(ArgTypes) ... args) +#else + virtual void do_run()=0; void run() +#endif { { boost::lock_guard lk(this->mutex); @@ -1403,56 +2120,131 @@ namespace boost } started=true; } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + do_run(boost::forward(args)...); +#else do_run(); +#endif + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + virtual void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args)=0; + void apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) +#else + virtual void do_apply()=0; + void apply() +#endif + { + { + boost::lock_guard lk(this->mutex); + if(started) + { + boost::throw_exception(task_already_started()); + } + started=true; + } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + do_apply(boost::forward(args)...); +#else + do_apply(); +#endif } void owner_destroyed() { - boost::lock_guard lk(this->mutex); + boost::unique_lock lk(this->mutex); if(!started) { started=true; - this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise())); + this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise()), lk); } } - - virtual void do_run()=0; }; - - - - template +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + template + struct task_object; +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_object: + task_base +#else + template + struct task_object: + task_base +#endif +#else + template struct task_object: task_base +#endif { private: task_object(task_object&); public: F f; - task_object(F const& f_): - f(f_) - {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES task_object(BOOST_THREAD_RV_REF(F) f_): f(boost::forward(f_)) {} #else + task_object(F const& f_): + f(f_) + {} task_object(BOOST_THREAD_RV_REF(F) f_): - f(boost::move(f_)) + f(boost::move(f_)) // TODO forward {} #endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::forward(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::forward(args)...)); + } +#else void do_run() { try { this->mark_finished_with_result(f()); } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS catch(thread_interrupted& ) { this->mark_interrupted_finish(); } +#endif catch(...) { this->mark_exceptional_finish(); @@ -1460,9 +2252,23 @@ namespace boost } }; - template - struct task_object: - task_base +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_object: + task_base +#else + template + struct task_object: + task_base +#endif +#else + template + struct task_object : + task_base +#endif { private: task_object(task_object&); @@ -1471,55 +2277,146 @@ namespace boost task_object(R (*f_)()): f(f_) {} + + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->set_value_at_thread_exit(f(boost::forward(args)...)); + } +#else + void do_apply() + { + try + { + this->set_value_at_thread_exit(f()); + } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + this->mark_finished_with_result(f(boost::forward(args)...)); + } +#else void do_run() { try { this->mark_finished_with_result(f()); } +#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS catch(thread_interrupted& ) { this->mark_interrupted_finish(); } +#endif catch(...) { this->mark_exceptional_finish(); } } }; +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_object: + task_base +#else template - struct task_object: - task_base + struct task_object: + task_base +#endif +#else + template + struct task_object: + task_base +#endif { private: task_object(task_object&); public: F f; - task_object(F const& f_): - f(f_) - {} #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES task_object(BOOST_THREAD_RV_REF(F) f_): f(boost::forward(f_)) {} #else + task_object(F const& f_): + f(f_) + {} task_object(BOOST_THREAD_RV_REF(F) f_): - f(boost::move(f_)) + f(boost::move(f_)) // TODO forward {} #endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::forward(args)...); +#else + void do_apply() + { + try + { + f(); +#endif + this->set_value_at_thread_exit(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::forward(args)...); +#else void do_run() { try { f(); +#endif this->mark_finished_with_result(); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS catch(thread_interrupted& ) { this->mark_interrupted_finish(); } +#endif catch(...) { this->mark_exceptional_finish(); @@ -1527,9 +2424,21 @@ namespace boost } }; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + struct task_object: + task_base +#else template<> - struct task_object: - task_base + struct task_object: + task_base +#endif +#else + template<> + struct task_object: + task_base +#endif { private: task_object(task_object&); @@ -1538,17 +2447,55 @@ namespace boost task_object(void (*f_)()): f(f_) {} + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_apply(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::forward(args)...); +#else + void do_apply() + { + try + { + f(); +#endif + this->set_value_at_thread_exit(); + } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + catch(thread_interrupted& ) + { + this->set_interrupted_at_thread_exit(); + } +#endif + catch(...) + { + this->set_exception_at_thread_exit(current_exception()); + } + } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void do_run(BOOST_THREAD_RV_REF(ArgTypes) ... args) + { + try + { + f(boost::forward(args)...); +#else void do_run() { try { f(); +#endif this->mark_finished_with_result(); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS catch(thread_interrupted& ) { this->mark_interrupted_finish(); } +#endif catch(...) { this->mark_exceptional_finish(); @@ -1558,12 +2505,30 @@ namespace boost } + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + class packaged_task + { + typedef boost::shared_ptr > task_ptr; + boost::shared_ptr > task; + #else + template + class packaged_task + { + typedef boost::shared_ptr > task_ptr; + boost::shared_ptr > task; + #endif +#else template class packaged_task { - typedef boost::shared_ptr > task_ptr; - boost::shared_ptr > task; + typedef boost::shared_ptr > task_ptr; + boost::shared_ptr > task; +#endif bool future_obtained; + struct dummy; public: typedef R result_type; @@ -1574,73 +2539,186 @@ namespace boost {} // construction and destruction +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) - explicit packaged_task(R(*f)()): - task(new detail::task_object(f)),future_obtained(false) - {} +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + explicit packaged_task(R(*f)(), BOOST_THREAD_FWD_REF(ArgTypes)... args) + { + typedef R(*FR)(BOOST_THREAD_FWD_REF(ArgTypes)...); + typedef detail::task_object task_object_type; + task= task_ptr(new task_object_type(f, boost::forward(args)...)); + future_obtained=false; + } + #else + explicit packaged_task(R(*f)()) + { + typedef R(*FR)(); + typedef detail::task_object task_object_type; + task= task_ptr(new task_object_type(f)); + future_obtained=false; + } + #endif +#else + explicit packaged_task(R(*f)()) + { + typedef R(*FR)(); + typedef detail::task_object task_object_type; + task= task_ptr(new task_object_type(f)); + future_obtained=false; + } +#endif +#endif #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template - explicit packaged_task(BOOST_THREAD_RV_REF(F) f): - task(new detail::task_object::type>::type - >(boost::forward(f))),future_obtained(false) - {} + explicit packaged_task(BOOST_THREAD_RV_REF(F) f + , typename disable_if::type, packaged_task>, dummy* >::type=0 + ) + { + //typedef typename remove_cv::type>::type FR; + typedef F FR; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + #else + typedef detail::task_object task_object_type; + #endif +#else + typedef detail::task_object task_object_type; +#endif + task = task_ptr(new task_object_type(boost::forward(f))); + future_obtained = false; + + } + #else template - explicit packaged_task(F const& f): - task(new detail::task_object(f)),future_obtained(false) - {} + explicit packaged_task(F const& f + , typename disable_if::type, packaged_task>, dummy* >::type=0 + ) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + #else + typedef detail::task_object task_object_type; + #endif +#else + typedef detail::task_object task_object_type; +#endif + task = task_ptr(new task_object_type(f)); + future_obtained=false; + } template - explicit packaged_task(BOOST_THREAD_RV_REF(F) f): - task(new detail::task_object(boost::move(f))),future_obtained(false) - {} + explicit packaged_task(BOOST_THREAD_RV_REF(F) f) + { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + task = task_ptr(new task_object_type(boost::forward(f))); +#else + typedef detail::task_object task_object_type; + task = task_ptr(new task_object_type(boost::move(f))); // TODO forward +#endif +#else + typedef detail::task_object task_object_type; + task = task_ptr(new task_object_type(boost::forward(f))); +#endif + future_obtained=false; + + } #endif #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) template packaged_task(boost::allocator_arg_t, Allocator a, R(*f)()) { typedef R(*FR)(); - typedef typename Allocator::template rebind >::other A2; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + #else + typedef detail::task_object task_object_type; + #endif +#else + typedef detail::task_object task_object_type; +#endif + typedef typename Allocator::template rebind::other A2; A2 a2(a); typedef thread_detail::allocator_destructor D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object(f), D(a2, 1) ); + task = task_ptr(::new(a2.allocate(1)) task_object_type(f), D(a2, 1) ); future_obtained = false; } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES template packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) { - typedef typename remove_cv::type>::type FR; - typedef typename Allocator::template rebind >::other A2; + //typedef typename remove_cv::type>::type FR; + typedef F FR; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + #else + typedef detail::task_object task_object_type; + #endif +#else + typedef detail::task_object task_object_type; +#endif + typedef typename Allocator::template rebind::other A2; A2 a2(a); typedef thread_detail::allocator_destructor D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object(boost::forward(f)), D(a2, 1) ); + task = task_ptr(::new(a2.allocate(1)) task_object_type(boost::forward(f)), D(a2, 1) ); future_obtained = false; } -#else +#else // ! defined BOOST_NO_CXX11_RVALUE_REFERENCES template packaged_task(boost::allocator_arg_t, Allocator a, const F& f) { - typedef typename Allocator::template rebind >::other A2; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + #else + typedef detail::task_object task_object_type; + #endif +#else + typedef detail::task_object task_object_type; +#endif + typedef typename Allocator::template rebind::other A2; A2 a2(a); typedef thread_detail::allocator_destructor D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object(f), D(a2, 1) ); + task = task_ptr(::new(a2.allocate(1)) task_object_type(f), D(a2, 1) ); future_obtained = false; } template packaged_task(boost::allocator_arg_t, Allocator a, BOOST_THREAD_RV_REF(F) f) { - typedef typename Allocator::template rebind >::other A2; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + typedef detail::task_object task_object_type; + #else + typedef detail::task_object task_object_type; + #endif +#else + typedef detail::task_object task_object_type; +#endif + typedef typename Allocator::template rebind::other A2; A2 a2(a); typedef thread_detail::allocator_destructor D; - task = task_ptr(::new(a2.allocate(1)) detail::task_object(boost::move(f)), D(a2, 1) ); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + task = task_ptr(::new(a2.allocate(1)) task_object_type(boost::forward(f)), D(a2, 1) ); +#else + task = task_ptr(::new(a2.allocate(1)) task_object_type(boost::move(f)), D(a2, 1) ); // TODO forward +#endif future_obtained = false; } + #endif //BOOST_NO_CXX11_RVALUE_REFERENCES #endif // BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS @@ -1661,6 +2739,8 @@ namespace boost } packaged_task& operator=(BOOST_THREAD_RV_REF(packaged_task) other) BOOST_NOEXCEPT { + + // todo use forward packaged_task temp(static_cast(other)); swap(temp); return *this; @@ -1687,6 +2767,7 @@ namespace boost // result retrieval BOOST_THREAD_FUTURE get_future() { + if(!task) { boost::throw_exception(task_moved()); @@ -1700,12 +2781,34 @@ namespace boost { boost::throw_exception(future_already_retrieved()); } - return BOOST_THREAD_FUTURE(); + //return BOOST_THREAD_FUTURE(); } // execution +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + void operator()(BOOST_THREAD_RV_REF(ArgTypes)... args) + { + if(!task) + { + boost::throw_exception(task_moved()); + } + task->run(boost::forward(args)...); + } + void make_ready_at_thread_exit(ArgTypes... args) + { + if(!task) + { + boost::throw_exception(task_moved()); + } + if (task->has_value()) + { + boost::throw_exception(promise_already_satisfied()); + } + task->apply(boost::forward(args)...); + } +#else void operator()() { if(!task) @@ -1714,7 +2817,17 @@ namespace boost } task->run(); } - + void make_ready_at_thread_exit() + { + if(!task) + { + boost::throw_exception(task_moved()); + } + if (task->has_value()) + boost::throw_exception(promise_already_satisfied()); + task->apply(); + } +#endif template void set_wait_callback(F f) { @@ -1734,22 +2847,86 @@ namespace boost BOOST_THREAD_DCL_MOVABLE_BEG(T) packaged_task BOOST_THREAD_DCL_MOVABLE_END + namespace detail + { + //////////////////////////////// + // make_future_deferred_object + //////////////////////////////// + template + BOOST_THREAD_FUTURE + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + make_future_deferred_object(Fp&& f) + #else + make_future_deferred_object(BOOST_THREAD_FWD_REF(Fp) f) + #endif + { + shared_ptr > + h(new future_deferred_object(boost::forward(f))); + return BOOST_THREAD_FUTURE(h); + } + //////////////////////////////// + // make_future_async_object + //////////////////////////////// + template + BOOST_THREAD_FUTURE + #if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + make_future_async_object(Fp&& f) + #else + make_future_async_object(BOOST_THREAD_FWD_REF(Fp) f) + #endif + { + shared_ptr > + h(new future_async_object(boost::forward(f))); + return BOOST_THREAD_FUTURE(h); + } + + } + + //////////////////////////////// + // template + // future async(F&&, ArgTypes&&...); + //////////////////////////////// + +#if defined BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + template + BOOST_THREAD_FUTURE + async(launch policy, R(*f)(BOOST_THREAD_FWD_REF(ArgTypes)...), BOOST_THREAD_FWD_REF(ArgTypes)... args) + { + //typedef packaged_task packaged_task_type; + typedef packaged_task packaged_task_type; + #else template BOOST_THREAD_FUTURE async(launch policy, R(*f)()) { - if (int(policy) & int(launch::async)) + typedef packaged_task packaged_task_type; + #endif +#else + template + BOOST_THREAD_FUTURE + async(launch policy, R(*f)()) + { + typedef packaged_task packaged_task_type; +#endif + if (int(policy) & int(launch::async)) { - packaged_task pt( f ); + packaged_task_type pt( f ); BOOST_THREAD_FUTURE ret = pt.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread( boost::move(pt), boost::forward(args)... ).detach(); +#else boost::thread( boost::move(pt) ).detach(); +#endif return ::boost::move(ret); } else if (int(policy) & int(launch::deferred)) { - packaged_task pt( f ); + packaged_task_type pt( f ); BOOST_THREAD_FUTURE ret = pt.get_future(); return ::boost::move(ret); @@ -1763,28 +2940,92 @@ namespace boost BOOST_THREAD_FUTURE async(R(*f)()) { - return async(launch::any, f); + return BOOST_THREAD_MAKE_RV_REF(async(launch(launch::any), f)); } -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - template - BOOST_THREAD_FUTURE::type()>::type> - async(launch policy, BOOST_THREAD_FWD_REF(F) f) - { - typedef typename boost::result_of::type()>::type R; +#endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK + #if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + + template + BOOST_THREAD_FUTURE::type( + typename decay::type... + )>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(ArgTypes)... args) + { + + typedef typename boost::result_of::type( + typename decay::type... + )>::type R; + typedef packaged_task packaged_task_type; + + typedef detail::async_func::type, typename decay::type...> BF; + typedef typename BF::result_type Rp; + + #else + template + BOOST_THREAD_FUTURE::type()>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f) + { + typedef typename boost::result_of::type()>::type R; + typedef packaged_task packaged_task_type; + + typedef detail::async_func::type> BF; + typedef typename BF::result_type Rp; + + #endif +#else + template + BOOST_THREAD_FUTURE::type()>::type> + async(launch policy, BOOST_THREAD_FWD_REF(F) f) + { + typedef typename boost::result_of::type()>::type R; + typedef packaged_task packaged_task_type; + + typedef detail::async_func::type> BF; + typedef typename BF::result_type Rp; +#endif + if (int(policy) & int(launch::async)) { - packaged_task pt( boost::forward(f) ); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + return boost::detail::make_future_async_object( + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(args))... + ) + ); +#else + packaged_task_type pt( boost::forward(f) ); BOOST_THREAD_FUTURE ret = pt.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread( boost::move(pt), boost::forward(args)... ).detach(); // todo forward +#else boost::thread( boost::move(pt) ).detach(); +#endif return ::boost::move(ret); +#endif } else if (int(policy) & int(launch::deferred)) { - packaged_task pt( boost::forward(f) ); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + return boost::detail::make_future_deferred_object( + BF( + thread_detail::decay_copy(boost::forward(f)) + , thread_detail::decay_copy(boost::forward(args))... + ) + ); +#else + BOOST_THREAD_FUTURE ret; + return ::boost::move(ret); +// return boost::detail::make_future_deferred_object( +// BF( +// thread_detail::decay_copy(boost::forward(f)) +// ) +// ); +#endif - BOOST_THREAD_FUTURE ret = pt.get_future(); - return ::boost::move(ret); } else { BOOST_THREAD_FUTURE ret; return ::boost::move(ret); @@ -1794,71 +3035,271 @@ namespace boost BOOST_THREAD_FUTURE::type> async(BOOST_THREAD_RV_REF(F) f) { - return async(launch::any, boost::forward(f)); + return async(launch(launch::any), boost::forward(f)); } -#else -// template -// BOOST_THREAD_FUTURE::type()>::type> -// async(launch policy, F const& f) -// { -// typedef typename boost::result_of::type()>::type R; -// if (int(policy) & int(launch::async)) -// { -// packaged_task pt( f ); -// -// BOOST_THREAD_FUTURE ret = pt.get_future(); -// boost::thread( boost::move(pt) ).detach(); -// return ::boost::move(ret); -// } -// else if (int(policy) & int(launch::deferred)) -// { -// packaged_task pt( f ); -// -// BOOST_THREAD_FUTURE ret = pt.get_future(); -// return ::boost::move(ret); -// } else { -// BOOST_THREAD_FUTURE ret; -// return ::boost::move(ret); -// } -// } -// template -// BOOST_THREAD_FUTURE::type> -// async(F const& f) -// { -// return async(launch::any, f); -// } - template - BOOST_THREAD_FUTURE::type()>::type> - async(launch policy, BOOST_THREAD_FWD_REF(F) f) - { - typedef typename boost::result_of::type()>::type R; - if (int(policy) & int(launch::async)) + //////////////////////////////// + // make_future + //////////////////////////////// + template + BOOST_THREAD_FUTURE::type> make_future(BOOST_THREAD_FWD_REF(T) value) + { + typedef typename decay::type future_type; + promise p; + p.set_value(boost::forward(value)); + return p.get_future(); + } + + + inline BOOST_THREAD_FUTURE make_future() + { + promise p; + return p.get_future(); + + } + + //////////////////////////////// + // make_shared_future + //////////////////////////////// + template + shared_future::type> make_shared_future(BOOST_THREAD_FWD_REF(T) value) + { + typedef typename decay::type future_type; + promise p; + p.set_value(boost::forward(value)); + return p.get_future().share(); + } + + + inline shared_future make_shared_future() + { + promise p; + return p.get_future().share(); + + } + + //////////////////////////////// + // detail::future_continuation + //////////////////////////////// +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + namespace detail + { + template + struct future_continuation : future_continuation_base + { + F& parent; + C continuation; + launch policy_; + promise next; + + future_continuation(F& f, BOOST_THREAD_FWD_REF(C) c) : + parent(f), + continuation(boost::forward(c)), + policy_(f.launch_policy()), + next() + {} + future_continuation(F& f, BOOST_THREAD_FWD_REF(C) c, launch policy) : + parent(f), + continuation(boost::forward(c)), + policy_(policy), + next() + {} + ~future_continuation() + {} + + void do_continuation(boost::unique_lock& lk) { - packaged_task pt( boost::forward(f) ); - - BOOST_THREAD_FUTURE ret = pt.get_future(); - boost::thread( boost::move(pt) ).detach(); - return ::boost::move(ret); + try + { + lk.unlock(); + // fixme what to do depending on inherits_launch_policy_ and policy_? +// if (int(policy_) & int(launch::deferred)) + { + R val = continuation(parent); + next.set_value(boost::move(val)); + } +// else +// { +// BOOST_THREAD_FUTURE f = async(policy_, continuation, boost::ref(parent)); +// R val = f.get(); +// next.set_value(boost::move(val)); +// } + } + catch (...) + { + next.set_exception(boost::current_exception()); + } } - else if (int(policy) & int(launch::deferred)) + private: + + future_continuation(future_continuation const&); + future_continuation& operator=(future_continuation const&); + }; +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + template + struct future_continuation : future_continuation_base + { + F& parent; + CR(*continuation)(F&) ; + launch policy_; + promise next; + + future_continuation(F& f, CR(*c)(F&)) : + parent(f), + continuation(c), + policy_(f.launch_policy()), + next() + {} + future_continuation(F& f, CR(*c)(F&), launch policy) : + parent(f), + continuation(c), + policy_(policy), + next() + {} + ~future_continuation() + {} + + void do_continuation(boost::unique_lock& lk) { - packaged_task pt( boost::forward(f) ); - - BOOST_THREAD_FUTURE ret = pt.get_future(); - return ::boost::move(ret); - } else { - BOOST_THREAD_FUTURE ret; - return ::boost::move(ret); + try + { + lk.unlock(); + // fixme what to do depending on inherits_launch_policy_ and policy_? +// if (int(policy_) & int(launch::deferred)) + { + R val = continuation(parent); + next.set_value(boost::move(val)); + } +// else +// { +// BOOST_THREAD_FUTURE f = async(policy_, continuation, boost::ref(parent)); +// R val = f.get(); +// next.set_value(boost::move(val)); +// } + } + catch (...) + { + next.set_exception(boost::current_exception()); + } } - } - template - BOOST_THREAD_FUTURE::type> - async(BOOST_THREAD_FWD_REF(F) f) + private: + + future_continuation(future_continuation const&); + future_continuation& operator=(future_continuation const&); + }; +#endif + } + + //////////////////////////////// + // template + // auto future::then(F&& func) -> BOOST_THREAD_FUTURE; + //////////////////////////////// + + template + template + inline BOOST_THREAD_FUTURE&)>::type> + BOOST_THREAD_FUTURE::then(launch policy, BOOST_THREAD_RV_REF(F) func) + { + + typedef typename boost::result_of&)>::type future_type; + + if (this->future_) { - return async(launch::any, boost::forward(f)); + boost::unique_lock lock(this->future_->mutex); + detail::future_continuation, future_type, F > *ptr = + new detail::future_continuation, future_type, F>(*this, boost::forward(func), policy); + if (ptr==0) + { + return BOOST_THREAD_FUTURE(); + } + this->future_->set_continuation_ptr(ptr, lock); + return ptr->next.get_future(); } + else + { + // fixme what to do when the future has no associated state? + return BOOST_THREAD_FUTURE(); + } + + } + template + template + inline BOOST_THREAD_FUTURE&)>::type> + BOOST_THREAD_FUTURE::then(BOOST_THREAD_RV_REF(F) func) + { + + typedef typename boost::result_of&)>::type future_type; + + if (this->future_) + { + boost::unique_lock lock(this->future_->mutex); + detail::future_continuation, future_type, F > *ptr = + new detail::future_continuation, future_type, F>(*this, boost::forward(func)); + if (ptr==0) + { + return BOOST_THREAD_FUTURE(); + } + this->future_->set_continuation_ptr(ptr, lock); + return ptr->next.get_future(); + } else { + // fixme what to do when the future has no associated state? + return BOOST_THREAD_FUTURE(); + } + + } +#if defined(BOOST_THREAD_RVALUE_REFERENCES_DONT_MATCH_FUNTION_PTR) + template + template + BOOST_THREAD_FUTURE + BOOST_THREAD_FUTURE::then(RF(*func)(BOOST_THREAD_FUTURE&)) + { + + typedef RF future_type; + + if (this->future_) + { + boost::unique_lock lock(this->future_->mutex); + detail::future_continuation, future_type, RF(*)(BOOST_THREAD_FUTURE&) > *ptr = + new detail::future_continuation, future_type, RF(*)(BOOST_THREAD_FUTURE&)>(*this, func); + if (ptr==0) + { + return BOOST_THREAD_FUTURE(); + } + this->future_->set_continuation_ptr(ptr, lock); + return ptr->next.get_future(); + } else { + // fixme what to do when the future has no associated state? + return BOOST_THREAD_FUTURE(); + } + + } + template + template + BOOST_THREAD_FUTURE + BOOST_THREAD_FUTURE::then(launch policy, RF(*func)(BOOST_THREAD_FUTURE&)) + { + + typedef RF future_type; + + if (this->future_) + { + boost::unique_lock lock(this->future_->mutex); + detail::future_continuation, future_type, RF(*)(BOOST_THREAD_FUTURE&) > *ptr = + new detail::future_continuation, future_type, RF(*)(BOOST_THREAD_FUTURE&)>(*this, func, policy); + if (ptr==0) + { + return BOOST_THREAD_FUTURE(); + } + this->future_->set_continuation_ptr(ptr, lock); + return ptr->next.get_future(); + } else { + // fixme what to do when the future has no associated state? + return BOOST_THREAD_FUTURE(); + } + + } +#endif #endif diff --git a/include/boost/thread/is_locked_by_this_thread.hpp b/include/boost/thread/is_locked_by_this_thread.hpp new file mode 100644 index 00000000..f1427356 --- /dev/null +++ b/include/boost/thread/is_locked_by_this_thread.hpp @@ -0,0 +1,39 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP +#define BOOST_THREAD_IS_LOCKED_BY_THIS_THREAD_HPP + +#include + +#include + +namespace boost +{ + template + class testable_mutex; + + /** + * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise. + * + * This function is used usually to assert the pre-condition when the function can only be called when the mutex + * must be locked by the current thread. + */ + template + bool is_locked_by_this_thread(testable_mutex const& mtx) + { + return mtx.is_locked(); + } + template + bool is_locked_by_this_thread(Lockable const&) + { + return true; + } +} + +#include + +#endif // header diff --git a/include/boost/thread/lock_algorithms.hpp b/include/boost/thread/lock_algorithms.hpp new file mode 100644 index 00000000..7a55f92a --- /dev/null +++ b/include/boost/thread/lock_algorithms.hpp @@ -0,0 +1,468 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_ALGORITHMS_HPP +#define BOOST_THREAD_LOCK_ALGORITHMS_HPP + +#include +#include +#include + +#include +#include + +#include + +namespace boost +{ + namespace detail + { + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (!m2.try_lock()) + { + return 2; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template + unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + boost::unique_lock l1(m1, boost::try_to_lock); + if (!l1) + { + return 1; + } + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock + 1; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2) + { + boost::unique_lock l1(m1); + if (!m2.try_lock()) + { + return 1; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + boost::unique_lock l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + boost::unique_lock l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4)) + { + return failed_lock; + } + l1.release(); + return 0; + } + + template + unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + boost::unique_lock l1(m1); + if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) + { + return failed_lock; + } + l1.release(); + return 0; + } + } + + namespace detail + { + template + struct is_mutex_type_wrapper + { + }; + + template + void lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper ) + { + unsigned const lock_count = 2; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + } + } + } + + template + void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ); + } + + template + void lock(MutexType1& m1, MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(const MutexType1& m1, MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(MutexType1& m1, const MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(const MutexType1& m1, const MutexType2& m2) + { + detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + unsigned const lock_count = 3; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + unsigned const lock_count = 4; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3, m4); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m4, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m4, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + case 3: + lock_first = detail::lock_helper(m4, m1, m2, m3); + if (!lock_first) return; + lock_first = (lock_first + 3) % lock_count; + break; + } + } + } + + template + void lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + unsigned const lock_count = 5; + unsigned lock_first = 0; + for (;;) + { + switch (lock_first) + { + case 0: + lock_first = detail::lock_helper(m1, m2, m3, m4, m5); + if (!lock_first) return; + break; + case 1: + lock_first = detail::lock_helper(m2, m3, m4, m5, m1); + if (!lock_first) return; + lock_first = (lock_first + 1) % lock_count; + break; + case 2: + lock_first = detail::lock_helper(m3, m4, m5, m1, m2); + if (!lock_first) return; + lock_first = (lock_first + 2) % lock_count; + break; + case 3: + lock_first = detail::lock_helper(m4, m5, m1, m2, m3); + if (!lock_first) return; + lock_first = (lock_first + 3) % lock_count; + break; + case 4: + lock_first = detail::lock_helper(m5, m1, m2, m3, m4); + if (!lock_first) return; + lock_first = (lock_first + 4) % lock_count; + break; + } + } + } + + namespace detail + { + template ::value> + struct try_lock_impl_return + { + typedef int type; + }; + + template + struct try_lock_impl_return + { + typedef Iterator type; + }; + + template + int try_lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper ) + { + return ((int) detail::try_lock_internal(m1, m2)) - 1; + } + + template + Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ); + } + + template + typename detail::try_lock_impl_return::type try_lock(MutexType1& m1, MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1, MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(MutexType1& m1, const MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1, const MutexType2& m2) + { + return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper::value>()); + } + + template + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3) + { + return ((int) detail::try_lock_internal(m1, m2, m3)) - 1; + } + + template + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4) + { + return ((int) detail::try_lock_internal(m1, m2, m3, m4)) - 1; + } + + template + int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5) + { + return ((int) detail::try_lock_internal(m1, m2, m3, m4, m5)) - 1; + } + + namespace detail + { + template + struct range_lock_guard + { + Iterator begin; + Iterator end; + + range_lock_guard(Iterator begin_, Iterator end_) : + begin(begin_), end(end_) + { + boost::lock(begin, end); + } + + void release() + { + begin = end; + } + + ~range_lock_guard() + { + for (; begin != end; ++begin) + { + begin->unlock(); + } + } + }; + + template + Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ) + + { + if (begin == end) + { + return end; + } + typedef typename std::iterator_traits::value_type lock_type; + unique_lock guard(*begin, try_to_lock); + + if (!guard.owns_lock()) + { + return begin; + } + Iterator const failed = boost::try_lock(++begin, end); + if (failed == end) + { + guard.release(); + } + + return failed; + } + } + + namespace detail + { + template + void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper ) + { + typedef typename std::iterator_traits::value_type lock_type; + + if (begin == end) + { + return; + } + bool start_with_begin = true; + Iterator second = begin; + ++second; + Iterator next = second; + + for (;;) + { + unique_lock begin_lock(*begin, defer_lock); + if (start_with_begin) + { + begin_lock.lock(); + Iterator const failed_lock = boost::try_lock(next, end); + if (failed_lock == end) + { + begin_lock.release(); + return; + } + start_with_begin = false; + next = failed_lock; + } + else + { + detail::range_lock_guard guard(next, end); + if (begin_lock.try_lock()) + { + Iterator const failed_lock = boost::try_lock(second, next); + if (failed_lock == next) + { + begin_lock.release(); + guard.release(); + return; + } + start_with_begin = false; + next = failed_lock; + } + else + { + start_with_begin = true; + next = second; + } + } + } + } + + } + +} +#include + +#endif diff --git a/include/boost/thread/lock_concepts.hpp b/include/boost/thread/lock_concepts.hpp new file mode 100644 index 00000000..fe453dc3 --- /dev/null +++ b/include/boost/thread/lock_concepts.hpp @@ -0,0 +1,196 @@ +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_LOCK_CONCEPTS_HPP +#define BOOST_THREAD_LOCK_CONCEPTS_HPP + +#include +#include +#include +#include +#include + +#include +#include + +namespace boost +{ + + /** + * BasicLock object supports the basic features + * required to delimit a critical region + * Supports the basic lock, unlock and try_lock functions and + * defines the lock traits + */ + + template + struct BasicLock + { + typedef typename Lk::mutex_type mutex_type; + void cvt_mutex_ptr(mutex_type*); + BOOST_CONCEPT_ASSERT(( BasicLockable )); + + BOOST_CONCEPT_USAGE(BasicLock) + { + const Lk l1(mtx); + Lk l2(mtx, defer_lock); + Lk l3(mtx, adopt_lock); + Lk l4(( Lk())); + Lk l5(( boost::move(l2))); + cvt_mutex_ptr(l1.mutex()); + if (l1.owns_lock()) return; + if (l1) return; + if (!l1) return; + + l2.lock(); + l2.unlock(); + l2.release(); + + } + BasicLock() : + mtx(*static_cast(0)) + {} + private: + BasicLock operator=(BasicLock const&); + mutex_type& mtx; + } + ; + + template + struct Lock + { + BOOST_CONCEPT_ASSERT(( BasicLock )); + typedef typename Lk::mutex_type mutex_type; + BOOST_CONCEPT_ASSERT(( Lockable )); + + BOOST_CONCEPT_USAGE(Lock) + { + Lk l1(mtx, try_to_lock); + if (l1.try_lock()) return; + } + Lock() : + mtx(*static_cast(0)) + {} + private: + Lock operator=(Lock const&); + mutex_type& mtx; + }; + + template + struct TimedLock + { + BOOST_CONCEPT_ASSERT(( Lock )); + typedef typename Lk::mutex_type mutex_type; + BOOST_CONCEPT_ASSERT(( TimedLockable )); + + BOOST_CONCEPT_USAGE(TimedLock) + { + const Lk l1(mtx, t); + Lk l2(mtx, d); + if (l1.try_lock_until(t)) return; + if (l1.try_lock_for(d)) return; + } + TimedLock() : + mtx(*static_cast(0)) + {} + private: + TimedLock operator=(TimedLock const&); + mutex_type& mtx; + boost::chrono::system_clock::time_point t; + boost::chrono::system_clock::duration d; + }; + + template + struct UniqueLock + { + BOOST_CONCEPT_ASSERT(( TimedLock )); + typedef typename Lk::mutex_type mutex_type; + + BOOST_CONCEPT_USAGE(UniqueLock) + { + + } + UniqueLock() : + mtx(*static_cast(0)) + {} + private: + UniqueLock operator=(UniqueLock const&); + mutex_type& mtx; + }; + + template + struct SharedLock + { + BOOST_CONCEPT_ASSERT(( TimedLock )); + typedef typename Lk::mutex_type mutex_type; + + BOOST_CONCEPT_USAGE(SharedLock) + { + } + SharedLock() : + mtx(*static_cast(0)) + {} + private: + SharedLock operator=(SharedLock const&); + mutex_type& mtx; + + }; + + template + struct UpgradeLock + { + BOOST_CONCEPT_ASSERT(( SharedLock )); + typedef typename Lk::mutex_type mutex_type; + + BOOST_CONCEPT_USAGE(UpgradeLock) + { + } + UpgradeLock() : + mtx(*static_cast(0)) + {} + private: + UpgradeLock operator=(UpgradeLock const&); + mutex_type& mtx; + }; + + /** + * An StrictLock is a scoped lock guard ensuring the mutex is locked on the + * scope of the lock, by locking the mutex on construction and unlocking it on + * destruction. + * + * Essentially, a StrictLock's role is only to live on the stack as an + * automatic variable. strict_lock must adhere to a non-copy and non-alias + * policy. StrictLock disables copying by making the copy constructor and the + * assignment operator private. While we're at it, let's disable operator new + * and operator delete; strict locks are not intended to be allocated on the + * heap. StrictLock avoids aliasing by using a slightly less orthodox and + * less well-known technique: disable address taking. + */ + + template + struct StrictLock + { + typedef typename Lk::mutex_type mutex_type; + BOOST_CONCEPT_ASSERT(( BasicLockable )); + BOOST_STATIC_ASSERT(( is_strict_lock::value)); + + BOOST_CONCEPT_USAGE( StrictLock) + { + if (l1.owns_lock(&mtx)) return; + } + StrictLock() : + l1(*static_cast(0)), + mtx(*static_cast(0)) + {} + private: + StrictLock operator=(StrictLock const&); + + Lk const& l1; + mutex_type const& mtx; + + }; + +} +#endif diff --git a/include/boost/thread/lock_factories.hpp b/include/boost/thread/lock_factories.hpp new file mode 100644 index 00000000..045589b6 --- /dev/null +++ b/include/boost/thread/lock_factories.hpp @@ -0,0 +1,90 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_FACTORIES_HPP +#define BOOST_THREAD_LOCK_FACTORIES_HPP + +#include +#include +#if ! defined(BOOST_NO_CXX11_HDR_TUPLE) +#include // todo change to once Boost.Tuple or Boost.Fusion provides Move semantics. +#endif +#include + +namespace boost +{ + + template + unique_lock make_unique_lock(Lockable& mtx) + { + return unique_lock (mtx); + } + + template + unique_lock make_unique_lock(Lockable& mtx, adopt_lock_t) + { + return unique_lock (mtx, adopt_lock); + } + + template + unique_lock make_unique_lock(Lockable& mtx, defer_lock_t) + { + return unique_lock (mtx, defer_lock); + } + + template + unique_lock make_unique_lock(Lockable& mtx, try_to_lock_t) + { + return unique_lock (mtx, try_to_lock); + } +#if ! defined(BOOST_NO_CXX11_HDR_TUPLE) + +#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES + template + std::tuple ...> make_unique_locks(Lockable& ...mtx) + { + boost::lock(mtx...); + return std::tuple ...>(unique_lock(mtx, adopt_lock)...); + } +#else + template + std::tuple, unique_lock > make_unique_locks(L1& m1, L2& m2) + { + boost::lock(m1, m2); + return std::tuple,unique_lock >( + unique_lock(m1, adopt_lock), + unique_lock(m2, adopt_lock) + ); + } + template + std::tuple, unique_lock, unique_lock > make_unique_locks(L1& m1, L2& m2, L2& m3) + { + boost::lock(m1, m2, m3); + return std::tuple,unique_lock,unique_lock >( + unique_lock(m1, adopt_lock), + unique_lock(m2, adopt_lock), + unique_lock(m3, adopt_lock) + ); + } + +#endif +#endif +// int main() +// { +// std::mutex m1; +// std::mutex m2; +// std::mutex m3; +// +// { +// auto lks = make_unique_locks(m1, m2, m3); +// +// } +// return 0; +// } + +} + +#include +#endif diff --git a/include/boost/thread/lock_guard.hpp b/include/boost/thread/lock_guard.hpp new file mode 100644 index 00000000..e24c8456 --- /dev/null +++ b/include/boost/thread/lock_guard.hpp @@ -0,0 +1,111 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_GUARD_HPP +#define BOOST_THREAD_LOCK_GUARD_HPP + +#include +#include +#include +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include +#include +#if ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST +#include +#endif +#include + +namespace boost +{ + +#if ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + namespace thread_detail + { + template + struct lockable_wrapper + { + Mutex* m; + explicit lockable_wrapper(Mutex& m_) : + m(&m_) + {} + }; + template + struct lockable_adopt_wrapper + { + Mutex* m; + explicit lockable_adopt_wrapper(Mutex& m_) : + m(&m_) + {} + }; + } +#endif + + template + class lock_guard + { + private: + Mutex& m; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_NO_COPYABLE( lock_guard ) + + explicit lock_guard(Mutex& m_) : + m(m_) + { + m.lock(); + } + + lock_guard(Mutex& m_, adopt_lock_t) : + m(m_) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + +#if ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + lock_guard(std::initializer_list > l_) : + m(*(const_cast*>(l_.begin())->m)) + { + m.lock(); + } + + lock_guard(std::initializer_list > l_) : + m(*(const_cast*>(l_.begin())->m)) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + +#endif + ~lock_guard() + { + m.unlock(); + } + }; + + +#if ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + template + lock_guard make_lock_guard(Lockable& mtx) + { + return { thread_detail::lockable_wrapper(mtx) }; + } + template + lock_guard make_lock_guard(Lockable& mtx, adopt_lock_t) + { + return { thread_detail::lockable_adopt_wrapper(mtx) }; + } +#endif +} + +#include + +#endif diff --git a/include/boost/thread/lock_options.hpp b/include/boost/thread/lock_options.hpp new file mode 100644 index 00000000..68899ca8 --- /dev/null +++ b/include/boost/thread/lock_options.hpp @@ -0,0 +1,31 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_OPTIONS_HPP +#define BOOST_THREAD_LOCK_OPTIONS_HPP + +#include + +namespace boost +{ + struct defer_lock_t + { + }; + struct try_to_lock_t + { + }; + struct adopt_lock_t + { + }; + + BOOST_CONSTEXPR_OR_CONST defer_lock_t defer_lock = {}; + BOOST_CONSTEXPR_OR_CONST try_to_lock_t try_to_lock = {}; + BOOST_CONSTEXPR_OR_CONST adopt_lock_t adopt_lock = {}; + +} +#include + +#endif diff --git a/include/boost/thread/lock_traits.hpp b/include/boost/thread/lock_traits.hpp new file mode 100644 index 00000000..5413c1eb --- /dev/null +++ b/include/boost/thread/lock_traits.hpp @@ -0,0 +1,42 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_TRAITS_HPP +#define BOOST_THREAD_LOCK_TRAITS_HPP + +#include +//#include +//#include +// +//#ifdef BOOST_THREAD_USES_CHRONO +//#include +//#include +//#endif + +#include + +#include + +namespace boost +{ + +/** + * An strict lock is a lock ensuring the mutex is locked on the scope of the lock + * There is no single way to define a strict lock as the strict_lock and + * nesteed_strict_lock shows. So we need a metafunction that states if a + * lock is a strict lock "sur parolle". + */ + +template +struct is_strict_lock_sur_parolle : false_type {}; + + +template +struct is_strict_lock : is_strict_lock_sur_parolle {}; + +} +#include + +#endif diff --git a/include/boost/thread/lock_types.hpp b/include/boost/thread/lock_types.hpp new file mode 100644 index 00000000..1b407871 --- /dev/null +++ b/include/boost/thread/lock_types.hpp @@ -0,0 +1,1221 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCK_TYPES_HPP +#define BOOST_THREAD_LOCK_TYPES_HPP + +#include +#include +#include +#include +#include +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include + +#include +#ifdef BOOST_THREAD_USES_CHRONO +#include +#include +#endif +#include + +#include + +namespace boost +{ + struct xtime; + + template + class shared_lock; + + template + class upgrade_lock; + + template + class unique_lock; + + namespace detail + { + template + class try_lock_wrapper; + } + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace sync + { + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + template + struct is_basic_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template + struct is_lockable > + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + } +#endif + + + template + class unique_lock + { + private: + Mutex* m; + bool is_locked; + + private: + explicit unique_lock(upgrade_lock&); + unique_lock& operator=(upgrade_lock& other); + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( unique_lock) + +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock(const volatile unique_lock&); +#endif +#endif + unique_lock()BOOST_NOEXCEPT : + m(0),is_locked(false) + {} + + explicit unique_lock(Mutex& m_) : + m(&m_), is_locked(false) + { + lock(); + } + unique_lock(Mutex& m_, adopt_lock_t) : + m(&m_), is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + unique_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + unique_lock(Mutex& m_, try_to_lock_t) : + m(&m_), is_locked(false) + { + try_lock(); + } +#if defined BOOST_THREAD_USES_DATETIME + template + unique_lock(Mutex& m_,TimeDuration const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } + unique_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + unique_lock(Mutex& mtx, const chrono::time_point& t) + : m(&mtx), is_locked(mtx.try_lock_until(t)) + { + } + template + unique_lock(Mutex& mtx, const chrono::duration& d) + : m(&mtx), is_locked(mtx.try_lock_for(d)) + { + } +#endif + + unique_lock(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other); + +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT + { + unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + + unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT + { + unique_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. +#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) + unique_lock& operator=(unique_lock other) + { + swap(other); + return *this; + } +#endif // BOOST_WORKAROUND +#endif + + // Conversion from upgrade locking + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock()) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, + const chrono::time_point& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_until(abs_time)) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } + + template + unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, + const chrono::duration& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(ul).owns_lock()) + { + if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_for(rel_time)) + { + m = BOOST_THREAD_RV(ul).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(ul).release(); + } + } +#endif + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + // Conversion from shared locking + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock()) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::time_point& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_until(abs_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + + template + unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::duration& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_for(rel_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } +#endif // BOOST_THREAD_USES_CHRONO +#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + + void swap(unique_lock& other)BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + ~unique_lock() + { + if (owns_lock()) + { + m->unlock(); + } + } + void lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + m->lock(); + is_locked = true; + } + bool try_lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + is_locked = m->try_lock(); + return is_locked; + } +#if defined BOOST_THREAD_USES_DATETIME + template + bool timed_lock(TimeDuration const& relative_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(relative_time); + return is_locked; + } + + bool timed_lock(::boost::system_time const& absolute_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(absolute_time); + return is_locked; + } + bool timed_lock(::boost::xtime const& absolute_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + is_locked=m->timed_lock(absolute_time); + return is_locked; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + + template + bool try_lock_for(const chrono::duration& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + is_locked=m->try_lock_for(rel_time); + return is_locked; + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); + } + is_locked=m->try_lock_until(abs_time); + return is_locked; + } +#endif + + void unlock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); + } + if (!owns_lock()) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock doesn't own the mutex")); + } + m->unlock(); + is_locked = false; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (unique_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&unique_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release()BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + friend class shared_lock ; + friend class upgrade_lock ; + }; + + template + void swap(unique_lock& lhs, unique_lock& rhs) + BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock BOOST_THREAD_DCL_MOVABLE_END + + template + class shared_lock + { + protected: + Mutex* m; + bool is_locked; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY(shared_lock) + + shared_lock() BOOST_NOEXCEPT: + m(0),is_locked(false) + {} + + explicit shared_lock(Mutex& m_): + m(&m_),is_locked(false) + { + lock(); + } + shared_lock(Mutex& m_,adopt_lock_t): + m(&m_),is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + shared_lock(Mutex& m_,try_to_lock_t): + m(&m_),is_locked(false) + { + try_lock(); + } +#if defined BOOST_THREAD_USES_DATETIME + shared_lock(Mutex& m_,system_time const& target_time): + m(&m_),is_locked(false) + { + timed_lock(target_time); + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + shared_lock(Mutex& mtx, const chrono::time_point& t) + : m(&mtx), is_locked(mtx.try_lock_shared_until(t)) + { + } + template + shared_lock(Mutex& mtx, const chrono::duration& d) + : m(&mtx), is_locked(mtx.try_lock_shared_for(d)) + { + } +#endif + + shared_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_and_lock_shared(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock_shared(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other) + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + + shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) + { + shared_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + + void swap(shared_lock& other) BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release() BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + + ~shared_lock() + { + if(owns_lock()) + { + m->unlock_shared(); + } + } + void lock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + m->lock_shared(); + is_locked=true; + } + bool try_lock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared(); + return is_locked; + } +#if defined BOOST_THREAD_USES_DATETIME + bool timed_lock(boost::system_time const& target_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } + template + bool timed_lock(Duration const& target_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->timed_lock_shared(target_time); + return is_locked; + } +#endif +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared_for(rel_time); + return is_locked; + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_shared_until(abs_time); + return is_locked; + } +#endif + void unlock() + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(!owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock doesn't own the mutex")); + } + m->unlock_shared(); + is_locked=false; + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (shared_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&shared_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + + }; + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock BOOST_THREAD_DCL_MOVABLE_END + + template + void swap(shared_lock& lhs,shared_lock& rhs) BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + template + class upgrade_lock + { + protected: + Mutex* m; + bool is_locked; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( upgrade_lock) + + upgrade_lock()BOOST_NOEXCEPT: + m(0),is_locked(false) + {} + + explicit upgrade_lock(Mutex& m_) : + m(&m_), is_locked(false) + { + lock(); + } + upgrade_lock(Mutex& m_, adopt_lock_t) : + m(&m_), is_locked(true) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m)); +#endif + } + upgrade_lock(Mutex& m_, defer_lock_t)BOOST_NOEXCEPT: + m(&m_),is_locked(false) + {} + upgrade_lock(Mutex& m_, try_to_lock_t) : + m(&m_), is_locked(false) + { + try_lock(); + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + upgrade_lock(Mutex& mtx, const chrono::time_point& t) + : m(&mtx), is_locked(mtx.try_lock_upgrade_until(t)) + { + } + template + upgrade_lock(Mutex& mtx, const chrono::duration& d) + : m(&mtx), is_locked(mtx.try_lock_upgrade_for(d)) + { + } +#endif + + upgrade_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + BOOST_THREAD_EXPLICIT_LOCK_CONVERSION upgrade_lock(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_and_lock_upgrade(); + } + BOOST_THREAD_RV(other).is_locked=false; + BOOST_THREAD_RV(other).m=0; + } + + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT + { + upgrade_lock temp(::boost::move(other)); + swap(temp); + return *this; + } + +#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION + upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other) + { + upgrade_lock temp(::boost::move(other)); + swap(temp); + return *this; + } +#endif + +#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + // Conversion from shared locking + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, try_to_lock_t) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade()) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::time_point& abs_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_until(abs_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } + + template + upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, + const chrono::duration& rel_time) + : m(0),is_locked(false) + { + if (BOOST_THREAD_RV(sl).owns_lock()) + { + if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_for(rel_time)) + { + m = BOOST_THREAD_RV(sl).release(); + is_locked = true; + } + } + else + { + m = BOOST_THREAD_RV(sl).release(); + } + } +#endif // BOOST_THREAD_USES_CHRONO +#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS + void swap(upgrade_lock& other)BOOST_NOEXCEPT + { + std::swap(m,other.m); + std::swap(is_locked,other.is_locked); + } + Mutex* mutex() const BOOST_NOEXCEPT + { + return m; + } + + Mutex* release()BOOST_NOEXCEPT + { + Mutex* const res=m; + m=0; + is_locked=false; + return res; + } + ~upgrade_lock() + { + if (owns_lock()) + { + m->unlock_upgrade(); + } + } + void lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex")); + } + m->lock_upgrade(); + is_locked = true; + } + bool try_lock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if (owns_lock()) + { + boost::throw_exception( + boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex")); + } + is_locked = m->try_lock_upgrade(); + return is_locked; + } + void unlock() + { + if (m == 0) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if (!owns_lock()) + { + boost::throw_exception( + boost::lock_error(system::errc::operation_not_permitted, "boost upgrade_lock doesn't own the mutex")); + } + m->unlock_upgrade(); + is_locked = false; + } +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_upgrade_for(rel_time); + return is_locked; + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if(m==0) + { + boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); + } + if(owns_lock()) + { + boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); + } + is_locked=m->try_lock_upgrade_until(abs_time); + return is_locked; + } +#endif +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (upgrade_lock::*bool_type)(); + operator bool_type() const BOOST_NOEXCEPT + { + return is_locked?&upgrade_lock::lock:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + bool owns_lock() const BOOST_NOEXCEPT + { + return is_locked; + } + friend class shared_lock ; + friend class unique_lock ; + }; + + template + void swap(upgrade_lock& lhs, upgrade_lock& rhs) + BOOST_NOEXCEPT + { + lhs.swap(rhs); + } + + BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock BOOST_THREAD_DCL_MOVABLE_END + + template + unique_lock::unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other): + m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) + { + if(is_locked) + { + m->unlock_upgrade_and_lock(); + } + BOOST_THREAD_RV(other).release(); + } + + template + class upgrade_to_unique_lock + { + private: + upgrade_lock* source; + unique_lock exclusive; + + public: + typedef Mutex mutex_type; + BOOST_THREAD_MOVABLE_ONLY( upgrade_to_unique_lock) + + explicit upgrade_to_unique_lock(upgrade_lock& m_) : + source(&m_), exclusive(::boost::move(*source)) + { + } + ~upgrade_to_unique_lock() + { + if (source) + { + *source = BOOST_THREAD_MAKE_RV_REF(upgrade_lock (::boost::move(exclusive))); + } + } + + upgrade_to_unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: + source(BOOST_THREAD_RV(other).source),exclusive(::boost::move(BOOST_THREAD_RV(other).exclusive)) + { + BOOST_THREAD_RV(other).source=0; + } + + upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT + { + upgrade_to_unique_lock temp(other); + swap(temp); + return *this; + } + + void swap(upgrade_to_unique_lock& other)BOOST_NOEXCEPT + { + std::swap(source,other.source); + exclusive.swap(other.exclusive); + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); + operator bool_type() const BOOST_NOEXCEPT + { + return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; + } + bool operator!() const BOOST_NOEXCEPT + { + return !owns_lock(); + } +#else + explicit operator bool() const BOOST_NOEXCEPT + { + return owns_lock(); + } +#endif + + bool owns_lock() const BOOST_NOEXCEPT + { + return exclusive.owns_lock(); + } + }; + +BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock BOOST_THREAD_DCL_MOVABLE_END + +namespace detail +{ + template + class try_lock_wrapper: +private unique_lock + { + typedef unique_lock base; + public: + BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper) + + try_lock_wrapper() + {} + + explicit try_lock_wrapper(Mutex& m): + base(m,try_to_lock) + {} + + try_lock_wrapper(Mutex& m_,adopt_lock_t): + base(m_,adopt_lock) + { +#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS + BOOST_ASSERT(is_locked_by_this_thread(m_)); +#endif + } + try_lock_wrapper(Mutex& m_,defer_lock_t): + base(m_,defer_lock) + {} + try_lock_wrapper(Mutex& m_,try_to_lock_t): + base(m_,try_to_lock) + {} +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(other)) + {} + +#elif defined BOOST_THREAD_USES_MOVE + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(::boost::move(static_cast(other))) + {} + +#else + try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): + base(BOOST_THREAD_RV_REF(base)(*other)) + {} +#endif + try_lock_wrapper& operator=(BOOST_THREAD_RV_REF_BEG try_lock_wrapper BOOST_THREAD_RV_REF_END other) + { + try_lock_wrapper temp(other); + swap(temp); + return *this; + } + void swap(try_lock_wrapper& other) + { + base::swap(other); + } + void lock() + { + base::lock(); + } + bool try_lock() + { + return base::try_lock(); + } + void unlock() + { + base::unlock(); + } + bool owns_lock() const + { + return base::owns_lock(); + } + Mutex* mutex() const + { + return base::mutex(); + } + Mutex* release() + { + return base::release(); + } + +#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) + typedef typename base::bool_type bool_type; + operator bool_type() const + { + return base::operator bool_type(); + } + bool operator!() const + { + return !this->owns_lock(); + } +#else + explicit operator bool() const + { + return owns_lock(); + } +#endif + }; + + template + void swap(try_lock_wrapper& lhs,try_lock_wrapper& rhs) + { + lhs.swap(rhs); + } +} +} +#include + +#endif diff --git a/include/boost/thread/lockable_adapter.hpp b/include/boost/thread/lockable_adapter.hpp new file mode 100644 index 00000000..c486bcae --- /dev/null +++ b/include/boost/thread/lockable_adapter.hpp @@ -0,0 +1,226 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_LOCKABLE_ADAPTER_HPP +#define BOOST_THREAD_LOCKABLE_ADAPTER_HPP + +#include +#include + +namespace boost +{ + + //[basic_lockable_adapter + template + class basic_lockable_adapter + { + public: + typedef BasicLockable mutex_type; + + protected: + mutex_type& lockable() const + { + return lockable_; + } + mutable mutex_type lockable_; /*< mutable so that it can be modified by const functions >*/ + public: + + BOOST_THREAD_NO_COPYABLE( basic_lockable_adapter) /*< no copyable >*/ + + basic_lockable_adapter() + {} + + void lock() + { + lockable().lock(); + } + void unlock() + { + lockable().unlock(); + } + + }; + //] + + //[lockable_adapter + template + class lockable_adapter : public basic_lockable_adapter + { + public: + typedef Lockable mutex_type; + + bool try_lock() + { + return this->lockable().try_lock(); + } + }; + //] + + //[timed_lockable_adapter + template + class timed_lockable_adapter: public lockable_adapter + { + public: + typedef TimedLock mutex_type; + + template + bool try_lock_until(chrono::time_point const & abs_time) + { + return this->lockable().try_lock_until(abs_time); + } + template + bool try_lock_for(chrono::duration const & rel_time) + { + return this->lockable().try_lock_for(rel_time); + } + + }; + //] + + //[shared_lockable_adapter + template + class shared_lockable_adapter: public timed_lockable_adapter + { + public: + typedef SharableLock mutex_type; + + void lock_shared() + { + this->lockable().lock_shared(); + } + bool try_lock_shared() + { + return this->lockable().try_lock_shared(); + } + void unlock_shared() + { + this->lockable().unlock_shared(); + } + + template + bool try_lock_shared_until(chrono::time_point const & abs_time) + { + return this->lockable().try_lock_shared_until(abs_time); + } + template + bool try_lock_shared_for(chrono::duration const & rel_time) + { + return this->lockable().try_lock_shared_for(rel_time); + } + + }; + + //] + + //[upgrade_lockable_adapter + template + class upgrade_lockable_adapter: public shared_lockable_adapter + { + public: + typedef UpgradableLock mutex_type; + + void lock_upgrade() + { + this->lockable().lock_upgrade(); + } + + bool try_lock_upgrade() + { + return this->lockable().try_lock_upgrade(); + } + + void unlock_upgrade() + { + this->lockable().unlock_upgrade(); + } + + template + bool try_lock_upgrade_until(chrono::time_point const & abs_time) + { + return this->lockable().try_lock_upgrade_until(abs_time); + } + template + bool try_lock_upgrade_for(chrono::duration const & rel_time) + { + return this->lockable().try_lock_upgrade_for(rel_time); + } + + bool try_unlock_shared_and_lock() + { + return this->lockable().try_unlock_shared_and_lock(); + } + + template + bool try_unlock_shared_and_lock_until(chrono::time_point const & abs_time) + { + return this->lockable().try_unlock_shared_and_lock_until(abs_time); + } + template + bool try_unlock_shared_and_lock_for(chrono::duration const & rel_time) + { + return this->lockable().try_unlock_shared_and_lock_for(rel_time); + } + + void unlock_and_lock_shared() + { + this->lockable().unlock_and_lock_shared(); + } + + bool try_unlock_shared_and_lock_upgrade() + { + return this->lockable().try_unlock_shared_and_lock_upgrade(); + } + + template + bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point const & abs_time) + { + return this->lockable().try_unlock_shared_and_lock_upgrade_until(abs_time); + } + template + bool try_unlock_shared_and_lock_upgrade_for(chrono::duration const & rel_time) + { + return this->lockable().try_unlock_shared_and_lock_upgrade_for(rel_time); + } + + void unlock_and_lock_upgrade() + { + this->lockable().unlock_and_lock_upgrade(); + } + + void unlock_upgrade_and_lock() + { + this->lockable().unlock_upgrade_and_lock(); + } + + bool try_unlock_upgrade_and_lock() + { + return this->lockable().try_unlock_upgrade_and_lock(); + } + template + bool try_unlock_upgrade_and_lock_until(chrono::time_point const & abs_time) + { + return this->lockable().try_unlock_upgrade_and_lock_until(abs_time); + } + template + bool try_unlock_upgrade_and_lock_for(chrono::duration const & rel_time) + { + return this->lockable().try_unlock_upgrade_and_lock_for(rel_time); + } + + void unlock_upgrade_and_lock_shared() + { + this->lockable().unlock_upgrade_and_lock_shared(); + } + + }; +//] + +} +#endif diff --git a/include/boost/thread/lockable_concepts.hpp b/include/boost/thread/lockable_concepts.hpp new file mode 100644 index 00000000..bedd962e --- /dev/null +++ b/include/boost/thread/lockable_concepts.hpp @@ -0,0 +1,157 @@ +// (C) Copyright 2012 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_THREAD_LOCKABLE_CONCEPTS_HPP +#define BOOST_THREAD_LOCKABLE_CONCEPTS_HPP + +#include +#include + +namespace boost +{ + + /** + * BasicLockable object supports the basic features + * required to delimit a critical region + * Supports the basic lock and unlock functions. + */ + + //[BasicLockable + template + struct BasicLockable + { + + BOOST_CONCEPT_USAGE(BasicLockable) + { + l.lock(); + l.unlock(); + } + BasicLockable() : l(*static_cast(0)) {} + private: + BasicLockable operator=(BasicLockable const&); + + Mutex& l; + } + ; + //] + /** + * Lockable extends BasicLockable + * with try_lock functions. + */ + + //[Lockable + template + struct Lockable + { + BOOST_CONCEPT_ASSERT(( BasicLockable )); + + BOOST_CONCEPT_USAGE(Lockable) + { + if (l.try_lock()) return; + } + Lockable() : l(*static_cast(0)) {} + private: + Lockable operator=(Lockable const&); + Mutex& l; + }; + //] + + /** + * TimedLockable object extends Lockable + * with timed lock functions: try_lock_until and try_lock_for and the exception based lock_until and lock_for + */ + + //[TimedLockable + template + struct TimedLockable + { + BOOST_CONCEPT_ASSERT(( Lockable )); + + BOOST_CONCEPT_USAGE(TimedLockable) + { + if (l.try_lock_until(t)) return; + if (l.try_lock_for(d)) return; + } + TimedLockable() : l(*static_cast(0)) {} + private: + TimedLockable operator=(TimedLockable const&); + Mutex& l; + chrono::system_clock::time_point t; + chrono::system_clock::duration d; + }; + //] + + /** + * SharedLockable object extends TimedLockable + * with the lock_shared, lock_shared_until, lock_shared_for, try_lock_shared_until, try_lock_shared + * and unlock_shared functions + */ + //[SharedLockable + template + struct SharedLockable + { + BOOST_CONCEPT_ASSERT(( TimedLockable )); + + BOOST_CONCEPT_USAGE(SharedLockable) + { + l.lock_shared(); + l.unlock_shared(); + if (l.try_lock_shared()) return; + if (l.try_lock_shared_until(t)) return; + if (l.try_lock_shared_for(d)) return; + } + SharedLockable() : l(*static_cast(0)) {} + private: + SharedLockable operator=(SharedLockable const&); + Mutex& l; + chrono::system_clock::time_point t; + chrono::system_clock::duration d; + }; + //] + + /** + * UpgradeLockable object extends SharedLockable + * with the lock_upgrade, lock_upgrade_until, unlock_upgrade_and_lock, + * unlock_and_lock_shared and unlock_upgrade_and_lock_shared functions + */ + + //[UpgradeLockable + template + struct UpgradeLockable + { + BOOST_CONCEPT_ASSERT(( SharedLockable )); + + BOOST_CONCEPT_USAGE(UpgradeLockable) + { + l.lock_upgrade(); + l.unlock_upgrade(); + if (l.try_lock_upgrade()) return; + if (l.try_lock_upgrade_until(t)) return; + if (l.try_lock_upgrade_for(d)) return; + if (l.try_unlock_shared_and_lock()) return; + if (l.try_unlock_shared_and_lock_until(t)) return; + if (l.try_unlock_shared_and_lock_for(d)) return; + l.unlock_and_lock_shared(); + if (l.try_unlock_shared_and_lock_upgrade()) return; + if (l.try_unlock_shared_and_lock_upgrade_until(t)) return; + if (l.try_unlock_shared_and_lock_upgrade_for(d)) return; + l.unlock_and_lock_upgrade(); + l.unlock_upgrade_and_lock(); + if (l.try_unlock_upgrade_and_lock()) return; + if (l.try_unlock_upgrade_and_lock_until(t)) return; + if (l.try_unlock_upgrade_and_lock_for(d)) return; + l.unlock_upgrade_and_lock_shared(); + } + UpgradeLockable() : l(*static_cast(0)) {} + private: + UpgradeLockable operator=(UpgradeLockable const&); + Mutex& l; + chrono::system_clock::time_point t; + chrono::system_clock::duration d; + }; + //] + +} +#endif diff --git a/include/boost/thread/lockable_traits.hpp b/include/boost/thread/lockable_traits.hpp new file mode 100644 index 00000000..223e98c6 --- /dev/null +++ b/include/boost/thread/lockable_traits.hpp @@ -0,0 +1,202 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2011-2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_LOCKABLE_TRAITS_HPP +#define BOOST_THREAD_LOCKABLE_TRAITS_HPP + +#include + +#include +#include +#include + +#include + +// todo make use of integral_constant, true_type and false_type + +namespace boost +{ + namespace sync + { + +#if defined(BOOST_NO_SFINAE) || \ + BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ + BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#if ! defined BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES +#endif +#endif + +#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + namespace detail + { +#define BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(member_name) \ + template::value> \ + struct has_member_called_##member_name \ + { \ + BOOST_STATIC_CONSTANT(bool, value=false); \ + }; \ + \ + template \ + struct has_member_called_##member_name \ + { \ + typedef char true_type; \ + struct false_type \ + { \ + true_type dummy[2]; \ + }; \ + \ + struct fallback { int member_name; }; \ + struct derived: \ + T, fallback \ + { \ + derived(); \ + }; \ + \ + template struct tester; \ + \ + template \ + static false_type has_member(tester<&U::member_name>*); \ + template \ + static true_type has_member(...); \ + \ + BOOST_STATIC_CONSTANT( \ + bool, value=sizeof(has_member(0))==sizeof(true_type)); \ + } + + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(lock) +; BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(unlock); + BOOST_THREAD_DEFINE_HAS_MEMBER_CALLED(try_lock); + + template::value > + struct has_member_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_lock::has_member(&T::lock))==sizeof(true_type)); + }; + + template::value > + struct has_member_unlock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_unlock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(V (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_unlock::has_member(&T::unlock))==sizeof(true_type)); + }; + + template::value > + struct has_member_try_lock + { + BOOST_STATIC_CONSTANT(bool, value=false); + }; + + template + struct has_member_try_lock + { + typedef char true_type; + struct false_type + { + true_type dummy[2]; + }; + + template + static true_type has_member(bool (U::*)()); + template + static false_type has_member(U); + + BOOST_STATIC_CONSTANT( + bool,value=sizeof(has_member_try_lock::has_member(&T::try_lock))==sizeof(true_type)); + }; + + } + + template + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && + detail::has_member_unlock::value); + }; + template + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = + is_basic_lockable::value && + detail::has_member_try_lock::value); + }; + +#else + template + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; +#endif + + template + struct is_recursive_mutex_sur_parolle + { + BOOST_STATIC_CONSTANT(bool, value = false); + }; + template + struct is_recursive_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable::value && + is_recursive_mutex_sur_parolle::value); + }; + template + struct is_recursive_lockable + { + BOOST_STATIC_CONSTANT(bool, value = is_lockable::value && + is_recursive_mutex_sur_parolle::value); + }; + } + template + struct is_mutex_type + { + BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable::value); + }; + +} +#include + +#endif diff --git a/include/boost/thread/locks.hpp b/include/boost/thread/locks.hpp index c11c2bd3..6749964c 100644 --- a/include/boost/thread/locks.hpp +++ b/include/boost/thread/locks.hpp @@ -6,1822 +6,11 @@ #ifndef BOOST_THREAD_LOCKS_HPP #define BOOST_THREAD_LOCKS_HPP -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef BOOST_THREAD_USES_CHRONO -#include -#include -#endif -#include - -namespace boost -{ - struct xtime; - -#if defined(BOOST_NO_SFINAE) || \ - BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600)) || \ - BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) -#define BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES -#endif - -#ifndef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES - namespace detail - { -#define BOOST_DEFINE_HAS_MEMBER_CALLED(member_name) \ - template::value> \ - struct has_member_called_##member_name \ - { \ - BOOST_STATIC_CONSTANT(bool, value=false); \ - }; \ - \ - template \ - struct has_member_called_##member_name \ - { \ - typedef char true_type; \ - struct false_type \ - { \ - true_type dummy[2]; \ - }; \ - \ - struct fallback { int member_name; }; \ - struct derived: \ - T, fallback \ - { \ - derived(); \ - }; \ - \ - template struct tester; \ - \ - template \ - static false_type has_member(tester<&U::member_name>*); \ - template \ - static true_type has_member(...); \ - \ - BOOST_STATIC_CONSTANT( \ - bool, value=sizeof(has_member(0))==sizeof(true_type)); \ - } - - BOOST_DEFINE_HAS_MEMBER_CALLED(lock); - BOOST_DEFINE_HAS_MEMBER_CALLED(unlock); - BOOST_DEFINE_HAS_MEMBER_CALLED(try_lock); - - template::value > - struct has_member_lock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template - struct has_member_lock - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(V (U::*)()); - template - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_lock::has_member(&T::lock))==sizeof(true_type)); - }; - - template::value > - struct has_member_unlock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template - struct has_member_unlock - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(V (U::*)()); - template - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_unlock::has_member(&T::unlock))==sizeof(true_type)); - }; - - template::value > - struct has_member_try_lock - { - BOOST_STATIC_CONSTANT(bool, value=false); - }; - - template - struct has_member_try_lock - { - typedef char true_type; - struct false_type - { - true_type dummy[2]; - }; - - template - static true_type has_member(bool (U::*)()); - template - static false_type has_member(U); - - BOOST_STATIC_CONSTANT( - bool,value=sizeof(has_member_try_lock::has_member(&T::try_lock))==sizeof(true_type)); - }; - - } - - - template - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock::value && - detail::has_member_unlock::value && - detail::has_member_try_lock::value); - - }; -#else - template - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = false); - }; -#endif - - struct defer_lock_t - {}; - struct try_to_lock_t - {}; - struct adopt_lock_t - {}; - - BOOST_CONSTEXPR_OR_CONST defer_lock_t defer_lock={}; - BOOST_CONSTEXPR_OR_CONST try_to_lock_t try_to_lock={}; - BOOST_CONSTEXPR_OR_CONST adopt_lock_t adopt_lock={}; - - template - class shared_lock; - - template - class upgrade_lock; - - template - class unique_lock; - - namespace detail - { - template - class try_lock_wrapper; - } - -#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES - template - struct is_mutex_type > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template - struct is_mutex_type > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template - struct is_mutex_type > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - template - struct is_mutex_type > - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - - class mutex; - class timed_mutex; - class recursive_mutex; - class recursive_timed_mutex; - class shared_mutex; - - template<> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - template<> - struct is_mutex_type - { - BOOST_STATIC_CONSTANT(bool, value = true); - }; - -#endif - - template - class lock_guard - { - private: - Mutex& m; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_NO_COPYABLE(lock_guard) - - explicit lock_guard(Mutex& m_): - m(m_) - { - m.lock(); - } - lock_guard(Mutex& m_,adopt_lock_t): - m(m_) - {} - ~lock_guard() - { - m.unlock(); - } - }; - - template - class unique_lock - { - private: - Mutex* m; - bool is_locked; - - private: - explicit unique_lock(upgrade_lock&); - unique_lock& operator=(upgrade_lock& other); - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(unique_lock) - -#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) - unique_lock(const volatile unique_lock&); -#endif -#endif - unique_lock() BOOST_NOEXCEPT : - m(0),is_locked(false) - {} - - explicit unique_lock(Mutex& m_): - m(&m_),is_locked(false) - { - lock(); - } - unique_lock(Mutex& m_,adopt_lock_t): - m(&m_),is_locked(true) - {} - unique_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: - m(&m_),is_locked(false) - {} - unique_lock(Mutex& m_,try_to_lock_t): - m(&m_),is_locked(false) - { - try_lock(); - } - template - unique_lock(Mutex& m_,TimeDuration const& target_time): - m(&m_),is_locked(false) - { - timed_lock(target_time); - } - unique_lock(Mutex& m_,system_time const& target_time): - m(&m_),is_locked(false) - { - timed_lock(target_time); - } - -#ifdef BOOST_THREAD_USES_CHRONO - template - unique_lock(Mutex& mtx, const chrono::time_point& t) - : m(&mtx), is_locked(mtx.try_lock_until(t)) - { - } - template - unique_lock(Mutex& mtx, const chrono::duration& d) - : m(&mtx), is_locked(mtx.try_lock_for(d)) - { - } -#endif - - unique_lock(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT: - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other); - -#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION - unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - unique_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#endif - - unique_lock& operator=(BOOST_THREAD_RV_REF(unique_lock) other) BOOST_NOEXCEPT - { - unique_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#if 0 // This should not be needed anymore. Use instead BOOST_THREAD_MAKE_RV_REF. -#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100) - unique_lock& operator=(unique_lock other) - { - swap(other); - return *this; - } -#endif // BOOST_WORKAROUND -#endif - - // Conversion from upgrade locking - unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, try_to_lock_t) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(ul).owns_lock()) { - if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock()) - { - m = BOOST_THREAD_RV(ul).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(ul).release(); - } - } - -#ifdef BOOST_THREAD_USES_CHRONO - template - unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, - const chrono::time_point& abs_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(ul).owns_lock()) { - if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_until(abs_time)) - { - m = BOOST_THREAD_RV(ul).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(ul).release(); - } - } - - template - unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END ul, - const chrono::duration& rel_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(ul).owns_lock()) { - if (BOOST_THREAD_RV(ul).mutex()->try_unlock_upgrade_and_lock_for(rel_time)) - { - m = BOOST_THREAD_RV(ul).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(ul).release(); - } - } -#endif - -#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - // Conversion from shared locking - unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, try_to_lock_t) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock()) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - -#ifdef BOOST_THREAD_USES_CHRONO - template - unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, - const chrono::time_point& abs_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_until(abs_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - - template - unique_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, - const chrono::duration& rel_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_for(rel_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } -#endif // BOOST_THREAD_USES_CHRONO -#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - - - void swap(unique_lock& other) BOOST_NOEXCEPT - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } - - ~unique_lock() - { - if(owns_lock()) - { - m->unlock(); - } - } - void lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - m->lock(); - is_locked=true; - } - bool try_lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->try_lock(); - return is_locked; - } - template - bool timed_lock(TimeDuration const& relative_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->timed_lock(relative_time); - return is_locked; - } - - bool timed_lock(::boost::system_time const& absolute_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->timed_lock(absolute_time); - return is_locked; - } - bool timed_lock(::boost::xtime const& absolute_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->timed_lock(absolute_time); - return is_locked; - } - -#ifdef BOOST_THREAD_USES_CHRONO - - template - bool try_lock_for(const chrono::duration& rel_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->try_lock_for(rel_time); - return is_locked; - } - template - bool try_lock_until(const chrono::time_point& abs_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost unique_lock owns already the mutex")); - } - is_locked=m->try_lock_until(abs_time); - return is_locked; - } -#endif - - void unlock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock has no mutex")); - } - if(!owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost unique_lock doesn't own the mutex")); - } - m->unlock(); - is_locked=false; - } - -#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) - typedef void (unique_lock::*bool_type)(); - operator bool_type() const BOOST_NOEXCEPT - { - return is_locked?&unique_lock::lock:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - bool owns_lock() const BOOST_NOEXCEPT - { - return is_locked; - } - - Mutex* mutex() const BOOST_NOEXCEPT - { - return m; - } - - Mutex* release() BOOST_NOEXCEPT - { - Mutex* const res=m; - m=0; - is_locked=false; - return res; - } - - friend class shared_lock; - friend class upgrade_lock; - }; - - template - void swap(unique_lock& lhs,unique_lock& rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) unique_lock BOOST_THREAD_DCL_MOVABLE_END - - template - class shared_lock - { - protected: - Mutex* m; - bool is_locked; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(shared_lock) - - shared_lock() BOOST_NOEXCEPT: - m(0),is_locked(false) - {} - - explicit shared_lock(Mutex& m_): - m(&m_),is_locked(false) - { - lock(); - } - shared_lock(Mutex& m_,adopt_lock_t): - m(&m_),is_locked(true) - {} - shared_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: - m(&m_),is_locked(false) - {} - shared_lock(Mutex& m_,try_to_lock_t): - m(&m_),is_locked(false) - { - try_lock(); - } - shared_lock(Mutex& m_,system_time const& target_time): - m(&m_),is_locked(false) - { - timed_lock(target_time); - } - -#ifdef BOOST_THREAD_USES_CHRONO - template - shared_lock(Mutex& mtx, const chrono::time_point& t) - : m(&mtx), is_locked(mtx.try_lock_shared_until(t)) - { - } - template - shared_lock(Mutex& mtx, const chrono::duration& d) - : m(&mtx), is_locked(mtx.try_lock_shared_for(d)) - { - } -#endif - - shared_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_and_lock_shared(); - } - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION shared_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_upgrade_and_lock_shared(); - } - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - - shared_lock& operator=(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - shared_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION - shared_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other) - { - shared_lock temp(::boost::move(other)); - swap(temp); - return *this; - } - - shared_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) - { - shared_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#endif - - void swap(shared_lock& other) BOOST_NOEXCEPT - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } - - Mutex* mutex() const BOOST_NOEXCEPT - { - return m; - } - - Mutex* release() BOOST_NOEXCEPT - { - Mutex* const res=m; - m=0; - is_locked=false; - return res; - } - - ~shared_lock() - { - if(owns_lock()) - { - m->unlock_shared(); - } - } - void lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - m->lock_shared(); - is_locked=true; - } - bool try_lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_shared(); - return is_locked; - } - bool timed_lock(boost::system_time const& target_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->timed_lock_shared(target_time); - return is_locked; - } - template - bool timed_lock(Duration const& target_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->timed_lock_shared(target_time); - return is_locked; - } -#ifdef BOOST_THREAD_USES_CHRONO - template - bool try_lock_for(const chrono::duration& rel_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_shared_for(rel_time); - return is_locked; - } - template - bool try_lock_until(const chrono::time_point& abs_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_shared_until(abs_time); - return is_locked; - } -#endif - void unlock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(!owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock doesn't own the mutex")); - } - m->unlock_shared(); - is_locked=false; - } - -#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) - typedef void (shared_lock::*bool_type)(); - operator bool_type() const BOOST_NOEXCEPT - { - return is_locked?&shared_lock::lock:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - bool owns_lock() const BOOST_NOEXCEPT - { - return is_locked; - } - - }; - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) shared_lock BOOST_THREAD_DCL_MOVABLE_END - - template - void swap(shared_lock& lhs,shared_lock& rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - template - class upgrade_lock - { - protected: - Mutex* m; - bool is_locked; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(upgrade_lock) - - upgrade_lock() BOOST_NOEXCEPT: - m(0),is_locked(false) - {} - - explicit upgrade_lock(Mutex& m_): - m(&m_),is_locked(false) - { - lock(); - } - upgrade_lock(Mutex& m_,adopt_lock_t): - m(&m_),is_locked(true) - {} - upgrade_lock(Mutex& m_,defer_lock_t) BOOST_NOEXCEPT: - m(&m_),is_locked(false) - {} - upgrade_lock(Mutex& m_,try_to_lock_t): - m(&m_),is_locked(false) - { - try_lock(); - } - -#ifdef BOOST_THREAD_USES_CHRONO - template - upgrade_lock(Mutex& mtx, const chrono::time_point& t) - : m(&mtx), is_locked(mtx.try_lock_upgrade_until(t)) - { - } - template - upgrade_lock(Mutex& mtx, const chrono::duration& d) - : m(&mtx), is_locked(mtx.try_lock_upgrade_for(d)) - { - } -#endif - - upgrade_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - BOOST_THREAD_EXPLICIT_LOCK_CONVERSION upgrade_lock(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_and_lock_upgrade(); - } - BOOST_THREAD_RV(other).is_locked=false; - BOOST_THREAD_RV(other).m=0; - } - - upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - upgrade_lock temp(::boost::move(other)); - swap(temp); - return *this; - } - -#ifndef BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION - upgrade_lock& operator=(BOOST_THREAD_RV_REF_BEG unique_lock BOOST_THREAD_RV_REF_END other) - { - upgrade_lock temp(::boost::move(other)); - swap(temp); - return *this; - } -#endif - -#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - // Conversion from shared locking - upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, try_to_lock_t) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade()) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - -#ifdef BOOST_THREAD_USES_CHRONO - template - upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, - const chrono::time_point& abs_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_until(abs_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } - - template - upgrade_lock(BOOST_THREAD_RV_REF_BEG shared_lock BOOST_THREAD_RV_REF_END sl, - const chrono::duration& rel_time) - : m(0),is_locked(false) - { - if (BOOST_THREAD_RV(sl).owns_lock()) { - if (BOOST_THREAD_RV(sl).mutex()->try_unlock_shared_and_lock_upgrade_for(rel_time)) - { - m = BOOST_THREAD_RV(sl).release(); - is_locked = true; - } - } - else - { - m = BOOST_THREAD_RV(sl).release(); - } - } -#endif // BOOST_THREAD_USES_CHRONO -#endif // BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS - - void swap(upgrade_lock& other) BOOST_NOEXCEPT - { - std::swap(m,other.m); - std::swap(is_locked,other.is_locked); - } - Mutex* mutex() const BOOST_NOEXCEPT - { - return m; - } - - Mutex* release() BOOST_NOEXCEPT - { - Mutex* const res=m; - m=0; - is_locked=false; - return res; - } - ~upgrade_lock() - { - if(owns_lock()) - { - m->unlock_upgrade(); - } - } - void lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex")); - } - m->lock_upgrade(); - is_locked=true; - } - bool try_lock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost upgrade_lock owns already the mutex")); - } - is_locked=m->try_lock_upgrade(); - return is_locked; - } - void unlock() - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(!owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost upgrade_lock doesn't own the mutex")); - } - m->unlock_upgrade(); - is_locked=false; - } -#ifdef BOOST_THREAD_USES_CHRONO - template - bool try_lock_for(const chrono::duration& rel_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_upgrade_for(rel_time); - return is_locked; - } - template - bool try_lock_until(const chrono::time_point& abs_time) - { - if(m==0) - { - boost::throw_exception(boost::lock_error(system::errc::operation_not_permitted, "boost shared_lock has no mutex")); - } - if(owns_lock()) - { - boost::throw_exception(boost::lock_error(system::errc::resource_deadlock_would_occur, "boost shared_lock owns already the mutex")); - } - is_locked=m->try_lock_upgrade_until(abs_time); - return is_locked; - } -#endif -#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) - typedef void (upgrade_lock::*bool_type)(); - operator bool_type() const BOOST_NOEXCEPT - { - return is_locked?&upgrade_lock::lock:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - bool owns_lock() const BOOST_NOEXCEPT - { - return is_locked; - } - friend class shared_lock; - friend class unique_lock; - }; - - template - void swap(upgrade_lock& lhs,upgrade_lock& rhs) BOOST_NOEXCEPT - { - lhs.swap(rhs); - } - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_lock BOOST_THREAD_DCL_MOVABLE_END - - template - unique_lock::unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_lock BOOST_THREAD_RV_REF_END other): - m(BOOST_THREAD_RV(other).m),is_locked(BOOST_THREAD_RV(other).is_locked) - { - if(is_locked) - { - m->unlock_upgrade_and_lock(); - } - BOOST_THREAD_RV(other).release(); - } - - template - class upgrade_to_unique_lock - { - private: - upgrade_lock* source; - unique_lock exclusive; - - public: - typedef Mutex mutex_type; - BOOST_THREAD_MOVABLE_ONLY(upgrade_to_unique_lock) - - explicit upgrade_to_unique_lock(upgrade_lock& m_): - source(&m_),exclusive(::boost::move(*source)) - {} - ~upgrade_to_unique_lock() - { - if(source) - { - *source=BOOST_THREAD_MAKE_RV_REF(upgrade_lock(::boost::move(exclusive))); - } - } - - upgrade_to_unique_lock(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT: - source(BOOST_THREAD_RV(other).source),exclusive(::boost::move(BOOST_THREAD_RV(other).exclusive)) - { - BOOST_THREAD_RV(other).source=0; - } - - upgrade_to_unique_lock& operator=(BOOST_THREAD_RV_REF_BEG upgrade_to_unique_lock BOOST_THREAD_RV_REF_END other) BOOST_NOEXCEPT - { - upgrade_to_unique_lock temp(other); - swap(temp); - return *this; - } - - void swap(upgrade_to_unique_lock& other) BOOST_NOEXCEPT - { - std::swap(source,other.source); - exclusive.swap(other.exclusive); - } - -#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) - typedef void (upgrade_to_unique_lock::*bool_type)(upgrade_to_unique_lock&); - operator bool_type() const BOOST_NOEXCEPT - { - return exclusive.owns_lock()?&upgrade_to_unique_lock::swap:0; - } - bool operator!() const BOOST_NOEXCEPT - { - return !owns_lock(); - } -#else - explicit operator bool() const BOOST_NOEXCEPT - { - return owns_lock(); - } -#endif - - bool owns_lock() const BOOST_NOEXCEPT - { - return exclusive.owns_lock(); - } - }; - - BOOST_THREAD_DCL_MOVABLE_BEG(Mutex) upgrade_to_unique_lock BOOST_THREAD_DCL_MOVABLE_END - - namespace detail - { - template - class try_lock_wrapper: - private unique_lock - { - typedef unique_lock base; - public: - BOOST_THREAD_MOVABLE_ONLY(try_lock_wrapper) - - try_lock_wrapper() - {} - - explicit try_lock_wrapper(Mutex& m): - base(m,try_to_lock) - {} - - try_lock_wrapper(Mutex& m_,adopt_lock_t): - base(m_,adopt_lock) - {} - try_lock_wrapper(Mutex& m_,defer_lock_t): - base(m_,defer_lock) - {} - try_lock_wrapper(Mutex& m_,try_to_lock_t): - base(m_,try_to_lock) - {} -#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES - try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): - base(::boost::move(other)) - {} - -#elif defined BOOST_THREAD_USES_MOVE - try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): - base(::boost::move(static_cast(other))) - {} - -#else - try_lock_wrapper(BOOST_THREAD_RV_REF(try_lock_wrapper) other): - base(BOOST_THREAD_RV_REF(base)(*other)) - {} -#endif - try_lock_wrapper& operator=(BOOST_THREAD_RV_REF_BEG try_lock_wrapper BOOST_THREAD_RV_REF_END other) - { - try_lock_wrapper temp(other); - swap(temp); - return *this; - } - void swap(try_lock_wrapper& other) - { - base::swap(other); - } - void lock() - { - base::lock(); - } - bool try_lock() - { - return base::try_lock(); - } - void unlock() - { - base::unlock(); - } - bool owns_lock() const - { - return base::owns_lock(); - } - Mutex* mutex() const - { - return base::mutex(); - } - Mutex* release() - { - return base::release(); - } - -#if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS) - typedef typename base::bool_type bool_type; - operator bool_type() const - { - return base::operator bool_type(); - } - bool operator!() const - { - return !this->owns_lock(); - } -#else - explicit operator bool() const - { - return owns_lock(); - } -#endif - }; - - template - void swap(try_lock_wrapper& lhs,try_lock_wrapper& rhs) - { - lhs.swap(rhs); - } - - template - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2) - { - boost::unique_lock l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(!m2.try_lock()) - { - return 2; - } - l1.release(); - return 0; - } - - template - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - boost::unique_lock l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(unsigned const failed_lock=try_lock_internal(m2,m3)) - { - return failed_lock+1; - } - l1.release(); - return 0; - } - - - template - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4) - { - boost::unique_lock l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) - { - return failed_lock+1; - } - l1.release(); - return 0; - } - - template - unsigned try_lock_internal(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4,MutexType5& m5) - { - boost::unique_lock l1(m1,boost::try_to_lock); - if(!l1) - { - return 1; - } - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) - { - return failed_lock+1; - } - l1.release(); - return 0; - } - - - template - unsigned lock_helper(MutexType1& m1,MutexType2& m2) - { - boost::unique_lock l1(m1); - if(!m2.try_lock()) - { - return 1; - } - l1.release(); - return 0; - } - - template - unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - boost::unique_lock l1(m1); - if(unsigned const failed_lock=try_lock_internal(m2,m3)) - { - return failed_lock; - } - l1.release(); - return 0; - } - - template - unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4) - { - boost::unique_lock l1(m1); - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4)) - { - return failed_lock; - } - l1.release(); - return 0; - } - - template - unsigned lock_helper(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4,MutexType5& m5) - { - boost::unique_lock l1(m1); - if(unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5)) - { - return failed_lock; - } - l1.release(); - return 0; - } - } - - namespace detail - { - template - struct is_mutex_type_wrapper - {}; - - template - void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper) - { - unsigned const lock_count=2; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - } - } - } - - template - void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper); - } - - - template - void lock(MutexType1& m1,MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - void lock(const MutexType1& m1,MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - void lock(MutexType1& m1,const MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - void lock(const MutexType1& m1,const MutexType2& m2) - { - detail::lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - unsigned const lock_count=3; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2,m3); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m3,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - case 2: - lock_first=detail::lock_helper(m3,m1,m2); - if(!lock_first) - return; - lock_first=(lock_first+2)%lock_count; - break; - } - } - } - - template - void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4) - { - unsigned const lock_count=4; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2,m3,m4); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m3,m4,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - case 2: - lock_first=detail::lock_helper(m3,m4,m1,m2); - if(!lock_first) - return; - lock_first=(lock_first+2)%lock_count; - break; - case 3: - lock_first=detail::lock_helper(m4,m1,m2,m3); - if(!lock_first) - return; - lock_first=(lock_first+3)%lock_count; - break; - } - } - } - - template - void lock(MutexType1& m1,MutexType2& m2,MutexType3& m3, - MutexType4& m4,MutexType5& m5) - { - unsigned const lock_count=5; - unsigned lock_first=0; - for(;;) - { - switch(lock_first) - { - case 0: - lock_first=detail::lock_helper(m1,m2,m3,m4,m5); - if(!lock_first) - return; - break; - case 1: - lock_first=detail::lock_helper(m2,m3,m4,m5,m1); - if(!lock_first) - return; - lock_first=(lock_first+1)%lock_count; - break; - case 2: - lock_first=detail::lock_helper(m3,m4,m5,m1,m2); - if(!lock_first) - return; - lock_first=(lock_first+2)%lock_count; - break; - case 3: - lock_first=detail::lock_helper(m4,m5,m1,m2,m3); - if(!lock_first) - return; - lock_first=(lock_first+3)%lock_count; - break; - case 4: - lock_first=detail::lock_helper(m5,m1,m2,m3,m4); - if(!lock_first) - return; - lock_first=(lock_first+4)%lock_count; - break; - } - } - } - - namespace detail - { - template::value> - struct try_lock_impl_return - { - typedef int type; - }; - - template - struct try_lock_impl_return - { - typedef Iterator type; - }; - - template - int try_lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper) - { - return ((int)detail::try_lock_internal(m1,m2))-1; - } - - template - Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper); - } - - template - typename detail::try_lock_impl_return::type try_lock(MutexType1& m1,MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1,MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - typename detail::try_lock_impl_return::type try_lock(MutexType1& m1,const MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - typename detail::try_lock_impl_return::type try_lock(const MutexType1& m1,const MutexType2& m2) - { - return detail::try_lock_impl(m1,m2,detail::is_mutex_type_wrapper::value>()); - } - - template - int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3) - { - return ((int)detail::try_lock_internal(m1,m2,m3))-1; - } - - template - int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4) - { - return ((int)detail::try_lock_internal(m1,m2,m3,m4))-1; - } - - template - int try_lock(MutexType1& m1,MutexType2& m2,MutexType3& m3,MutexType4& m4,MutexType5& m5) - { - return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1; - } - - - namespace detail - { - template - struct range_lock_guard - { - Iterator begin; - Iterator end; - - range_lock_guard(Iterator begin_,Iterator end_): - begin(begin_),end(end_) - { - boost::lock(begin,end); - } - - void release() - { - begin=end; - } - - ~range_lock_guard() - { - for(;begin!=end;++begin) - { - begin->unlock(); - } - } - }; - - template - Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper) - - { - if(begin==end) - { - return end; - } - typedef typename std::iterator_traits::value_type lock_type; - unique_lock guard(*begin,try_to_lock); - - if(!guard.owns_lock()) - { - return begin; - } - Iterator const failed=boost::try_lock(++begin,end); - if(failed==end) - { - guard.release(); - } - - return failed; - } - } - - - namespace detail - { - template - void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper) - { - typedef typename std::iterator_traits::value_type lock_type; - - if(begin==end) - { - return; - } - bool start_with_begin=true; - Iterator second=begin; - ++second; - Iterator next=second; - - for(;;) - { - unique_lock begin_lock(*begin,defer_lock); - if(start_with_begin) - { - begin_lock.lock(); - Iterator const failed_lock=boost::try_lock(next,end); - if(failed_lock==end) - { - begin_lock.release(); - return; - } - start_with_begin=false; - next=failed_lock; - } - else - { - detail::range_lock_guard guard(next,end); - if(begin_lock.try_lock()) - { - Iterator const failed_lock=boost::try_lock(second,next); - if(failed_lock==next) - { - begin_lock.release(); - guard.release(); - return; - } - start_with_begin=false; - next=failed_lock; - } - else - { - start_with_begin=true; - next=second; - } - } - } - } - - } - -} -#include +#include +#include +#include +#include +#include #endif diff --git a/include/boost/thread/mutex.hpp b/include/boost/thread/mutex.hpp index 4669886c..05c60941 100644 --- a/include/boost/thread/mutex.hpp +++ b/include/boost/thread/mutex.hpp @@ -3,7 +3,7 @@ // mutex.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,4 +18,36 @@ #error "Boost threads unavailable on this platform" #endif +#include + + +namespace boost +{ + namespace sync + { +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + } +} + #endif diff --git a/include/boost/thread/null_mutex.hpp b/include/boost/thread/null_mutex.hpp new file mode 100644 index 00000000..10d31e81 --- /dev/null +++ b/include/boost/thread/null_mutex.hpp @@ -0,0 +1,240 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_NULL_MUTEX_HPP +#define BOOST_THREAD_NULL_MUTEX_HPP + +#include +#include + +/// \file +/// Describes null_mutex class + +namespace boost +{ + + /// Implements a mutex that simulates a mutex without doing any operation and + /// simulates a successful operation. + class null_mutex + { + public: + + BOOST_THREAD_NO_COPYABLE( null_mutex) /*< no copyable >*/ + + /// Simulates a mutex lock() operation. Empty function. + void lock() + { + } + + /// Simulates a mutex try_lock() operation. + /// Equivalent to "return true;" + bool try_lock() + { + return true; + } + + /// Simulates a mutex unlock() operation. + /// Empty function. + void unlock() + { + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_lock_until() operation. + /// Equivalent to "return true;" + template + bool try_lock_until(chrono::time_point const &) + { + return true; + } + + /// Simulates a mutex try_lock_for() operation. + /// Equivalent to "return true;" + template + bool try_lock_for(chrono::duration const &) + { + return true; + } +#endif + + /// Simulates a mutex lock_shared() operation. + /// Empty function. + void lock_shared() + { + } + + /// Simulates a mutex try_lock_shared() operation. + /// Equivalent to "return true;" + bool try_lock_shared() + { + return true; + } + + /// Simulates a mutex unlock_shared() operation. + /// Empty function. + void unlock_shared() + { + } + + /// Simulates a mutex try_lock_shared_until() operation. + /// Equivalent to "return true;" + template + bool try_lock_shared_until(chrono::time_point const &) + { + return true; + } + /// Simulates a mutex try_lock_shared_for() operation. + /// Equivalent to "return true;" + template + bool try_lock_shared_for(chrono::duration const &) + { + return true; + } + + /// Simulates a mutex lock_upgrade() operation. + /// Empty function. + void lock_upgrade() + { + } + + /// Simulates a mutex try_lock_upgrade() operation. + /// Equivalent to "return true;" + bool try_lock_upgrade() + { + return true; + } + + /// Simulates a mutex unlock_upgrade() operation. + /// Empty function. + void unlock_upgrade() + { + } + + /// Simulates a mutex try_lock_upgrade_until() operation. + /// Equivalent to "return true;" + template + bool try_lock_upgrade_until(chrono::time_point const &) + { + return true; + } + + /// Simulates a mutex try_lock_upgrade_for() operation. + /// Equivalent to "return true;" + template + bool try_lock_upgrade_for(chrono::duration const &) + { + return true; + } + + /// Simulates a mutex try_unlock_shared_and_lock() operation. + /// Equivalent to "return true;" + bool try_unlock_shared_and_lock() + { + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_unlock_shared_and_lock_until() operation. + /// Equivalent to "return true;" + template + bool try_unlock_shared_and_lock_until(chrono::time_point const &) + { + return true; + } + + /// Simulates a mutex try_unlock_shared_and_lock_for() operation. + /// Equivalent to "return true;" + template + bool try_unlock_shared_and_lock_for(chrono::duration const &) + { + return true; + } +#endif + + /// Simulates unlock_and_lock_shared(). + /// Empty function. + void unlock_and_lock_shared() + { + } + + /// Simulates a mutex try_unlock_shared_and_lock_upgrade() operation. + /// Equivalent to "return true;" + bool try_unlock_shared_and_lock_upgrade() + { + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_unlock_shared_and_lock_upgrade_until() operation. + /// Equivalent to "return true;" + template + bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point const &) + { + return true; + } + + /// Simulates a mutex try_unlock_shared_and_lock_upgrade_for() operation. + /// Equivalent to "return true;" + template + bool try_unlock_shared_and_lock_upgrade_for(chrono::duration const &) + { + return true; + } +#endif + + /// Simulates unlock_and_lock_upgrade(). + /// Empty function. + void unlock_and_lock_upgrade() + { + } + + /// Simulates unlock_upgrade_and_lock(). + /// Empty function. + void unlock_upgrade_and_lock() + { + } + + /// Simulates a mutex try_unlock_upgrade_and_lock() operation. + /// Equivalent to "return true;" + bool try_unlock_upgrade_and_lock() + { + return true; + } + +#ifdef BOOST_THREAD_USES_CHRONO + /// Simulates a mutex try_unlock_upgrade_and_lock_until() operation. + /// Equivalent to "return true;" + template + bool try_unlock_upgrade_and_lock_until(chrono::time_point const &) + { + return true; + } + + /// Simulates a mutex try_unlock_upgrade_and_lock_for() operation. + /// Equivalent to "return true;" + template + bool try_unlock_upgrade_and_lock_for(chrono::duration const &) + { + return true; + } +#endif + + /// Simulates unlock_upgrade_and_lock_shared(). + /// Empty function. + void unlock_upgrade_and_lock_shared() + { + } + + }; + +} //namespace boost { + + +#endif diff --git a/include/boost/thread/poly_lockable.hpp b/include/boost/thread/poly_lockable.hpp new file mode 100644 index 00000000..73461881 --- /dev/null +++ b/include/boost/thread/poly_lockable.hpp @@ -0,0 +1,68 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_LOCKABLE_HPP +#define BOOST_THREAD_POLY_LOCKABLE_HPP + +#include +#include + +namespace boost +{ + + //[basic_poly_lockable + class basic_poly_lockable + { + public: + + virtual ~basic_poly_lockable() = 0; + + virtual void lock() = 0; + virtual void unlock() = 0; + + }; + //] + + //[poly_lockable + class poly_lockable : public basic_poly_lockable + { + public: + + virtual ~poly_lockable() = 0; + virtual bool try_lock() = 0; + }; + //] + + //[timed_poly_lockable + class timed_poly_lockable: public poly_lockable + { + public: + virtual ~timed_poly_lockable()=0; + + virtual bool try_lock_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_lock_until(chrono::steady_clock::time_point const & abs_time)=0; + template + bool try_lock_until(chrono::time_point const & abs_time) + { + return try_lock_until(time_point_cast(abs_time)); + } + + virtual bool try_lock_for(chrono::nanoseconds const & relative_time)=0; + template + bool try_lock_for(chrono::duration const & rel_time) + { + return try_lock_for(duration_cast(rel_time)); + } + + }; + //] + +} +#endif diff --git a/include/boost/thread/poly_lockable_adapter.hpp b/include/boost/thread/poly_lockable_adapter.hpp new file mode 100644 index 00000000..448789ec --- /dev/null +++ b/include/boost/thread/poly_lockable_adapter.hpp @@ -0,0 +1,89 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_LOCKABLE_ADAPTER_HPP +#define BOOST_THREAD_POLY_LOCKABLE_ADAPTER_HPP + +#include + +namespace boost +{ + + //[poly_basic_lockable_adapter + template + class poly_basic_lockable_adapter : public Base + { + public: + typedef Mutex mutex_type; + + protected: + mutex_type& mtx() const + { + return mtx_; + } + mutable mutex_type mtx_; /*< mutable so that it can be modified by const functions >*/ + public: + + BOOST_THREAD_NO_COPYABLE( poly_basic_lockable_adapter) /*< no copyable >*/ + + poly_basic_lockable_adapter() + {} + + void lock() + { + mtx().lock(); + } + void unlock() + { + mtx().unlock(); + } + + }; + //] + + //[poly_lockable_adapter + template + class poly_lockable_adapter : public poly_basic_lockable_adapter + { + public: + typedef Mutex mutex_type; + + bool try_lock() + { + return this->mtx().try_lock(); + } + }; + //] + + //[poly_timed_lockable_adapter + template + class poly_timed_lockable_adapter: public poly_lockable_adapter + { + public: + typedef Mutex mutex_type; + + bool try_lock_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_lock_until(abs_time); + } + bool try_lock_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_lock_until(abs_time); + } + bool try_lock_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_lock_for(rel_time); + } + + }; + //] + +} +#endif diff --git a/include/boost/thread/poly_shared_lockable.hpp b/include/boost/thread/poly_shared_lockable.hpp new file mode 100644 index 00000000..4348ed76 --- /dev/null +++ b/include/boost/thread/poly_shared_lockable.hpp @@ -0,0 +1,135 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_SHARED_LOCKABLE_HPP +#define BOOST_THREAD_POLY_SHARED_LOCKABLE_HPP + +#include +#include + +namespace boost +{ + + + //[shared_poly_lockable + class shared_poly_lockable: public timed_poly_lockable + { + public: + virtual ~shared_poly_lockable() = 0; + + virtual void lock_shared() = 0; + virtual bool try_lock_shared() = 0; + virtual void unlock_shared() = 0; + + virtual bool try_lock_shared_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_lock_shared_until(chrono::steady_clock::time_point const & abs_time)=0; + template + bool try_lock_shared_until(chrono::time_point const & abs_time) + { + return try_lock_shared_until(time_point_cast(abs_time)); + } + + virtual bool try_lock_shared_for(chrono::nanoseconds const & relative_time)=0; + template + bool try_lock_shared_for(chrono::duration const & rel_time) + { + return try_lock_shared_for(duration_cast(rel_time)); + } + + }; + + //] + + //[upgrade_poly_lockable + class upgrade_poly_lockable: public shared_poly_lockable + { + public: + virtual ~upgrade_poly_lockable() = 0; + + virtual void lock_upgrade() = 0; + virtual bool try_lock_upgrade() = 0; + virtual void unlock_upgrade() = 0; + + virtual bool try_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)=0; + template + bool try_lock_upgrade_until(chrono::time_point const & abs_time) + { + return try_lock_upgrade_until(time_point_cast(abs_time)); + } + + virtual bool try_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0; + template + bool try_lock_upgrade_for(chrono::duration const & rel_time) + { + return try_lock_upgrade_for(duration_cast(rel_time)); + } + + virtual bool try_unlock_shared_and_lock() = 0; + + virtual bool try_unlock_shared_and_lock_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_unlock_shared_and_lock_until(chrono::steady_clock::time_point const & abs_time)=0; + template + bool try_unlock_shared_and_lock_until(chrono::time_point const & abs_time) + { + return try_unlock_shared_and_lock_until(time_point_cast(abs_time)); + } + + virtual bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & relative_time)=0; + template + bool try_unlock_shared_and_lock_for(chrono::duration const & rel_time) + { + return try_unlock_shared_and_lock_for(duration_cast(rel_time)); + } + + virtual void unlock_and_lock_shared() = 0; + virtual bool try_unlock_shared_and_lock_upgrade() = 0; + + virtual bool try_unlock_shared_and_lock_upgrade_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time)=0; + template + bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point const & abs_time) + { + return try_unlock_shared_and_lock_upgrade_until(time_point_cast(abs_time)); + } + + virtual bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & relative_time)=0; + template + bool try_unlock_shared_and_lock_upgrade_for(chrono::duration const & rel_time) + { + return try_unlock_shared_and_lock_upgrade_for(duration_cast(rel_time)); + } + + virtual void unlock_and_lock_upgrade() = 0; + virtual void unlock_upgrade_and_lock() = 0; + virtual bool try_unlock_upgrade_and_lock() = 0; + + virtual bool try_unlock_upgrade_and_lock_until(chrono::system_clock::time_point const & abs_time)=0; + virtual bool try_unlock_upgrade_and_lock_until(chrono::steady_clock::time_point const & abs_time)=0; + template + bool try_unlock_upgrade_and_lock_until(chrono::time_point const & abs_time) + { + return try_unlock_upgrade_and_lock_until(time_point_cast(abs_time)); + } + + virtual bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & relative_time)=0; + template + bool try_unlock_upgrade_and_lock_for(chrono::duration const & rel_time) + { + return try_unlock_upgrade_and_lock_for(duration_cast(rel_time)); + } + + virtual void unlock_upgrade_and_lock_shared() = 0; + + }; +//] + +} +#endif diff --git a/include/boost/thread/poly_shared_lockable_adapter.hpp b/include/boost/thread/poly_shared_lockable_adapter.hpp new file mode 100644 index 00000000..f1361289 --- /dev/null +++ b/include/boost/thread/poly_shared_lockable_adapter.hpp @@ -0,0 +1,170 @@ +////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright Vicente J. Botet Escriba 2008-2009,2012. Distributed under the 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. +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef BOOST_THREAD_POLY_SHARED_LOCKABLE_ADAPTER_HPP +#define BOOST_THREAD_POLY_SHARED_LOCKABLE_ADAPTER_HPP + +#include +#include + +namespace boost +{ + + //[shared_lockable_adapter + template + class poly_shared_lockable_adapter: public poly_timed_lockable_adapter + { + public: + typedef Mutex mutex_type; + + void lock_shared() + { + this->mtx().lock_shared(); + } + bool try_lock_shared() + { + return this->mtx().try_lock_shared(); + } + void unlock_shared() + { + this->mtx().unlock_shared(); + } + + bool try_lock_shared_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_lock_shared_until(abs_time); + } + bool try_lock_shared_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_lock_shared_until(abs_time); + } + bool try_lock_shared_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_lock_shared_for(rel_time); + } + + }; + + //] + + //[upgrade_lockable_adapter + template + class upgrade_lockable_adapter: public shared_lockable_adapter + { + public: + typedef Mutex mutex_type; + + void lock_upgrade() + { + this->mtx().lock_upgrade(); + } + + bool try_lock_upgrade() + { + return this->mtx().try_lock_upgrade(); + } + + void unlock_upgrade() + { + this->mtx().unlock_upgrade(); + } + + bool try_lock_upgrade_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_lock_upgrade_until(abs_time); + } + bool try_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_lock_upgrade_until(abs_time); + } + bool try_lock_upgrade_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_lock_upgrade_for(rel_time); + } + + bool try_unlock_shared_and_lock() + { + return this->mtx().try_unlock_shared_and_lock(); + } + + bool try_unlock_shared_and_lock_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_until(abs_time); + } + bool try_unlock_shared_and_lock_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_until(abs_time); + } + template + bool try_unlock_shared_and_lock_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_unlock_shared_and_lock_for(rel_time); + } + + void unlock_and_lock_shared() + { + this->mtx().unlock_and_lock_shared(); + } + + bool try_unlock_shared_and_lock_upgrade() + { + return this->mtx().try_unlock_shared_and_lock_upgrade(); + } + + bool try_unlock_shared_and_lock_upgrade_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_upgrade_until(abs_time); + } + bool try_unlock_shared_and_lock_upgrade_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_shared_and_lock_upgrade_until(abs_time); + } + bool try_unlock_shared_and_lock_upgrade_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_unlock_shared_and_lock_upgrade_for(rel_time); + } + + void unlock_and_lock_upgrade() + { + this->mtx().unlock_and_lock_upgrade(); + } + + void unlock_upgrade_and_lock() + { + this->mtx().unlock_upgrade_and_lock(); + } + + bool try_unlock_upgrade_and_lock() + { + return this->mtx().try_unlock_upgrade_and_lock(); + } + bool try_unlock_upgrade_and_lock_until(chrono::system_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_upgrade_and_lock_until(abs_time); + } + bool try_unlock_upgrade_and_lock_until(chrono::steady_clock::time_point const & abs_time) + { + return this->mtx().try_unlock_upgrade_and_lock_until(abs_time); + } + bool try_unlock_upgrade_and_lock_for(chrono::nanoseconds const & rel_time) + { + return this->mtx().try_unlock_upgrade_and_lock_for(rel_time); + } + + void unlock_upgrade_and_lock_shared() + { + this->mtx().unlock_upgrade_and_lock_shared(); + } + + }; +//] + +} +#endif diff --git a/include/boost/thread/pthread/condition_variable.hpp b/include/boost/thread/pthread/condition_variable.hpp index aa710076..7c69d793 100644 --- a/include/boost/thread/pthread/condition_variable.hpp +++ b/include/boost/thread/pthread/condition_variable.hpp @@ -4,11 +4,13 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007-10 Anthony Williams -// (C) Copyright 2011 Vicente J. Botet Escriba +// (C) Copyright 2011-2012 Vicente J. Botet Escriba #include #include +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS #include +#endif #include #ifdef BOOST_THREAD_USES_CHRONO #include @@ -20,10 +22,12 @@ namespace boost { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS namespace this_thread { void BOOST_THREAD_DECL interruption_point(); } +#endif namespace thread_cv_detail { @@ -56,34 +60,44 @@ namespace boost int res=0; { thread_cv_detail::lock_on_exit > guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#endif guard.activate(m); do { res = pthread_cond_wait(&cond,&internal_mutex); } while (res == EINTR); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(res) { boost::throw_exception(condition_error(res, "boost:: condition_variable constructor failed in pthread_cond_wait")); } } - inline bool condition_variable::do_timed_wait( + inline bool condition_variable::do_wait_until( unique_lock& m, struct timespec const &timeout) { if (!m.owns_lock()) - boost::throw_exception(condition_error(EPERM, "condition_variable do_timed_wait: mutex not locked")); + { + boost::throw_exception(condition_error(EPERM, "condition_variable do_wait_until: mutex not locked")); + } thread_cv_detail::lock_on_exit > guard; int cond_res; { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#endif guard.activate(m); cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(cond_res==ETIMEDOUT) { return false; @@ -140,11 +154,15 @@ namespace boost int res=0; { thread_cv_detail::lock_on_exit guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#endif guard.activate(m); res=pthread_cond_wait(&cond,&internal_mutex); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(res) { boost::throw_exception(condition_error(res, "condition_variable_any failed in pthread_cond_wait")); @@ -157,11 +175,12 @@ namespace boost while(!pred()) wait(m); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_wait(lock_type& m,boost::system_time const& wait_until) { - struct timespec const timeout=detail::get_timespec(wait_until); - return do_timed_wait(m, timeout); + struct timespec const timeout=detail::to_timespec(wait_until); + return do_wait_until(m, timeout); } template bool timed_wait(lock_type& m,xtime const& wait_until) @@ -197,7 +216,7 @@ namespace boost { return timed_wait(m,get_system_time()+wait_duration,pred); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template cv_status @@ -274,17 +293,15 @@ namespace boost } template - inline void wait_until( + cv_status wait_until( lock_type& lk, chrono::time_point tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast(d); - ts.tv_sec = static_cast(s.count()); - ts.tv_nsec = static_cast((d - s).count()); - do_timed_wait(lk, ts); + timespec ts = boost::detail::to_timespec(d); + if (do_wait_until(lk, ts)) return cv_status::no_timeout; + else return cv_status::timeout; } #endif @@ -302,18 +319,22 @@ namespace boost private: // used by boost::thread::try_join_until template - inline bool do_timed_wait( + inline bool do_wait_until( lock_type& m, struct timespec const &timeout) { int res=0; { thread_cv_detail::lock_on_exit guard; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::interruption_checker check_for_interruption(&internal_mutex,&cond); +#endif guard.activate(m); res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS this_thread::interruption_point(); +#endif if(res==ETIMEDOUT) { return false; diff --git a/include/boost/thread/pthread/condition_variable_fwd.hpp b/include/boost/thread/pthread/condition_variable_fwd.hpp index dbb38926..42bdd89f 100644 --- a/include/boost/thread/pthread/condition_variable_fwd.hpp +++ b/include/boost/thread/pthread/condition_variable_fwd.hpp @@ -4,15 +4,16 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007-8 Anthony Williams -// (C) Copyright 2011 Vicente J. Botet Escriba +// (C) Copyright 2011-2012 Vicente J. Botet Escriba #include #include #include #include #include -#include +#include #include +#include #include #ifdef BOOST_THREAD_USES_CHRONO #include @@ -31,6 +32,20 @@ namespace boost pthread_mutex_t internal_mutex; pthread_cond_t cond; + public: + //private: // used by boost::thread::try_join_until + + inline bool do_wait_until( + unique_lock& lock, + struct timespec const &timeout); + + bool do_wait_for( + unique_lock& lock, + struct timespec const &timeout) + { + return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now())); + } + public: BOOST_THREAD_NO_COPYABLE(condition_variable) condition_variable() @@ -66,16 +81,17 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME inline bool timed_wait( unique_lock& m, boost::system_time const& wait_until) { #if defined BOOST_THREAD_WAIT_BUG - struct timespec const timeout=detail::get_timespec(wait_until + BOOST_THREAD_WAIT_BUG); - return do_timed_wait(m, timeout); + struct timespec const timeout=detail::to_timespec(wait_until + BOOST_THREAD_WAIT_BUG); + return do_wait_until(m, timeout); #else - struct timespec const timeout=detail::get_timespec(wait_until); - return do_timed_wait(m, timeout); + struct timespec const timeout=detail::to_timespec(wait_until); + return do_wait_until(m, timeout); #endif } bool timed_wait( @@ -121,6 +137,7 @@ namespace boost { return timed_wait(m,get_system_time()+wait_duration,pred); } +#endif #ifdef BOOST_THREAD_USES_CHRONO @@ -210,24 +227,17 @@ namespace boost void notify_all() BOOST_NOEXCEPT; #ifdef BOOST_THREAD_USES_CHRONO - inline void wait_until( + inline cv_status wait_until( unique_lock& lk, chrono::time_point tp) { using namespace chrono; nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast(d); - ts.tv_sec = static_cast(s.count()); - ts.tv_nsec = static_cast((d - s).count()); - do_timed_wait(lk, ts); + timespec ts = boost::detail::to_timespec(d); + if (do_wait_until(lk, ts)) return cv_status::no_timeout; + else return cv_status::timeout; } #endif - //private: // used by boost::thread::try_join_until - - inline bool do_timed_wait( - unique_lock& lock, - struct timespec const &timeout); }; BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk); diff --git a/include/boost/thread/pthread/mutex.hpp b/include/boost/thread/pthread/mutex.hpp index 2c5af92b..f33f5b12 100644 --- a/include/boost/thread/pthread/mutex.hpp +++ b/include/boost/thread/pthread/mutex.hpp @@ -6,10 +6,13 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include #include #include #include -#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif #include #include #include @@ -71,12 +74,15 @@ namespace boost void unlock() { - int ret; + int res; do { - ret = pthread_mutex_unlock(&m); - } while (ret == EINTR); - BOOST_VERIFY(!ret); + res = pthread_mutex_unlock(&m); + } while (res == EINTR); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_lock")); + } } bool try_lock() @@ -86,12 +92,8 @@ namespace boost { res = pthread_mutex_trylock(&m); } while (res == EINTR); - if(res && (res!=EBUSY)) + if (res==EBUSY) { - // The following throw_exception has been replaced by an assertion and just return false, - // as this is an internal error and the user can do nothing with the exception. - //boost::throw_exception(lock_error(res,"boost: mutex try_lock failed in pthread_mutex_trylock")); - BOOST_ASSERT_MSG(false ,"boost: mutex try_lock failed in pthread_mutex_trylock"); return false; } @@ -105,8 +107,10 @@ namespace boost return &m; } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_lock; typedef detail::try_lock_wrapper scoped_try_lock; +#endif }; typedef mutex try_mutex; @@ -146,6 +150,7 @@ namespace boost #endif } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_lock(TimeDuration const & relative_time) { @@ -155,23 +160,47 @@ namespace boost { return timed_lock(system_time(absolute_time)); } - +#endif #ifdef BOOST_PTHREAD_HAS_TIMEDLOCK void lock() { - BOOST_VERIFY(!pthread_mutex_lock(&m)); + int res; + do + { + res = pthread_mutex_lock(&m); + } while (res == EINTR); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex lock failed in pthread_mutex_lock")); + } } void unlock() { - BOOST_VERIFY(!pthread_mutex_unlock(&m)); + int res; + do + { + res = pthread_mutex_unlock(&m); + } while (res == EINTR); + if (res) + { + boost::throw_exception(lock_error(res,"boost: mutex unlock failed in pthread_mutex_lock")); + } } bool try_lock() { - int const res=pthread_mutex_trylock(&m); - BOOST_ASSERT(!res || res==EBUSY); - return !res; + int res; + do + { + res = pthread_mutex_trylock(&m); + } while (res == EINTR); + if (res==EBUSY) + { + return false; + } + + return !res; } @@ -232,12 +261,13 @@ namespace boost public: #endif +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { - struct timespec const ts=detail::get_timespec(abs_time); + struct timespec const ts=boost::detail::to_timespec(abs_time); return do_try_lock_until(ts); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) @@ -261,12 +291,9 @@ namespace boost } bool try_lock_until(const chrono::time_point& tp) { - using namespace chrono; - nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast(d); - ts.tv_sec = static_cast(s.count()); - ts.tv_nsec = static_cast((d - s).count()); + //using namespace chrono; + chrono::nanoseconds d = tp.time_since_epoch(); + timespec ts = boost::detail::to_timespec(d); return do_try_lock_until(ts); } #endif @@ -278,9 +305,11 @@ namespace boost return &m; } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_timed_lock; typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/include/boost/thread/pthread/recursive_mutex.hpp b/include/boost/thread/pthread/recursive_mutex.hpp index 2a6bc7da..5cfcf9f7 100644 --- a/include/boost/thread/pthread/recursive_mutex.hpp +++ b/include/boost/thread/pthread/recursive_mutex.hpp @@ -9,7 +9,9 @@ #include #include #include -#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif #include #include #ifndef _WIN32 @@ -167,8 +169,10 @@ namespace boost #endif +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_lock; typedef detail::try_lock_wrapper scoped_try_lock; +#endif }; typedef recursive_mutex recursive_try_mutex; @@ -232,11 +236,13 @@ namespace boost #endif } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_lock(TimeDuration const & relative_time) { return timed_lock(get_system_time()+relative_time); } +#endif #ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK void lock() @@ -334,12 +340,13 @@ namespace boost #endif +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const & abs_time) { - struct timespec const ts=detail::get_timespec(abs_time); + struct timespec const ts=detail::to_timespec(abs_time); return do_try_lock_until(ts); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) @@ -363,12 +370,9 @@ namespace boost } bool try_lock_until(const chrono::time_point& tp) { - using namespace chrono; - nanoseconds d = tp.time_since_epoch(); - timespec ts; - seconds s = duration_cast(d); - ts.tv_sec = static_cast(s.count()); - ts.tv_nsec = static_cast((d - s).count()); + //using namespace chrono; + chrono::nanoseconds d = tp.time_since_epoch(); + timespec ts = boost::detail::to_timespec(d); return do_try_lock_until(ts); } #endif @@ -380,9 +384,11 @@ namespace boost return &m; } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_timed_lock; typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/include/boost/thread/pthread/shared_mutex.hpp b/include/boost/thread/pthread/shared_mutex.hpp index cf451886..5e9c8fd6 100644 --- a/include/boost/thread/pthread/shared_mutex.hpp +++ b/include/boost/thread/pthread/shared_mutex.hpp @@ -12,7 +12,9 @@ #include #include #include +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS #include +#endif #ifdef BOOST_THREAD_USES_CHRONO #include #include @@ -63,8 +65,10 @@ namespace boost void lock_shared() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked) { @@ -75,7 +79,7 @@ namespace boost bool try_lock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); if(state.exclusive || state.exclusive_waiting_blocked) { @@ -88,10 +92,13 @@ namespace boost } } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock_shared(system_time const& timeout) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked) { @@ -109,6 +116,7 @@ namespace boost { return timed_lock_shared(get_system_time()+relative_time); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_shared_for(const chrono::duration& rel_time) @@ -118,8 +126,10 @@ namespace boost template bool try_lock_shared_until(const chrono::time_point& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked) { @@ -134,7 +144,7 @@ namespace boost #endif void unlock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); bool const last_reader=!--state.shared_count; if(last_reader) @@ -155,8 +165,10 @@ namespace boost void lock() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.shared_count || state.exclusive) { @@ -166,10 +178,13 @@ namespace boost state.exclusive=true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(system_time const& timeout) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.shared_count || state.exclusive) { @@ -194,7 +209,7 @@ namespace boost { return timed_lock(get_system_time()+relative_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) @@ -204,8 +219,10 @@ namespace boost template bool try_lock_until(const chrono::time_point& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.shared_count || state.exclusive) { @@ -228,7 +245,7 @@ namespace boost bool try_lock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); if(state.shared_count || state.exclusive) { @@ -244,7 +261,7 @@ namespace boost void unlock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); state.exclusive=false; state.exclusive_waiting_blocked=false; release_waiters(); @@ -252,8 +269,10 @@ namespace boost void lock_upgrade() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { shared_cond.wait(lk); @@ -262,10 +281,13 @@ namespace boost state.upgrade=true; } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock_upgrade(system_time const& timeout) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { if(!shared_cond.timed_wait(lk,timeout)) @@ -287,7 +309,7 @@ namespace boost { return timed_lock_upgrade(get_system_time()+relative_time); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_upgrade_for(const chrono::duration& rel_time) @@ -297,8 +319,10 @@ namespace boost template bool try_lock_upgrade_until(const chrono::time_point& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { if(cv_status::timeout == shared_cond.wait_until(lk,abs_time)) @@ -317,7 +341,7 @@ namespace boost #endif bool try_lock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade) { return false; @@ -332,7 +356,7 @@ namespace boost void unlock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); state.upgrade=false; bool const last_reader=!--state.shared_count; @@ -348,8 +372,10 @@ namespace boost // Upgrade <-> Exclusive void unlock_upgrade_and_lock() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); --state.shared_count; while(state.shared_count) { @@ -361,7 +387,7 @@ namespace boost void unlock_and_lock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); state.exclusive=false; state.upgrade=true; ++state.shared_count; @@ -371,7 +397,7 @@ namespace boost bool try_unlock_upgrade_and_lock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); if( !state.exclusive && !state.exclusive_waiting_blocked && state.upgrade @@ -398,8 +424,10 @@ namespace boost try_unlock_upgrade_and_lock_until( const chrono::time_point& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); if (state.shared_count != 1) { for (;;) @@ -422,7 +450,7 @@ namespace boost // Shared <-> Exclusive void unlock_and_lock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); state.exclusive=false; ++state.shared_count; state.exclusive_waiting_blocked=false; @@ -432,7 +460,7 @@ namespace boost #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS bool try_unlock_shared_and_lock() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); if( !state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade @@ -458,8 +486,10 @@ namespace boost try_unlock_shared_and_lock_until( const chrono::time_point& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); if (state.shared_count != 1) { for (;;) @@ -483,7 +513,7 @@ namespace boost // Shared <-> Upgrade void unlock_upgrade_and_lock_shared() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); state.upgrade=false; state.exclusive_waiting_blocked=false; release_waiters(); @@ -492,7 +522,7 @@ namespace boost #ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS bool try_unlock_shared_and_lock_upgrade() { - boost::mutex::scoped_lock lk(state_change); + boost::unique_lock lk(state_change); if( !state.exclusive && !state.exclusive_waiting_blocked && !state.upgrade @@ -517,8 +547,10 @@ namespace boost try_unlock_shared_and_lock_upgrade_until( const chrono::time_point& abs_time) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS boost::this_thread::disable_interruption do_not_disturb; - boost::mutex::scoped_lock lk(state_change); +#endif + boost::unique_lock lk(state_change); if( state.exclusive || state.exclusive_waiting_blocked || state.upgrade diff --git a/include/boost/thread/pthread/thread_data.hpp b/include/boost/thread/pthread/thread_data.hpp index db4e09f5..c1ef62ee 100644 --- a/include/boost/thread/pthread/thread_data.hpp +++ b/include/boost/thread/pthread/thread_data.hpp @@ -8,7 +8,8 @@ #include #include -#include +#include +#include #include #include @@ -24,6 +25,10 @@ #include #include +#if defined(__ANDROID__) +#include // http://code.google.com/p/android/issues/detail?id=39983 +#endif + #include #include @@ -77,6 +82,7 @@ namespace boost namespace detail { + struct future_object_base; struct tss_cleanup_function; struct thread_exit_callback_node; struct tss_data_node @@ -107,8 +113,10 @@ namespace boost bool joined; boost::detail::thread_exit_callback_node* thread_exit_callbacks; std::map tss_data; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS bool interrupt_enabled; bool interrupt_requested; +#endif pthread_mutex_t* cond_mutex; pthread_cond_t* current_cond; typedef std::vector @@ -116,27 +124,40 @@ namespace boost > notify_list_t; notify_list_t notify; + typedef std::vector > async_states_t; + async_states_t async_states_; + thread_data_base(): done(false),join_started(false),joined(false), thread_exit_callbacks(0), +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interrupt_enabled(true), interrupt_requested(false), +#endif current_cond(0), - notify() + notify(), + async_states_() {} virtual ~thread_data_base(); typedef pthread_t native_handle_type; virtual void run()=0; - void notify_all_at_thread_exit(condition_variable* cv, mutex* m) + virtual void notify_all_at_thread_exit(condition_variable* cv, mutex* m) { notify.push_back(std::pair(cv, m)); } + + void make_ready_at_thread_exit(shared_ptr as) + { + async_states_.push_back(as); + } + }; BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS class interruption_checker { thread_data_base* const thread_info; @@ -189,70 +210,46 @@ namespace boost } }; } +#endif namespace this_thread { + namespace hiden + { + void BOOST_THREAD_DECL sleep_for(const timespec& ts); + void BOOST_THREAD_DECL sleep_until(const timespec& ts); + } + #ifdef BOOST_THREAD_USES_CHRONO +#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + inline void BOOST_SYMBOL_VISIBLE sleep_for(const chrono::nanoseconds& ns) { - using namespace chrono; - boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data(); - - if(thread_info) - { - unique_lock lk(thread_info->sleep_mutex); - while(cv_status::no_timeout==thread_info->sleep_condition.wait_for(lk,ns)) {} - } - else - { - if (ns >= nanoseconds::zero()) - { - - # if defined(BOOST_HAS_PTHREAD_DELAY_NP) - timespec ts; - ts.tv_sec = static_cast(duration_cast(ns).count()); - ts.tv_nsec = static_cast((ns - seconds(ts.tv_sec)).count()); - BOOST_VERIFY(!pthread_delay_np(&ts)); - # elif defined(BOOST_HAS_NANOSLEEP) - timespec ts; - ts.tv_sec = static_cast(duration_cast(ns).count()); - ts.tv_nsec = static_cast((ns - seconds(ts.tv_sec)).count()); - // nanosleep takes a timespec that is an offset, not - // an absolute time. - nanosleep(&ts, 0); - # else - mutex mx; - mutex::scoped_lock lock(mx); - condition_variable cond; - cond.wait_for(lock, ns); - # endif - } - } + return boost::this_thread::hiden::sleep_for(boost::detail::to_timespec(ns)); } #endif +#endif // BOOST_THREAD_USES_CHRONO + void BOOST_THREAD_DECL yield() BOOST_NOEXCEPT; +#if defined BOOST_THREAD_USES_DATETIME #ifdef __DECXXX /// Workaround of DECCXX issue of incorrect template substitution - template - inline void sleep(TimeDuration const& rel_time) - { - this_thread::sleep(get_system_time()+rel_time); - } - template<> - void BOOST_THREAD_DECL sleep(system_time const& abs_time); -#else - void BOOST_THREAD_DECL sleep(system_time const& abs_time); +#endif + inline void sleep(system_time const& abs_time) + { + return boost::this_thread::hiden::sleep_until(boost::detail::to_timespec(abs_time)); + } template inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) { this_thread::sleep(get_system_time()+rel_time); } -#endif - } +#endif // BOOST_THREAD_USES_DATETIME + } // this_thread } #include diff --git a/include/boost/thread/pthread/timespec.hpp b/include/boost/thread/pthread/timespec.hpp index d7465c1a..82f50f6c 100644 --- a/include/boost/thread/pthread/timespec.hpp +++ b/include/boost/thread/pthread/timespec.hpp @@ -1,34 +1,118 @@ #ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP #define BOOST_THREAD_PTHREAD_TIMESPEC_HPP -// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2007-8 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#include #include +#if defined BOOST_THREAD_USES_DATETIME #include +#endif #include #ifndef _WIN32 #include #endif +#ifdef BOOST_THREAD_USES_CHRONO +#include +#endif + +#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) +# define BOOST_THREAD_TIMESPEC_MAC_API +#include //for gettimeofday and timeval +#else +#include // for clock_gettime +#endif #include namespace boost { - namespace detail + namespace detail + { +#if defined BOOST_THREAD_USES_DATETIME + inline struct timespec to_timespec(boost::system_time const& abs_time) { - inline struct timespec get_timespec(boost::system_time const& abs_time) - { - struct timespec timeout={0,0}; - boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); - - timeout.tv_sec=time_since_epoch.total_seconds(); - timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); - return timeout; - } + struct timespec timeout = { 0,0}; + boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0); + + timeout.tv_sec=time_since_epoch.total_seconds(); + timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second())); + return timeout; } +#endif +#if defined BOOST_THREAD_USES_CHRONO + inline timespec to_timespec(chrono::nanoseconds const& ns) + { + struct timespec ts; + ts.tv_sec = static_cast(chrono::duration_cast(ns).count()); + ts.tv_nsec = static_cast((ns - chrono::duration_cast(ns)).count()); + return ts; + } + +#endif + + inline timespec to_timespec(boost::intmax_t const& ns) + { + boost::intmax_t s = ns / 1000000000l; + struct timespec ts; + ts.tv_sec = static_cast (s); + ts.tv_nsec = static_cast (ns - s * 1000000000l); + return ts; + } + inline boost::intmax_t to_nanoseconds_int_max(timespec const& ts) + { + return static_cast(ts.tv_sec) * 1000000000l + ts.tv_nsec; + } + inline bool timespec_ge_zero(timespec const& ts) + { + return (ts.tv_sec >= 0) || (ts.tv_nsec >= 0); + } + inline timespec timespec_now() + { + timespec ts; + +#if defined(BOOST_THREAD_TIMESPEC_MAC_API) + timeval tv; + ::gettimeofday(&tv, 0); + ts.tv_sec = tv.tv_sec; + ts.tv_nsec = tv.tv_usec * 1000; +#else + if ( ::clock_gettime( CLOCK_REALTIME, &ts ) ) + { + BOOST_ASSERT(0 && "Boost::Thread - Internal Error"); + } +#endif + return ts; + } + inline timespec timespec_zero() + { + timespec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + return ts; + } + inline timespec timespec_plus(timespec const& lhs, timespec const& rhs) + { + return to_timespec(to_nanoseconds_int_max(lhs) + to_nanoseconds_int_max(rhs)); + } + inline timespec timespec_minus(timespec const& lhs, timespec const& rhs) + { + return to_timespec(to_nanoseconds_int_max(lhs) - to_nanoseconds_int_max(rhs)); + } + inline bool timespec_gt(timespec const& lhs, timespec const& rhs) + { + return to_nanoseconds_int_max(lhs) > to_nanoseconds_int_max(rhs); + } + inline bool timespec_ge(timespec const& lhs, timespec const& rhs) + { + return to_nanoseconds_int_max(lhs) >= to_nanoseconds_int_max(rhs); + } + + } } #include diff --git a/include/boost/thread/recursive_mutex.hpp b/include/boost/thread/recursive_mutex.hpp index d5f6116e..e716a190 100644 --- a/include/boost/thread/recursive_mutex.hpp +++ b/include/boost/thread/recursive_mutex.hpp @@ -3,7 +3,7 @@ // recursive_mutex.hpp // -// (C) Copyright 2007 Anthony Williams +// (C) Copyright 2007 Anthony Williams // // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at @@ -18,4 +18,47 @@ #error "Boost threads unavailable on this platform" #endif +#include + +namespace boost +{ + namespace sync + { + +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + + template<> + struct is_recursive_mutex_sur_parolle + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_recursive_mutex_sur_parolle + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + + } +} #endif diff --git a/include/boost/thread/reverse_lock.hpp b/include/boost/thread/reverse_lock.hpp index c196cde0..479c314b 100644 --- a/include/boost/thread/reverse_lock.hpp +++ b/include/boost/thread/reverse_lock.hpp @@ -6,7 +6,9 @@ #ifndef BOOST_THREAD_REVERSE_LOCK_HPP #define BOOST_THREAD_REVERSE_LOCK_HPP #include -#include +#include +#include +#include #include namespace boost @@ -15,7 +17,6 @@ namespace boost template class reverse_lock { - public: typedef typename Lock::mutex_type mutex_type; BOOST_THREAD_NO_COPYABLE(reverse_lock) diff --git a/include/boost/thread/scoped_thread.hpp b/include/boost/thread/scoped_thread.hpp new file mode 100644 index 00000000..2759e38e --- /dev/null +++ b/include/boost/thread/scoped_thread.hpp @@ -0,0 +1,227 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +// Based on the Anthony's idea of scoped_thread in CCiA + +#ifndef BOOST_THREAD_SCOPED_THREAD_HPP +#define BOOST_THREAD_SCOPED_THREAD_HPP + +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + + /** + * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. + * + * CallableThread: A callable void(thread&) . + * The default is a join_if_joinable. + * + * thread std/boost::thread destructor terminates the program if the thread is not joinable. + * Having a wrapper that can join the thread before destroying it seems a natural need. + * + * Example: + * + * boost::strict_scoped_thread<> t((boost::thread(F))); + * + */ + template + class strict_scoped_thread + { + thread t_; + public: + + BOOST_THREAD_NO_COPYABLE( strict_scoped_thread) /// non copyable + + /** + * Constructor from the thread to own. + * + * @param t: the thread to own. + * + * Effects: move the thread to own @c t. + */ + explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) : + t_(boost::move(t)) + { + } + + /** + * Destructor + */ + ~strict_scoped_thread() + { + CallableThread on_destructor; + + on_destructor(t_); + } + + }; + + /** + * RAI @c thread wrapper adding a specific destroyer allowing to master what can be done at destruction time. + * + * CallableThread: A callable void(thread&) . + * The default is join_if_joinable. + * + * thread std::thread destructor terminates the program if the thread is not joinable. + * Having a wrapper that can join the thread before destroying it seems a natural need. + * + * Remark: @c scoped_thread is not a @c thread as @c thread is not designed to be derived from as a polymorphic type. + * Anyway @c scoped_thread can be used in most of the contexts a @c thread could be used as it has the + * same non-deprecated interface with the exception of the construction. + * + * Example: + * + * boost::scoped_thread<> t((boost::thread(F))); + * t.interrupt(); + * + */ + template + class scoped_thread + { + thread t_; + public: + + typedef thread::id id; + + BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only + + /** + * Default Constructor. + * + * Effects: wraps a not-a-thread. + */ + scoped_thread() BOOST_NOEXCEPT: + t_() + { + } + + /** + * Constructor from the thread to own. + * + * @param t: the thread to own. + * + * Effects: move the thread to own @c t. + */ + explicit scoped_thread(BOOST_THREAD_RV_REF(thread) t) : + t_(boost::move(t)) + { + } + +// explicit operator thread() +// { +// return boost::move(t_); +// } + + /** + * Move constructor. + */ + scoped_thread(BOOST_RV_REF(scoped_thread) x) : + t_(boost::move(x.t_)) + {} + + /** + * Destructor + * + * Effects: destroys the internal destroyer before destroying the owned thread. + */ + ~scoped_thread() + { + CallableThread on_destructor; + + on_destructor(t_); + } + + /** + * Move assignment. + */ + scoped_thread& operator=(BOOST_RV_REF(scoped_thread) x) + { + t_ = boost::move(x.t_); + return *this; + } + + /** + * + */ + void swap(scoped_thread& x)BOOST_NOEXCEPT + { + t_.swap(x.t_); + } + + // forwarded thread functions + inline thread::id get_id() const BOOST_NOEXCEPT + { + return t_.get_id(); + } + + void detach() + { + t_.detach(); + } + + void join() + { + t_.join(); + } + +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_join_for(const chrono::duration& rel_time) + { + return t_.try_join_for(rel_time); + } + + template + bool try_join_until(const chrono::time_point& abs_time) + { + return t_.try_join_until(abs_time); + } +#endif + + thread::native_handle_type native_handle()BOOST_NOEXCEPT + { + return t_.native_handle(); + } + +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + void interrupt() + { + t_.interrupt(); + } + + bool interruption_requested() const BOOST_NOEXCEPT + { + return t_.interruption_requested(); + } +#endif + + static unsigned hardware_concurrency()BOOST_NOEXCEPT + { + return thread::hardware_concurrency(); + } + + }; + + /** + * Effects: swaps the contents of two scoped threads. + */ + template + void swap(scoped_thread& lhs, scoped_thread& rhs) +BOOST_NOEXCEPT { + return lhs.swap(rhs); +} + +} +#include + +#endif diff --git a/include/boost/thread/shared_lock_guard.hpp b/include/boost/thread/shared_lock_guard.hpp index 8a2f2c54..97a6397c 100644 --- a/include/boost/thread/shared_lock_guard.hpp +++ b/include/boost/thread/shared_lock_guard.hpp @@ -6,7 +6,8 @@ #ifndef BOOST_THREAD_SHARED_LOCK_GUARD_HPP #define BOOST_THREAD_SHARED_LOCK_GUARD_HPP #include -#include +//#include +#include #include namespace boost diff --git a/include/boost/thread/shared_mutex.hpp b/include/boost/thread/shared_mutex.hpp index e85e269d..9e12a8f3 100644 --- a/include/boost/thread/shared_mutex.hpp +++ b/include/boost/thread/shared_mutex.hpp @@ -23,4 +23,26 @@ #error "Boost threads unavailable on this platform" #endif +#include + +namespace boost +{ + namespace sync + { +#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES + template<> + struct is_basic_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; + template<> + struct is_lockable + { + BOOST_STATIC_CONSTANT(bool, value = true); + }; +#endif + + } +} + #endif diff --git a/include/boost/thread/strict_lock.hpp b/include/boost/thread/strict_lock.hpp new file mode 100644 index 00000000..bc7a2ed2 --- /dev/null +++ b/include/boost/thread/strict_lock.hpp @@ -0,0 +1,186 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2008-2009,2012 Vicente J. Botet Escriba + +#ifndef BOOST_THREAD_STRICT_LOCK_HPP +#define BOOST_THREAD_STRICT_LOCK_HPP + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace boost +{ + + + //[strict_lock + template + class strict_lock + { + + BOOST_CONCEPT_ASSERT(( BasicLockable )); + public: + typedef Lockable mutex_type; + + // construct/copy/destroy: + + BOOST_THREAD_NO_COPYABLE( strict_lock) + + /** + * Constructor from a mutex reference. + * + * @param mtx the mutex to lock. + * + * __Effects: Stores a reference to the mutex to lock and locks it. + * __Throws: Any exception BasicMutex::lock() can throw. + */ + explicit strict_lock(mutex_type& mtx) : + mtx_(mtx) + { + mtx.lock(); + } /*< locks on construction >*/ + + /** + * Destructor + * + * __Effects: unlocks the stored mutex. + * + * __Throws + */ + ~strict_lock() + { + mtx_.unlock(); + } /*< unlocks on destruction >*/ + + + // observers + private: + + /** + * @return the owned mutex. + */ + const mutex_type* mutex() const BOOST_NOEXCEPT + { + return &mtx_; + } + public: + + /** + * @return whether if this lock is locking that mutex. + */ + bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT + { + return l == mutex(); + } /*< strict locks specific function >*/ + + //BOOST_ADRESS_OF_DELETE(strict_lock) /*< disable aliasing >*/ + //BOOST_HEAP_ALLOCATION_DELETE(strict_lock) /*< disable heap allocation >*/ + + /*< no possibility to unlock >*/ + + private: + mutex_type& mtx_; + }; + //] + template + struct is_strict_lock_sur_parolle > : true_type + { + }; + + /** + * A nested strict lock is a scoped lock guard ensuring the mutex is locked on its + * scope, by taking ownership of an nesting lock, and locking the mutex on construction if not already locked + * and restoring the ownership to the nesting lock on destruction. + */ + //[nested_strict_lock + template + class nested_strict_lock + { + BOOST_CONCEPT_ASSERT(( BasicLock )); /*< The Lock must be a movable lock >*/ + public: + typedef typename Lock::mutex_type mutex_type; /*< Name the lockable type locked by Lock >*/ + + BOOST_THREAD_NO_COPYABLE( nested_strict_lock) + + /** + * Constructor from a nesting @c Lock. + * + * @param lk the nesting lock + * + * __Requires: lk.mutex() != null_ptr + * __Effects: Stores the reference to the lock parameter and takes ownership on it. + * If the lock doesn't owns the mutex @mtx lock it. + * __Postconditions: @c owns_lock() + * __StrongException + * __Throws: + * + * - lock_error when BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is defined and lk.mutex() == null_ptr + * + * - Any exception that @c lk.lock() can throw. + * + */ + nested_strict_lock(Lock& lk) : + lk_(lk) /*< Store reference to lk >*/ + { + /*< Define BOOST_THREAD_DONT_CHECK_PRECONDITIONS if you don't want to check lk ownership >*/ + BOOST_THREAD_ASSERT_PRECONDITION( lk.mutex() != 0, + lock_error() + ); + if (!lk.owns_lock()) lk.lock(); /*< ensures it is locked >*/ + tmp_lk_ = move(lk); /*< Move ownership to temporary lk >*/ + } + + /** + * Destructor + * + * __Effects: Restores ownership to the nesting lock. + */ + ~nested_strict_lock()BOOST_NOEXCEPT + { + lk_ = move(tmp_lk_); /*< Move ownership to nesting lock >*/ + } + + // observers +private: + /** + * return @c the owned mutex. + */ + const mutex_type* mutex() const BOOST_NOEXCEPT + { + return tmp_lk_.mutex(); + } +public: + /** + * @return whether if this lock is locking that mutex. + */ + bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT + { + return l == mutex(); + } + + //BOOST_ADRESS_OF_DELETE(nested_strict_lock) + //BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock) + + private: + Lock& lk_; + Lock tmp_lk_; + }; + //] + + template + struct is_strict_lock_sur_parolle > : true_type + { + }; + +} +#include + +#endif diff --git a/include/boost/thread/synchronized_value.hpp b/include/boost/thread/synchronized_value.hpp new file mode 100644 index 00000000..3d14f001 --- /dev/null +++ b/include/boost/thread/synchronized_value.hpp @@ -0,0 +1,267 @@ +// (C) Copyright 2010 Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_SYNCHRONIZED_VALUE_HPP +#define BOOST_THREAD_SYNCHRONIZED_VALUE_HPP + +#include +#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES + +#include +#include +#include + +#include + +namespace boost +{ + /** + * + */ + template + class synchronized_value + { + public: + typedef T value_type; + typedef Lockable lockable_type; + private: + T value_; + mutable lockable_type mtx_; + public: + synchronized_value() + : value_() + { + } + + synchronized_value(T other) + : value_(other) + { + } + + /** + * + */ + struct const_strict_synchronizer + { + protected: + friend class synchronized_value; + + boost::unique_lock lk_; + T const& value_; + + explicit const_strict_synchronizer(synchronized_value const& outer) : + lk_(outer.mtx_), value_(outer.value_) + { + } + public: + BOOST_THREAD_NO_COPYABLE( const_strict_synchronizer ) + + const_strict_synchronizer(const_strict_synchronizer&& other) + : lk_(boost::move(other.lk_)),value_(other.value_) + { + } + + ~const_strict_synchronizer() + { + } + + const T* operator->() const + { + return &value_; + } + + const T& operator*() const + { + return value_; + } + + }; + + /** + * + */ + struct strict_synchronizer : const_strict_synchronizer + { + protected: + friend class synchronized_value; + + explicit strict_synchronizer(synchronized_value& outer) : + const_strict_synchronizer(const_cast(outer)) + { + } + public: + BOOST_THREAD_NO_COPYABLE( strict_synchronizer ) + + strict_synchronizer(strict_synchronizer&& other) + : const_strict_synchronizer(boost::move(other)) + { + } + + ~strict_synchronizer() + { + } + + T* operator->() + { + return const_cast(&this->value_); + } + + T& operator*() + { + return const_cast(this->value_); + } + + }; + + + strict_synchronizer operator->() + { + return BOOST_THREAD_MAKE_RV_REF(strict_synchronizer(*this)); + } + const_strict_synchronizer operator->() const + { + return BOOST_THREAD_MAKE_RV_REF(const_strict_synchronizer(*this)); + } + + strict_synchronizer synchronize() + { + return BOOST_THREAD_MAKE_RV_REF(strict_synchronizer(*this)); + } + const_strict_synchronizer synchronize() const + { + return BOOST_THREAD_MAKE_RV_REF(const_strict_synchronizer(*this)); + } + + /** + * + */ + struct unique_synchronizer : unique_lock + { + private: + friend class synchronized_value; + typedef unique_lock base_type; + + T& value_; + + explicit unique_synchronizer(synchronized_value& outer) + : base_type(outer.mtx_), value_(outer.value_) + { + } + public: + BOOST_THREAD_NO_COPYABLE(unique_synchronizer) + + unique_synchronizer(unique_synchronizer&& other): + base_type(static_cast(other)),value_(other.value_) + { + } + + ~unique_synchronizer() + { + } + + T* operator->() + { + if (this->owns_lock()) + return &value_; + else + return 0; + } + + const T* operator->() const + { + if (this->owns_lock()) + return &value_; + else + return 0; + } + + T& operator*() + { + BOOST_ASSERT (this->owns_lock()); + return value_; + } + + const T& operator*() const + { + BOOST_ASSERT (this->owns_lock()); + return value_; + } + + }; + + private: + class deref_value + { + private: + friend class synchronized_value; + + boost::unique_lock lk_; + T& value_; + + explicit deref_value(synchronized_value& outer): + lk_(outer.mtx_),value_(outer.value_) + {} + + public: + BOOST_THREAD_NO_COPYABLE(deref_value) + deref_value(deref_value&& other): + lk_(boost::move(other.lk_)),value_(other.value_) + {} + operator T() + { + return value_; + } + + deref_value& operator=(T const& newVal) + { + value_=newVal; + return *this; + } + }; + class const_deref_value + { + private: + friend class synchronized_value; + + boost::unique_lock lk_; + const T& value_; + + explicit const_deref_value(synchronized_value const& outer): + lk_(outer.mtx_), value_(outer.value_) + {} + + public: + BOOST_THREAD_NO_COPYABLE(const_deref_value) + const_deref_value(const_deref_value&& other): + lk_(boost::move(other.lk_)), value_(other.value_) + {} + + operator T() + { + return value_; + } + }; + + public: + deref_value operator*() + { + return BOOST_THREAD_MAKE_RV_REF(deref_value(*this)); + } + + const_deref_value operator*() const + { + return BOOST_THREAD_MAKE_RV_REF(const_deref_value(*this)); + } + + }; + +} + +#include + +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES +#endif // header diff --git a/include/boost/thread/testable_mutex.hpp b/include/boost/thread/testable_mutex.hpp new file mode 100644 index 00000000..b0829213 --- /dev/null +++ b/include/boost/thread/testable_mutex.hpp @@ -0,0 +1,142 @@ +// (C) Copyright 2012 Vicente J. Botet Escriba +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + + +#ifndef BOOST_THREAD_TESTABLE_LOCKABLE_HPP +#define BOOST_THREAD_TESTABLE_LOCKABLE_HPP + +#include + +#include + +#include +#include + +#include + +namespace boost +{ + /** + * Based on Associate Mutexes with Data to Prevent Races, By Herb Sutter, May 13, 2010 + * http://www.drdobbs.com/windows/associate-mutexes-with-data-to-prevent-r/224701827?pgno=3 + * + * Make our mutex testable if it isn't already. + * + * Many mutex services (including boost::mutex) don't provide a way to ask, + * "Do I already hold a lock on this mutex?" + * Sometimes it is needed to know if a method like is_held to be available. + * This wrapper associates an arbitrary lockable type with a thread id that stores the ID of the thread that + * currently holds the lockable. The thread id initially holds an invalid value that means no threads own the mutex. + * When we acquire a lock, we set the thread id; and when we release a lock, we reset it back to its default no id state. + * + */ + template + class testable_mutex + { + Lockable mtx_; + atomic id_; + public: + /// the type of the wrapped lockable + typedef Lockable lockable_type; + + /// Non copyable + BOOST_THREAD_NO_COPYABLE(testable_mutex) + + void lock() + { + mtx_.lock(); + id_ = this_thread::get_id(); + } + + void unlock() + { + BOOST_ASSERT(is_locked(mtx_)); + id_ = thread::id(); + mtx_.unlock(); + } + + bool try_lock() + { + if (mtx_.try_lock()) + { + id_ = this_thread::get_id(); + return true; + } + else + { + return false; + } + } +#ifdef BOOST_THREAD_USES_CHRONO + template + bool try_lock_for(const chrono::duration& rel_time) + { + if (mtx_.try_lock_for(rel_time)) + { + id_ = this_thread::get_id(); + return true; + } + else + { + return false; + } + } + template + bool try_lock_until(const chrono::time_point& abs_time) + { + if (mtx_.try_lock_until(abs_time)) + { + id_ = this_thread::get_id(); + return true; + } + else + { + return false; + } + } +#endif + + bool is_locked_by_this_thread() + { + return this_thread::get_id() == id_; + } + + bool get_id() + { + return id_; + } + + // todo add the shared and upgrade mutex functions + }; + + template + struct is_testable_lockable : false_type + {}; + + template + struct is_testable_lockable > : true_type + {}; + +// /** +// * Overloaded function used to check if the mutex is locked when it is testable and do nothing otherwise. +// * +// * This function is used usually to assert the pre-condition when the function can only be called when the mutex +// * must be locked by the current thread. +// */ +// template +// bool is_locked_by_this_thread(testable_mutex const& mtx) +// { +// return mtx.is_locked(); +// } +// template +// bool is_locked_by_this_thread(Lockable const&) +// { +// return true; +// } +} + +#include + +#endif // header diff --git a/include/boost/thread/thread.hpp b/include/boost/thread/thread.hpp index ee15c6e3..6316aa14 100644 --- a/include/boost/thread/thread.hpp +++ b/include/boost/thread/thread.hpp @@ -20,7 +20,9 @@ #endif #include +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS #include +#endif #include #include diff --git a/include/boost/thread/thread_functors.hpp b/include/boost/thread/thread_functors.hpp new file mode 100644 index 00000000..c36bbb7e --- /dev/null +++ b/include/boost/thread/thread_functors.hpp @@ -0,0 +1,56 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +// Based on the Anthony's idea of scoped_thread in CCiA + +#ifndef BOOST_THREAD_THREAD_FUNCTORS_HPP +#define BOOST_THREAD_THREAD_FUNCTORS_HPP + +#include +#include +#include +#include + +#include + +namespace boost +{ + + struct detach + { + void operator()(thread& t) + { + t.detach(); + } + }; + + struct join_if_joinable + { + void operator()(thread& t) + { + if (t.joinable()) + { + t.join(); + } + } + }; + + struct interrupt_and_join_if_joinable + { + void operator()(thread& t) + { + t.interrupt(); + if (t.joinable()) + { + t.join(); + } + } + }; + +} +#include + +#endif diff --git a/include/boost/thread/thread_guard.hpp b/include/boost/thread/thread_guard.hpp new file mode 100644 index 00000000..85157f10 --- /dev/null +++ b/include/boost/thread/thread_guard.hpp @@ -0,0 +1,46 @@ +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// (C) Copyright 2009-2012 Anthony Williams +// (C) Copyright 2012 Vicente J. Botet Escriba + +// Based on the Anthony's idea of thread_joiner in CCiA + +#ifndef BOOST_THREAD_THREAD_GUARD_HPP +#define BOOST_THREAD_THREAD_GUARD_HPP + +#include +#include +#include + +#include + +namespace boost +{ + + /** + * Non-copyable RAII scoped thread guard joiner which join the thread if joinable when destroyed. + */ + template + class thread_guard + { + thread& t_; + public: + BOOST_THREAD_NO_COPYABLE( thread_guard) + + explicit thread_guard(thread& t) : + t_(t) + { + } + ~thread_guard() + { + CallableThread on_destructor; + + on_destructor(t_); + } + }; + +} +#include + +#endif diff --git a/include/boost/thread/v2/thread.hpp b/include/boost/thread/v2/thread.hpp index d686c5fe..331c2945 100644 --- a/include/boost/thread/v2/thread.hpp +++ b/include/boost/thread/v2/thread.hpp @@ -9,9 +9,10 @@ #include #ifdef BOOST_THREAD_USES_CHRONO #include +#include #endif #include -#include +#include namespace boost { @@ -20,15 +21,6 @@ namespace boost #ifdef BOOST_THREAD_USES_CHRONO - template - void sleep_for(const chrono::duration& d) - { - using namespace chrono; - nanoseconds ns = duration_cast (d); - if (ns < d) ++ns; - sleep_for(ns); - } - template void sleep_until(const chrono::time_point& t) { @@ -40,6 +32,28 @@ namespace boost cv.wait_until(lk, t); } +#ifdef BOOST_THREAD_SLEEP_FOR_IS_STEADY + + template + void sleep_for(const chrono::duration& d) + { + using namespace chrono; + if (d > duration::zero()) + { + duration Max = nanoseconds::max(); + nanoseconds ns; + if (d < Max) + { + ns = duration_cast(d); + if (ns < d) + ++ns; + } + else + ns = nanoseconds::max(); + sleep_for(ns); + } + } + template inline BOOST_SYMBOL_VISIBLE void sleep_until(const chrono::time_point& t) @@ -47,6 +61,22 @@ namespace boost using namespace chrono; sleep_for(t - steady_clock::now()); } +#else + template + void sleep_for(const chrono::duration& d) + { + using namespace chrono; + if (d > duration::zero()) + { + steady_clock::time_point c_now = steady_clock::now(); + do + { + sleep_until(system_clock::now() + ceil(d)); + } while (steady_clock::now() - c_now < d ); + } + } + +#endif #endif } diff --git a/include/boost/thread/win32/basic_recursive_mutex.hpp b/include/boost/thread/win32/basic_recursive_mutex.hpp index e259121a..cfdfa043 100644 --- a/include/boost/thread/win32/basic_recursive_mutex.hpp +++ b/include/boost/thread/win32/basic_recursive_mutex.hpp @@ -58,6 +58,7 @@ namespace boost recursion_count=1; } } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(::boost::system_time const& target) { long const current_thread_id=win32::GetCurrentThreadId(); @@ -68,6 +69,7 @@ namespace boost { return timed_lock(get_system_time()+timeout); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -114,6 +116,7 @@ namespace boost return false; } +#if defined BOOST_THREAD_USES_DATETIME bool try_timed_lock(long current_thread_id,::boost::system_time const& target) { if(mutex.timed_lock(target)) @@ -124,6 +127,7 @@ namespace boost } return false; } +#endif template bool try_timed_lock_until(long current_thread_id,TP const& target) { diff --git a/include/boost/thread/win32/basic_timed_mutex.hpp b/include/boost/thread/win32/basic_timed_mutex.hpp index 6a430774..5d85c70d 100644 --- a/include/boost/thread/win32/basic_timed_mutex.hpp +++ b/include/boost/thread/win32/basic_timed_mutex.hpp @@ -14,7 +14,9 @@ #include #include #include +#if defined BOOST_THREAD_USES_DATETIME #include +#endif #include #ifdef BOOST_THREAD_USES_CHRONO #include @@ -118,6 +120,7 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME bool timed_lock(::boost::system_time const& wait_until) { if(try_lock()) @@ -147,7 +150,6 @@ namespace boost return true; } - template bool timed_lock(Duration const& timeout) { @@ -158,7 +160,7 @@ namespace boost { return timed_lock(system_time(timeout)); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template bool try_lock_for(const chrono::duration& rel_time) diff --git a/include/boost/thread/win32/condition_variable.hpp b/include/boost/thread/win32/condition_variable.hpp index 4c893add..5cf81fc9 100644 --- a/include/boost/thread/win32/condition_variable.hpp +++ b/include/boost/thread/win32/condition_variable.hpp @@ -11,9 +11,13 @@ #include #include #include +#if defined BOOST_THREAD_USES_DATETIME #include +#endif #include #include +#include +#include #include #include @@ -195,7 +199,7 @@ namespace boost ~entry_manager() { - if(! entry->is_notified()) + //if(! entry->is_notified()) // several regression #7657 { entry->remove_waiter(); } @@ -321,6 +325,7 @@ namespace boost } +#if defined BOOST_THREAD_USES_DATETIME bool timed_wait(unique_lock& m,boost::system_time const& abs_time) { return do_wait(m,abs_time); @@ -351,7 +356,7 @@ namespace boost { return do_wait(m,wait_duration.total_milliseconds(),pred); } - +#endif #ifdef BOOST_THREAD_USES_CHRONO template @@ -428,6 +433,7 @@ namespace boost while(!pred()) wait(m); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_wait(lock_type& m,boost::system_time const& abs_time) { @@ -463,6 +469,7 @@ namespace boost { return do_wait(m,wait_duration.total_milliseconds(),pred); } +#endif #ifdef BOOST_THREAD_USES_CHRONO template diff --git a/include/boost/thread/win32/mutex.hpp b/include/boost/thread/win32/mutex.hpp index 85a00e29..01544784 100644 --- a/include/boost/thread/win32/mutex.hpp +++ b/include/boost/thread/win32/mutex.hpp @@ -8,7 +8,10 @@ #include #include -#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif +#include #include @@ -33,8 +36,10 @@ namespace boost destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_lock; typedef detail::try_lock_wrapper scoped_try_lock; +#endif }; typedef mutex try_mutex; @@ -54,9 +59,11 @@ namespace boost destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_timed_lock; typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/include/boost/thread/win32/once.hpp b/include/boost/thread/win32/once.hpp index 3066b50b..0a00cb3e 100644 --- a/include/boost/thread/win32/once.hpp +++ b/include/boost/thread/win32/once.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -157,9 +158,7 @@ namespace boost status=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&flag.status,running_value,0); if(!status) { -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { if(!event_handle) { @@ -187,8 +186,7 @@ namespace boost } break; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { BOOST_INTERLOCKED_EXCHANGE(&flag.status,0); if(!event_handle) @@ -199,9 +197,9 @@ namespace boost { ::boost::detail::win32::SetEvent(event_handle); } - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } if(!counted) diff --git a/include/boost/thread/win32/recursive_mutex.hpp b/include/boost/thread/win32/recursive_mutex.hpp index 5144e77a..1f0f7f5e 100644 --- a/include/boost/thread/win32/recursive_mutex.hpp +++ b/include/boost/thread/win32/recursive_mutex.hpp @@ -12,7 +12,10 @@ #include #include -#include +#include +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS +#include +#endif #include @@ -32,8 +35,10 @@ namespace boost ::boost::detail::basic_recursive_mutex::destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_lock; typedef detail::try_lock_wrapper scoped_try_lock; +#endif }; typedef recursive_mutex recursive_try_mutex; @@ -52,9 +57,11 @@ namespace boost ::boost::detail::basic_recursive_timed_mutex::destroy(); } +#if defined BOOST_THREAD_PROVIDES_NESTED_LOCKS typedef unique_lock scoped_timed_lock; typedef detail::try_lock_wrapper scoped_try_lock; typedef scoped_timed_lock scoped_lock; +#endif }; } diff --git a/include/boost/thread/win32/shared_mutex.hpp b/include/boost/thread/win32/shared_mutex.hpp index fef2d5ba..94269489 100644 --- a/include/boost/thread/win32/shared_mutex.hpp +++ b/include/boost/thread/win32/shared_mutex.hpp @@ -136,12 +136,12 @@ namespace boost BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel())); } +#if defined BOOST_THREAD_USES_DATETIME template bool timed_lock_shared(TimeDuration const & relative_time) { return timed_lock_shared(get_system_time()+relative_time); } - bool timed_lock_shared(boost::system_time const& wait_until) { for(;;) @@ -220,6 +220,7 @@ namespace boost BOOST_ASSERT(res==0); } } +#endif #ifdef BOOST_THREAD_USES_CHRONO template diff --git a/include/boost/thread/win32/thread_data.hpp b/include/boost/thread/win32/thread_data.hpp index 18fd7cbb..48ba8728 100644 --- a/include/boost/thread/win32/thread_data.hpp +++ b/include/boost/thread/win32/thread_data.hpp @@ -22,6 +22,11 @@ #include +#ifdef BOOST_MSVC +#pragma warning(push) +#pragma warning(disable:4251) +#endif + namespace boost { class condition_variable; @@ -67,6 +72,7 @@ namespace boost namespace detail { + struct future_object_base; struct tss_cleanup_function; struct thread_exit_callback_node; struct tss_data_node @@ -88,24 +94,35 @@ namespace boost { long count; detail::win32::handle_manager thread_handle; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS detail::win32::handle_manager interruption_handle; +#endif boost::detail::thread_exit_callback_node* thread_exit_callbacks; std::map tss_data; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS bool interruption_enabled; +#endif unsigned id; typedef std::vector //, hidden_allocator > > notify_list_t; notify_list_t notify; + typedef std::vector > async_states_t; + async_states_t async_states_; thread_data_base(): count(0),thread_handle(detail::win32::invalid_handle_value), +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)), +#endif thread_exit_callbacks(0),tss_data(), +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interruption_enabled(true), +#endif id(0), - notify() + notify(), + async_states_() {} virtual ~thread_data_base(); @@ -122,11 +139,12 @@ namespace boost } } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void interrupt() { BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0); } - +#endif typedef detail::win32::handle native_handle_type; virtual void run()=0; @@ -136,7 +154,13 @@ namespace boost notify.push_back(std::pair(cv, m)); } + void make_ready_at_thread_exit(shared_ptr as) + { + async_states_.push_back(as); + } + }; + BOOST_THREAD_DECL thread_data_base* get_current_thread_data(); typedef boost::intrusive_ptr thread_data_ptr; @@ -235,7 +259,6 @@ namespace boost { interruptible_wait(detail::win32::invalid_handle_value,abs_time); } - template inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time) { @@ -255,6 +278,10 @@ namespace boost } +#ifdef BOOST_MSVC +#pragma warning(pop) +#endif + #include #endif diff --git a/include/boost/thread/win32/thread_heap_alloc.hpp b/include/boost/thread/win32/thread_heap_alloc.hpp index 9b6d3902..1832dbcf 100644 --- a/include/boost/thread/win32/thread_heap_alloc.hpp +++ b/include/boost/thread/win32/thread_heap_alloc.hpp @@ -5,10 +5,12 @@ #ifndef THREAD_HEAP_ALLOC_HPP #define THREAD_HEAP_ALLOC_HPP #include +#include #include #include #include #include +#include #if defined( BOOST_USE_WINDOWS_H ) # include @@ -75,20 +77,17 @@ namespace boost inline T* heap_new() { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES @@ -96,159 +95,135 @@ namespace boost inline T* heap_new(A1&& a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast(a1)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template inline T* heap_new(A1&& a1,A2&& a2) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template inline T* heap_new(A1&& a1,A2&& a2,A3&& a3) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), static_cast(a3)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(static_cast(a1),static_cast(a2), static_cast(a3),static_cast(a4)); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } #else template inline T* heap_new_impl(A1 a1) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template inline T* heap_new_impl(A1 a1,A2 a2) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1,a2); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template inline T* heap_new_impl(A1 a1,A2 a2,A3 a3) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1,a2,a3); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } template inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4) { void* const heap_memory=allocate_raw_heap_memory(sizeof(T)); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { T* const data=new (heap_memory) T(a1,a2,a3,a4); return data; } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { free_raw_heap_memory(heap_memory); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } diff --git a/include/boost/thread/win32/thread_primitives.hpp b/include/boost/thread/win32/thread_primitives.hpp index c0dba111..e2c1aad9 100644 --- a/include/boost/thread/win32/thread_primitives.hpp +++ b/include/boost/thread/win32/thread_primitives.hpp @@ -232,7 +232,7 @@ namespace boost BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0); } - class handle_manager + class BOOST_THREAD_DECL handle_manager { private: handle handle_to_manage; diff --git a/include/boost/thread/xtime.hpp b/include/boost/thread/xtime.hpp index 1ca996fa..9c6a3596 100644 --- a/include/boost/thread/xtime.hpp +++ b/include/boost/thread/xtime.hpp @@ -9,6 +9,7 @@ #define BOOST_XTIME_WEK070601_HPP #include +#if defined BOOST_THREAD_USES_DATETIME #include #include @@ -88,5 +89,5 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2) } // namespace boost #include - +#endif #endif //BOOST_XTIME_WEK070601_HPP diff --git a/src/pthread/thread.cpp b/src/pthread/thread.cpp index 4321a268..f6ec12ae 100644 --- a/src/pthread/thread.cpp +++ b/src/pthread/thread.cpp @@ -1,20 +1,23 @@ // Copyright (C) 2001-2003 // William E. Kempf // Copyright (C) 2007-8 Anthony Williams -// (C) Copyright 2011 Vicente J. Botet Escriba +// (C) Copyright 2011-2012 Vicente J. Botet Escriba // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 #include #include +#if defined BOOST_THREAD_USES_DATETIME #include +#endif #include #include #include #include -#include +#include #ifdef __GLIBC__ #include @@ -33,14 +36,17 @@ namespace boost { thread_data_base::~thread_data_base() { - { for (notify_list_t::iterator i = notify.begin(), e = notify.end(); i != e; ++i) { i->second->unlock(); i->first->notify_all(); } - } + for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end(); + i != e; ++i) + { + (*i)->make_ready(); + } } struct thread_exit_callback_node @@ -72,6 +78,7 @@ namespace boost { while(!thread_info->tss_data.empty() || thread_info->thread_exit_callbacks) { + while(thread_info->thread_exit_callbacks) { detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks; @@ -97,7 +104,10 @@ namespace boost thread_info->tss_data.erase(current); } } - thread_info->self.reset(); + if (thread_info) // fixme: should we test this? + { + thread_info->self.reset(); + } } } } @@ -148,26 +158,33 @@ namespace boost boost::detail::thread_data_ptr thread_info = static_cast(param)->self; thread_info->self.reset(); detail::set_current_thread_data(thread_info.get()); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS BOOST_TRY { +#endif thread_info->run(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + } BOOST_CATCH (thread_interrupted const&) { } - BOOST_CATCH_END // Removed as it stops the debugger identifying the cause of the exception // Unhandled exceptions still cause the application to terminate // BOOST_CATCH(...) // { +// throw; +// // std::terminate(); // } - + BOOST_CATCH_END +#endif detail::tls_destructor(thread_info.get()); detail::set_current_thread_data(0); boost::lock_guard lock(thread_info->data_mutex); thread_info->done=true; thread_info->done_condition.notify_all(); + return 0; } } @@ -177,7 +194,9 @@ namespace boost { externally_launched_thread() { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interrupt_enabled=false; +#endif } void run() @@ -215,18 +234,20 @@ namespace boost thread::thread() BOOST_NOEXCEPT {} - void thread::start_thread() + bool thread::start_thread_noexcept() { thread_info->self=thread_info; int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get()); if (res != 0) { thread_info->self.reset(); - boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create")); + return false; +// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create")); } + return true; } - void thread::start_thread(const attributes& attr) + bool thread::start_thread_noexcept(const attributes& attr) { thread_info->self=thread_info; const attributes::native_handle_type* h = attr.native_handle(); @@ -234,14 +255,16 @@ namespace boost if (res != 0) { thread_info->self.reset(); - boost::throw_exception(thread_resource_error()); + return false; +// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_create")); } int detached_state; res = pthread_attr_getdetachstate(h, &detached_state); if (res != 0) { thread_info->self.reset(); - boost::throw_exception(thread_resource_error()); + return false; +// boost::throw_exception(thread_resource_error(res, "boost thread: failed in pthread_attr_getdetachstate")); } if (PTHREAD_CREATE_DETACHED==detached_state) { @@ -259,6 +282,7 @@ namespace boost } } } + return true; } @@ -268,12 +292,8 @@ namespace boost return thread_info; } - void thread::join() + bool thread::join_noexcept() { - if (this_thread::get_id() == get_id()) - { - boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself")); - } detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { @@ -312,21 +332,16 @@ namespace boost { thread_info.reset(); } + return true; } else { -#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED - boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); -#endif + return false; } } - bool thread::do_try_join_until(struct timespec const &timeout) + bool thread::do_try_join_until_noexcept(struct timespec const &timeout, bool& res) { - if (this_thread::get_id() == get_id()) - { - boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself")); - } detail::thread_data_ptr const local_thread_info=(get_thread_info)(); if(local_thread_info) { @@ -336,9 +351,10 @@ namespace boost unique_lock lock(local_thread_info->data_mutex); while(!local_thread_info->done) { - if(!local_thread_info->done_condition.do_timed_wait(lock,timeout)) + if(!local_thread_info->done_condition.do_wait_until(lock,timeout)) { - return false; + res=false; + return true; } } do_join=!local_thread_info->join_started; @@ -368,13 +384,12 @@ namespace boost { thread_info.reset(); } + res=true; return true; } else { -#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED - boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); -#endif + return false; } } @@ -403,61 +418,95 @@ namespace boost namespace this_thread { - -#ifdef __DECXXX - /// Workaround of DECCXX issue of incorrect template substitution - template<> -#endif - void sleep(const system_time& st) + namespace hiden + { + void BOOST_THREAD_DECL sleep_for(const timespec& ts) { - detail::thread_data_base* const thread_info=detail::get_current_thread_data(); + boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data(); if(thread_info) { - unique_lock lk(thread_info->sleep_mutex); - while(thread_info->sleep_condition.timed_wait(lk,st)) {} + unique_lock lk(thread_info->sleep_mutex); + while( thread_info->sleep_condition.do_wait_for(lk,ts)) {} } else { - xtime const xt=get_xtime(st); - for (int foo=0; foo < 5; ++foo) - { -# if defined(BOOST_HAS_PTHREAD_DELAY_NP) - timespec ts; - to_timespec_duration(xt, ts); - BOOST_VERIFY(!pthread_delay_np(&ts)); -# elif defined(BOOST_HAS_NANOSLEEP) - timespec ts; - to_timespec_duration(xt, ts); + if (boost::detail::timespec_ge(ts, boost::detail::timespec_zero())) + { - // nanosleep takes a timespec that is an offset, not - // an absolute time. - nanosleep(&ts, 0); -# else - mutex mx; - mutex::scoped_lock lock(mx); - condition cond; - cond.timed_wait(lock, xt); -# endif - xtime cur; - xtime_get(&cur, TIME_UTC_); - if (xtime_cmp(xt, cur) <= 0) - return; - } + # if defined(BOOST_HAS_PTHREAD_DELAY_NP) + BOOST_VERIFY(!pthread_delay_np(&ts)); + # elif defined(BOOST_HAS_NANOSLEEP) + // nanosleep takes a timespec that is an offset, not + // an absolute time. + nanosleep(&ts, 0); + # else + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.do_wait_for(lock, ts); + # endif + } } } + void BOOST_THREAD_DECL sleep_until(const timespec& ts) + { + boost::detail::thread_data_base* const thread_info=boost::detail::get_current_thread_data(); + + if(thread_info) + { + unique_lock lk(thread_info->sleep_mutex); + while(thread_info->sleep_condition.do_wait_until(lk,ts)) {} + } + else + { + timespec now = boost::detail::timespec_now(); + if (boost::detail::timespec_gt(ts, now)) + { + for (int foo=0; foo < 5; ++foo) + { + + # if defined(BOOST_HAS_PTHREAD_DELAY_NP) + timespec d = boost::detail::timespec_minus(ts, now); + BOOST_VERIFY(!pthread_delay_np(&d)); + # elif defined(BOOST_HAS_NANOSLEEP) + // nanosleep takes a timespec that is an offset, not + // an absolute time. + timespec d = boost::detail::timespec_minus(ts, now); + nanosleep(&d, 0); + # else + mutex mx; + unique_lock lock(mx); + condition_variable cond; + cond.do_wait_until(lock, ts); + # endif + timespec now2 = boost::detail::timespec_now(); + if (boost::detail::timespec_ge(now2, ts)) + { + return; + } + } + } + } + } + } // hiden + } // this_thread + namespace this_thread + { void yield() BOOST_NOEXCEPT { # if defined(BOOST_HAS_SCHED_YIELD) BOOST_VERIFY(!sched_yield()); # elif defined(BOOST_HAS_PTHREAD_YIELD) BOOST_VERIFY(!pthread_yield()); -# else - xtime xt; - xtime_get(&xt, TIME_UTC_); - sleep(xt); +# elif defined BOOST_THREAD_USES_DATETIME +// xtime xt; +// xtime_get(&xt, TIME_UTC_); +// sleep(xt); +//# else + sleep_for(chrono::milliseconds(0)); # endif } } @@ -479,24 +528,7 @@ namespace boost #endif } - thread::id thread::get_id() const BOOST_NOEXCEPT - { - #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID - //return local_thread_info->thread_handle; - return const_cast(this)->native_handle(); - #else - detail::thread_data_ptr const local_thread_info=(get_thread_info)(); - if(local_thread_info) - { - return id(local_thread_info); - } - else - { - return id(); - } - #endif - } - +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void thread::interrupt() { detail::thread_data_ptr const local_thread_info=(get_thread_info)(); @@ -525,6 +557,7 @@ namespace boost return false; } } +#endif thread::native_handle_type thread::native_handle() { @@ -542,18 +575,9 @@ namespace boost +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS namespace this_thread { - thread::id get_id() BOOST_NOEXCEPT - { - #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID - return pthread_self(); - #else - boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data(); - return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr()); - #endif - } - void interruption_point() { #ifndef BOOST_NO_EXCEPTIONS @@ -623,6 +647,7 @@ namespace boost } } } +#endif namespace detail { diff --git a/src/pthread/timeconv.inl b/src/pthread/timeconv.inl index cab7c55a..d81f31ba 100644 --- a/src/pthread/timeconv.inl +++ b/src/pthread/timeconv.inl @@ -17,6 +17,7 @@ const int NANOSECONDS_PER_MILLISECOND = 1000000; const int MICROSECONDS_PER_SECOND = 1000000; const int NANOSECONDS_PER_MICROSECOND = 1000; +#if defined BOOST_THREAD_USES_DATETIME inline void to_time(int milliseconds, boost::xtime& xt) { int res = 0; @@ -33,7 +34,9 @@ inline void to_time(int milliseconds, boost::xtime& xt) xt.nsec -= NANOSECONDS_PER_SECOND; } } +#endif #if defined(BOOST_HAS_PTHREADS) +#if defined BOOST_THREAD_USES_DATETIME inline void to_timespec(const boost::xtime& xt, timespec& ts) { ts.tv_sec = static_cast(xt.sec); @@ -44,14 +47,27 @@ inline void to_timespec(const boost::xtime& xt, timespec& ts) ts.tv_nsec %= NANOSECONDS_PER_SECOND; } } - +#endif inline void to_time(int milliseconds, timespec& ts) { +#if defined BOOST_THREAD_USES_DATETIME boost::xtime xt; to_time(milliseconds, xt); to_timespec(xt, ts); +#else + ts.tv_sec += (milliseconds / MILLISECONDS_PER_SECOND); + ts.tv_nsec += ((milliseconds % MILLISECONDS_PER_SECOND) * + NANOSECONDS_PER_MILLISECOND); + + if (ts.tv_nsec >= NANOSECONDS_PER_SECOND) + { + ++ts.tv_sec; + ts.tv_nsec -= NANOSECONDS_PER_SECOND; + } +#endif } +#if defined BOOST_THREAD_USES_DATETIME inline void to_timespec_duration(const boost::xtime& xt, timespec& ts) { boost::xtime cur; @@ -82,7 +98,9 @@ inline void to_timespec_duration(const boost::xtime& xt, timespec& ts) } } #endif +#endif +#if defined BOOST_THREAD_USES_DATETIME inline void to_duration(boost::xtime xt, int& milliseconds) { boost::xtime cur; @@ -126,6 +144,7 @@ inline void to_microduration(boost::xtime xt, int& microseconds) NANOSECONDS_PER_MICROSECOND); } } +#endif } // Change Log: diff --git a/src/win32/thread.cpp b/src/win32/thread.cpp index 5a26f5eb..e9c0eafe 100644 --- a/src/win32/thread.cpp +++ b/src/win32/thread.cpp @@ -3,6 +3,7 @@ // http://www.boost.org/LICENSE_1_0.txt) // (C) Copyright 2007 Anthony Williams // (C) Copyright 2007 David Deakins +// (C) Copyright 2011-2012 Vicente J. Botet Escriba #ifndef _WIN32_WINNT #define _WIN32_WINNT 0x400 @@ -11,17 +12,19 @@ #ifndef WINVER #define WINVER 0x400 #endif +#define BOOST_THREAD_VERSION 2 #include #include #include #include #include +#include #include -#include +#if defined BOOST_THREAD_USES_DATETIME #include - +#endif #include #include #ifndef UNDER_CE @@ -36,16 +39,20 @@ namespace boost { thread_data_base::~thread_data_base() { - { for (notify_list_t::iterator i = notify.begin(), e = notify.end(); i != e; ++i) { i->second->unlock(); i->first->notify_all(); } - } + for (async_states_t::iterator i = async_states_.begin(), e = async_states_.end(); + i != e; ++i) + { + (*i)->make_ready(); + } } } + namespace { #ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11 @@ -75,24 +82,34 @@ namespace boost } } - detail::thread_data_base* get_current_thread_data() - { - if(current_thread_tls_key==TLS_OUT_OF_INDEXES) - { - return 0; - } - return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); - } - void set_current_thread_data(detail::thread_data_base* new_data) { boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key); - if(current_thread_tls_key!=TLS_OUT_OF_INDEXES) + if (current_thread_tls_key!=TLS_OUT_OF_INDEXES) + { BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data)); + } else - boost::throw_exception(thread_resource_error()); + { + BOOST_VERIFY(false); + //boost::throw_exception(thread_resource_error()); + } } + } + namespace detail + { + thread_data_base* get_current_thread_data() + { + if(current_thread_tls_key==TLS_OUT_OF_INDEXES) + { + return 0; + } + return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key); + } + } + namespace + { #ifndef BOOST_HAS_THREADEX // Windows CE doesn't define _beginthreadex @@ -151,7 +168,7 @@ namespace boost { void run_thread_exit_callbacks() { - detail::thread_data_ptr current_thread_data(get_current_thread_data(),false); + detail::thread_data_ptr current_thread_data(detail::get_current_thread_data(),false); if(current_thread_data) { while(! current_thread_data->tss_data.empty() || current_thread_data->thread_exit_callbacks) @@ -190,23 +207,24 @@ namespace boost { detail::thread_data_base* const thread_info(reinterpret_cast(param)); set_current_thread_data(thread_info); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + BOOST_TRY { +#endif thread_info->run(); +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS } -#ifndef BOOST_NO_EXCEPTIONS - catch(thread_interrupted const&) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(thread_interrupted const&) { } -#endif // Removed as it stops the debugger identifying the cause of the exception // Unhandled exceptions still cause the application to terminate -// catch(...) // BOOST_NO_EXCEPTIONS protected +// BOOST_CATCH(...) // { // std::terminate(); // } + BOOST_CATCH_END +#endif run_thread_exit_callbacks(); return 0; } @@ -215,29 +233,33 @@ namespace boost thread::thread() BOOST_NOEXCEPT {} - void thread::start_thread() + bool thread::start_thread_noexcept() { uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); if(!new_thread) { - boost::throw_exception(thread_resource_error()); + return false; +// boost::throw_exception(thread_resource_error()); } intrusive_ptr_add_ref(thread_info.get()); thread_info->thread_handle=(detail::win32::handle)(new_thread); ResumeThread(thread_info->thread_handle); + return true; } - void thread::start_thread(const attributes& attr) + bool thread::start_thread_noexcept(const attributes& attr) { //uintptr_t const new_thread=_beginthreadex(attr.get_security(),attr.get_stack_size(),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); uintptr_t const new_thread=_beginthreadex(0,static_cast(attr.get_stack_size()),&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id); if(!new_thread) { - boost::throw_exception(thread_resource_error()); + return false; +// boost::throw_exception(thread_resource_error()); } intrusive_ptr_add_ref(thread_info.get()); thread_info->thread_handle=(detail::win32::handle)(new_thread); ResumeThread(thread_info->thread_handle); + return true; } thread::thread(detail::thread_data_ptr data): @@ -252,7 +274,9 @@ namespace boost externally_launched_thread() { ++count; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS interruption_enabled=false; +#endif } void run() @@ -268,28 +292,25 @@ namespace boost void make_external_thread_data() { externally_launched_thread* me=detail::heap_new(); -#ifndef BOOST_NO_EXCEPTIONS - try // BOOST_NO_EXCEPTIONS protected -#endif + BOOST_TRY { set_current_thread_data(me); } -#ifndef BOOST_NO_EXCEPTIONS - catch(...) // BOOST_NO_EXCEPTIONS protected + BOOST_CATCH(...) { detail::heap_delete(me); - throw; // BOOST_NO_EXCEPTIONS protected + BOOST_RETHROW } -#endif + BOOST_CATCH_END } detail::thread_data_base* get_or_make_current_thread_data() { - detail::thread_data_base* current_thread_data(get_current_thread_data()); + detail::thread_data_base* current_thread_data(detail::get_current_thread_data()); if(!current_thread_data) { make_external_thread_data(); - current_thread_data=get_current_thread_data(); + current_thread_data=detail::get_current_thread_data(); } return current_thread_data; } @@ -311,52 +332,45 @@ namespace boost { return (get_thread_info)(); } - void thread::join() + bool thread::join_noexcept() { - if (this_thread::get_id() == get_id()) - { - boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself")); - } + detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel()); release_handle(); + return true; } else { -#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED - boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); -#endif + return false; } } +#if defined BOOST_THREAD_USES_DATETIME bool thread::timed_join(boost::system_time const& wait_until) { return do_try_join_until(get_milliseconds_until(wait_until)); } - - bool thread::do_try_join_until(uintmax_t milli) +#endif + bool thread::do_try_join_until_noexcept(uintmax_t milli, bool& res) { - if (this_thread::get_id() == get_id()) - { - boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself")); - } detail::thread_data_ptr local_thread_info=(get_thread_info)(); if(local_thread_info) { if(!this_thread::interruptible_wait(local_thread_info->thread_handle,milli)) { - return false; + res=false; + return true; } release_handle(); + res=true; return true; } else { -#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED - boost::throw_exception(thread_resource_error(system::errc::invalid_argument, "boost thread: thread not joinable")); -#endif + return false; } } @@ -370,6 +384,7 @@ namespace boost thread_info=0; } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void thread::interrupt() { detail::thread_data_ptr local_thread_info=(get_thread_info)(); @@ -391,6 +406,7 @@ namespace boost GetSystemInfo(&info); return info.dwNumberOfProcessors; } +#endif thread::native_handle_type thread::native_handle() { @@ -467,19 +483,22 @@ namespace boost detail::win32::handle handles[3]={0}; unsigned handle_count=0; unsigned wait_handle_index=~0U; +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS unsigned interruption_index=~0U; +#endif unsigned timeout_index=~0U; if(handle_to_wait_for!=detail::win32::invalid_handle_value) { wait_handle_index=handle_count; handles[handle_count++]=handle_to_wait_for; } - if(get_current_thread_data() && get_current_thread_data()->interruption_enabled) +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS + if(detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled) { interruption_index=handle_count; - handles[handle_count++]=get_current_thread_data()->interruption_handle; + handles[handle_count++]=detail::get_current_thread_data()->interruption_handle; } - +#endif detail::win32::handle_manager timer_handle; #ifndef UNDER_CE @@ -531,11 +550,13 @@ namespace boost { return true; } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS else if(notified_index==interruption_index) { - detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle); throw thread_interrupted(); } +#endif else if(notified_index==timeout_index) { return false; @@ -558,51 +579,53 @@ namespace boost thread::id get_id() BOOST_NOEXCEPT { #if defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID - //return detail::win32::GetCurrentThread(); return detail::win32::GetCurrentThreadId(); #else return thread::id(get_or_make_current_thread_data()); #endif } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS void interruption_point() { if(interruption_enabled() && interruption_requested()) { - detail::win32::ResetEvent(get_current_thread_data()->interruption_handle); + detail::win32::ResetEvent(detail::get_current_thread_data()->interruption_handle); throw thread_interrupted(); } } bool interruption_enabled() BOOST_NOEXCEPT { - return get_current_thread_data() && get_current_thread_data()->interruption_enabled; + return detail::get_current_thread_data() && detail::get_current_thread_data()->interruption_enabled; } bool interruption_requested() BOOST_NOEXCEPT { - return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0); + return detail::get_current_thread_data() && (detail::win32::WaitForSingleObject(detail::get_current_thread_data()->interruption_handle,0)==0); } +#endif void yield() BOOST_NOEXCEPT { detail::win32::Sleep(0); } +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS disable_interruption::disable_interruption() BOOST_NOEXCEPT: interruption_was_enabled(interruption_enabled()) { if(interruption_was_enabled) { - get_current_thread_data()->interruption_enabled=false; + detail::get_current_thread_data()->interruption_enabled=false; } } disable_interruption::~disable_interruption() BOOST_NOEXCEPT { - if(get_current_thread_data()) + if(detail::get_current_thread_data()) { - get_current_thread_data()->interruption_enabled=interruption_was_enabled; + detail::get_current_thread_data()->interruption_enabled=interruption_was_enabled; } } @@ -610,18 +633,19 @@ namespace boost { if(d.interruption_was_enabled) { - get_current_thread_data()->interruption_enabled=true; + detail::get_current_thread_data()->interruption_enabled=true; } } restore_interruption::~restore_interruption() BOOST_NOEXCEPT { - if(get_current_thread_data()) + if(detail::get_current_thread_data()) { - get_current_thread_data()->interruption_enabled=false; + detail::get_current_thread_data()->interruption_enabled=false; } } } +#endif namespace detail { @@ -716,7 +740,7 @@ namespace boost BOOST_THREAD_DECL void notify_all_at_thread_exit(condition_variable& cond, unique_lock lk) { - detail::thread_data_base* const current_thread_data(get_current_thread_data()); + detail::thread_data_base* const current_thread_data(detail::get_current_thread_data()); if(current_thread_data) { current_thread_data->notify_all_at_thread_exit(&cond, lk.release()); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 490eb5f9..d6801e0a 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -23,6 +23,8 @@ project : requirements multi + BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED + all gcc:-Wextra gcc:-pedantic @@ -43,7 +45,7 @@ project clang:-Wextra clang:-pedantic clang:-Wno-long-long - clang:-ansi + #clang:-ansi #clang:-fpermissive # doesn't work gcc-mingw-4.4.0:-fdiagnostics-show-option @@ -66,6 +68,19 @@ project #clang-3.0:-Wno-unused-function #clang-3.0:-Wno-unused-variable +# Note: Some of the remarks from the Intel compiler are disabled +# remark #193: zero used for undefined preprocessing identifier "XXX" +# remark #304: access control not specified ("public" by default) +# remark #593: variable "XXX" was set but never used +# remark #1418: external function definition with no prior declaration +# remark #2415: variable "XXX" of static storage duration was declared but never referenced + + intel:-wd193,304,383,444 + intel:-wd593,981 + intel:-wd1418 + intel:-wd2415 + + ; rule thread-run ( sources ) @@ -77,6 +92,7 @@ rule thread-run ( sources ) ; } + rule thread-test ( sources ) { return @@ -102,6 +118,18 @@ rule thread-run2 ( sources : name ) ; } +rule thread-run2-h ( sources : name ) +{ + return + [ run $(sources) : : : + /boost/system//boost_system + BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS + BOOST_THREAD_VERSION=3 + : $(name)_h ] + ; +} + + rule thread-run-lib2 ( sources : name ) { return @@ -187,10 +215,11 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run test_5542_3.cpp ] [ thread-run test_5891.cpp ] [ thread-run test_6130.cpp ] - [ thread-run test_6170.cpp ] + #[ thread-run test_6170.cpp ] [ thread-run test_6174.cpp ] - [ thread-run test_7160.cpp ] + #[ thread-run test_7160.cpp ] [ thread-run test_7328.cpp ] + [ thread-run test_7571.cpp ] ; @@ -228,7 +257,7 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/conditions/notify_all_at_thread_exit_pass.cpp : notify_all_at_thread_exit_p ] ; - explicit ts_async ; + #explicit ts_async ; test-suite ts_async : [ thread-run2 ./sync/futures/async/async_pass.cpp : async__async_p ] @@ -245,7 +274,17 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/futures/promise/get_future_pass.cpp : promise__get_future_p ] [ thread-run2 ./sync/futures/promise/move_ctor_pass.cpp : promise__move_ctor_p ] [ thread-run2 ./sync/futures/promise/move_assign_pass.cpp : promise__move_asign_p ] + [ thread-run2 ./sync/futures/promise/set_exception_pass.cpp : promise__set_exception_p ] + [ thread-run2 ./sync/futures/promise/set_lvalue_pass.cpp : promise__set_lvalue_p ] + [ thread-run2 ./sync/futures/promise/set_rvalue_pass.cpp : promise__set_rvalue_p ] + [ thread-run2 ./sync/futures/promise/set_value_const_pass.cpp : promise__set_value_const_p ] + [ thread-run2 ./sync/futures/promise/set_value_void_pass.cpp : promise__set_value_void_p ] [ thread-run2 ./sync/futures/promise/use_allocator_pass.cpp : promise__use_allocator_p ] + [ thread-run2 ./sync/futures/promise/set_exception_at_thread_exit_pass.cpp : promise__set_exception_at_thread_exit_p ] + [ thread-run2 ./sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp : promise__set_lvalue_at_thread_exit_p ] + [ thread-run2 ./sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp : promise__set_rvalue_at_thread_exit_p ] + [ thread-run2 ./sync/futures/promise/set_value_at_thread_exit_const_pass.cpp : promise__set_value_at_thread_exit_const_p ] + [ thread-run2 ./sync/futures/promise/set_value_at_thread_exit_void_pass.cpp : promise__set_value_at_thread_exit_void_p ] ; #explicit ts_future ; @@ -255,10 +294,23 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-compile-fail ./sync/futures/future/copy_ctor_fail.cpp : : future__copy_ctor_f ] [ thread-run2 ./sync/futures/future/default_pass.cpp : future__default_p ] [ thread-run2 ./sync/futures/future/dtor_pass.cpp : future__dtor_p ] - #[ thread-run2 ./sync/futures/future/get_pass.cpp : future__get_p ] + [ thread-run2 ./sync/futures/future/get_pass.cpp : future__get_p ] [ thread-run2 ./sync/futures/future/move_ctor_pass.cpp : future__move_ctor_p ] [ thread-run2 ./sync/futures/future/move_assign_pass.cpp : future__move_asign_p ] [ thread-run2 ./sync/futures/future/share_pass.cpp : future__share_p ] + [ thread-run2 ./sync/futures/future/then_pass.cpp : future__then_p ] + ; + + #explicit ts_shared_future ; + test-suite ts_shared_future + : + [ thread-run2 ./sync/futures/shared_future/copy_assign_pass.cpp : shared_future__copy_assign_p ] + [ thread-run2 ./sync/futures/shared_future/copy_ctor_pass.cpp : shared_future__copy_ctor_p ] + [ thread-run2 ./sync/futures/shared_future/default_pass.cpp : shared_future__default_p ] + [ thread-run2 ./sync/futures/shared_future/dtor_pass.cpp : shared_future__dtor_p ] + [ thread-run2 ./sync/futures/shared_future/get_pass.cpp : shared_future__get_p ] + [ thread-run2 ./sync/futures/shared_future/move_ctor_pass.cpp : shared_future__move_ctor_p ] + [ thread-run2 ./sync/futures/shared_future/move_assign_pass.cpp : shared_future__move_asign_p ] ; #explicit ts_packaged_task ; @@ -269,16 +321,17 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-compile-fail ./sync/futures/packaged_task/copy_ctor_fail.cpp : : packaged_task__copy_ctor_f ] [ thread-run2 ./sync/futures/packaged_task/default_ctor_pass.cpp : packaged_task__default_ctor_p ] [ thread-run2 ./sync/futures/packaged_task/func_ctor_pass.cpp : packaged_task__func_ctor_p ] - #[ thread-run2 ./sync/futures/packaged_task/dtor_pass.cpp : packaged_task__dtor_p ] + [ thread-run2 ./sync/futures/packaged_task/dtor_pass.cpp : packaged_task__dtor_p ] [ thread-run2 ./sync/futures/packaged_task/get_future_pass.cpp : packaged_task__get_future_p ] [ thread-run2 ./sync/futures/packaged_task/move_ctor_pass.cpp : packaged_task__move_ctor_p ] [ thread-run2 ./sync/futures/packaged_task/move_assign_pass.cpp : packaged_task__move_asign_p ] - #[ thread-run2 ./sync/futures/packaged_task/operator_pass.cpp : packaged_task__operator_p ] + [ thread-run2 ./sync/futures/packaged_task/operator_pass.cpp : packaged_task__operator_p ] [ thread-run2 ./sync/futures/packaged_task/reset_pass.cpp : packaged_task__reset_p ] [ thread-run2 ./sync/futures/packaged_task/use_allocator_pass.cpp : packaged_task__use_allocator_p ] [ thread-run2 ./sync/futures/packaged_task/types_pass.cpp : packaged_task__types_p ] [ thread-run2 ./sync/futures/packaged_task/member_swap_pass.cpp : packaged_task__member_swap_p ] [ thread-run2 ./sync/futures/packaged_task/non_member_swap_pass.cpp : packaged_task__non_member_swap_p ] + [ thread-run2 ./sync/futures/packaged_task/make_ready_at_thread_exit_pass.cpp : packaged_task__make_ready_at_thread_exit_p ] ; @@ -290,6 +343,8 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/mutual_exclusion/locks/lock_guard/adopt_lock_pass.cpp : lock_guard__cons__adopt_lock_p ] [ thread-run2 ./sync/mutual_exclusion/locks/lock_guard/default_pass.cpp : lock_guard__cons__default_p ] [ thread-run2 ./sync/mutual_exclusion/locks/lock_guard/types_pass.cpp : lock_guard__types_p ] + [ thread-run2 ./sync/mutual_exclusion/locks/lock_guard/make_lock_guard_pass.cpp : make_lock_guard_p ] + [ thread-run2 ./sync/mutual_exclusion/locks/lock_guard/make_lock_guard_adopt_lock_pass.cpp : make_lock_guard__adopt_lock_p ] ; #explicit ts_unique_lock ; @@ -320,9 +375,23 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/mod/release_pass.cpp : unique_lock__release_p ] [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/obs/mutex_pass.cpp : unique_lock__mutex_p ] [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/obs/op_bool_pass.cpp : unique_lock__op_bool_p ] - [ thread-compile-fail ./sync/mutual_exclusion/locks/unique_lock/obs/op_int_fail.cpp : : unique_lock__op_int_f ] + #[ thread-compile-fail ./sync/mutual_exclusion/locks/unique_lock/obs/op_int_fail.cpp : : unique_lock__op_int_f ] [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/obs/owns_lock_pass.cpp : unique_lock__owns_lock_p ] [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/types_pass.cpp : unique_lock__types_p ] + + + ; + + #explicit ts_make_unique_lock ; + test-suite ts_make_unique_lock + : + [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_mutex_pass.cpp : make_unique_lock__mutex_p ] + [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_adopt_lock_pass.cpp : make_unique_lock__adopt_lock_p ] + [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_defer_lock_pass.cpp : make_unique_lock__defer_lock_p ] + [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_try_to_lock_pass.cpp : make_unique_lock__try_to_lock_p ] + + [ thread-run2 ./sync/mutual_exclusion/locks/unique_lock/cons/make_unique_locks_mutex_pass.cpp : make_unique_locks__mutex_p ] + ; #explicit ts_shared_lock ; @@ -353,6 +422,10 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/mutual_exclusion/locks/shared_lock/obs/op_bool_pass.cpp : shared_lock__op_bool_p ] [ thread-run2 ./sync/mutual_exclusion/locks/shared_lock/obs/owns_lock_pass.cpp : shared_lock__owns_lock_p ] [ thread-run2 ./sync/mutual_exclusion/locks/shared_lock/types_pass.cpp : shared_lock__types_p ] + + [ thread-run2-h ./sync/mutual_exclusion/locks/shared_lock/cons/default_pass.cpp : shared_lock__cons__default_p ] + [ thread-run2-h ./sync/mutual_exclusion/locks/shared_lock/cons/defer_lock_pass.cpp : shared_lock__cons__defer_lock_p ] + ; #explicit ts_upgrade_lock ; @@ -443,6 +516,7 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/mutual_exclusion/shared_mutex/try_lock_pass.cpp : shared_mutex__try_lock_p ] [ thread-run2 ./sync/mutual_exclusion/shared_mutex/try_lock_until_pass.cpp : shared_mutex__try_lock_until_p ] + [ thread-run2-h ./sync/mutual_exclusion/shared_mutex/default_pass.cpp : shared_mutex__default_p ] ; #explicit ts_this_thread ; @@ -463,7 +537,7 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run-lib2 ./threads/thread/constr/F_pass.cpp : thread__constr__F_p ] [ thread-run-lib2 ./threads/thread/constr/FArgs_pass.cpp : thread__constr__FArgs_p ] [ thread-run2 ./threads/thread/constr/Frvalue_pass.cpp : thread__constr__Frvalue_p ] - #[ thread-run2 ./threads/thread/constr/FrvalueArgs_pass.cpp : thread__constr__FrvalueArgs_p ] + [ thread-run2 ./threads/thread/constr/FrvalueArgs_pass.cpp : thread__constr__FrvalueArgs_p ] [ thread-run2 ./threads/thread/constr/move_pass.cpp : thread__constr__move_p ] [ thread-run2 ./threads/thread/destr/dtor_pass.cpp : thread__destr__dtor_p ] [ thread-run2 ./threads/thread/id/hash_pass.cpp : thread__id__hash_p ] @@ -504,6 +578,15 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run ../example/shared_mutex.cpp ] #[ thread-run ../example/vhh_shared_monitor.cpp ] #[ thread-run ../example/vhh_shared_mutex.cpp ] + [ thread-run ../example/make_future.cpp ] + [ thread-run ../example/future_then.cpp ] + [ thread-run ../example/synchronized_value.cpp ] + [ thread-run ../example/synchronized_person.cpp ] + [ thread-run ../example/thread_guard.cpp ] + [ thread-run ../example/scoped_thread.cpp ] + [ thread-run ../example/strict_lock.cpp ] + [ thread-run ../example/ba_externallly_locked.cpp ] + ; #explicit ts_shared_upwards ; @@ -538,4 +621,12 @@ rule thread-compile-fail ( sources : reqs * : name ) [ thread-run2 ./sync/mutual_exclusion/locks/reverse_lock/types_pass.cpp : reverse_lock__types_p ] ; + explicit ts_ ; + test-suite ts_ + : + #[ thread-run test_7665.cpp ] + #[ thread-run test_7666.cpp ] + #[ thread-run ../example/unwrap.cpp ] + ; + } diff --git a/test/condition_test_common.hpp b/test/condition_test_common.hpp index 38f77909..4aa114e0 100644 --- a/test/condition_test_common.hpp +++ b/test/condition_test_common.hpp @@ -2,7 +2,7 @@ #define CONDITION_TEST_COMMON_HPP // Copyright (C) 2007 Anthony Williams // -// Distributed under the Boost Software License, Version 1.0. (See accompanying +// Distributed under the 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 @@ -10,14 +10,14 @@ #include unsigned const timeout_seconds=5; - + struct wait_for_flag { boost::mutex mutex; boost::condition_variable cond_var; bool flag; unsigned woken; - + wait_for_flag(): flag(false),woken(0) {} @@ -25,11 +25,11 @@ struct wait_for_flag struct check_flag { bool const& flag; - + check_flag(bool const& flag_): flag(flag_) {} - + bool operator()() const { return flag; @@ -38,10 +38,10 @@ struct wait_for_flag void operator=(check_flag&); }; - + void wait_without_predicate() { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); while(!flag) { cond_var.wait(lock); @@ -51,7 +51,7 @@ struct wait_for_flag void wait_with_predicate() { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); cond_var.wait(lock,check_flag(flag)); if(flag) { @@ -62,8 +62,8 @@ struct wait_for_flag void timed_wait_without_predicate() { boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds); - - boost::mutex::scoped_lock lock(mutex); + + boost::unique_lock lock(mutex); while(!flag) { if(!cond_var.timed_wait(lock,timeout)) @@ -77,7 +77,7 @@ struct wait_for_flag void timed_wait_with_predicate() { boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds); - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag) { ++woken; @@ -85,7 +85,7 @@ struct wait_for_flag } void relative_timed_wait_with_predicate() { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag) { ++woken; diff --git a/test/shared_mutex_locking_thread.hpp b/test/shared_mutex_locking_thread.hpp index 98a415b1..3b743235 100644 --- a/test/shared_mutex_locking_thread.hpp +++ b/test/shared_mutex_locking_thread.hpp @@ -37,15 +37,15 @@ public: unblocked_count_mutex(unblocked_count_mutex_), finish_mutex(finish_mutex_) {} - + void operator()() { // acquire lock lock_type lock(rw_mutex); - + // increment count to show we're unblocked { - boost::mutex::scoped_lock ublock(unblocked_count_mutex); + boost::unique_lock ublock(unblocked_count_mutex); ++unblocked_count; unblocked_condition.notify_one(); ++simultaneous_running_count; @@ -54,11 +54,11 @@ public: max_simultaneous_running=simultaneous_running_count; } } - + // wait to finish - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); { - boost::mutex::scoped_lock ublock(unblocked_count_mutex); + boost::unique_lock ublock(unblocked_count_mutex); --simultaneous_running_count; } } @@ -72,9 +72,9 @@ class simple_writing_thread boost::mutex& finish_mutex; boost::mutex& unblocked_mutex; unsigned& unblocked_count; - + void operator=(simple_writing_thread&); - + public: simple_writing_thread(boost::shared_mutex& rwm_, boost::mutex& finish_mutex_, @@ -83,17 +83,17 @@ public: rwm(rwm_),finish_mutex(finish_mutex_), unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) {} - + void operator()() { boost::unique_lock lk(rwm); - + { - boost::mutex::scoped_lock ulk(unblocked_mutex); + boost::unique_lock ulk(unblocked_mutex); ++unblocked_count; } - - boost::mutex::scoped_lock flk(finish_mutex); + + boost::unique_lock flk(finish_mutex); } }; @@ -103,9 +103,9 @@ class simple_reading_thread boost::mutex& finish_mutex; boost::mutex& unblocked_mutex; unsigned& unblocked_count; - + void operator=(simple_reading_thread&); - + public: simple_reading_thread(boost::shared_mutex& rwm_, boost::mutex& finish_mutex_, @@ -114,17 +114,17 @@ public: rwm(rwm_),finish_mutex(finish_mutex_), unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_) {} - + void operator()() { boost::shared_lock lk(rwm); - + { - boost::mutex::scoped_lock ulk(unblocked_mutex); + boost::unique_lock ulk(unblocked_mutex); ++unblocked_count; } - - boost::mutex::scoped_lock flk(finish_mutex); + + boost::unique_lock flk(finish_mutex); } }; diff --git a/test/sync/futures/async/async_pass.cpp b/test/sync/futures/async/async_pass.cpp index f38799b6..25c7a1ae 100644 --- a/test/sync/futures/async/async_pass.cpp +++ b/test/sync/futures/async/async_pass.cpp @@ -22,10 +22,12 @@ // future::type> // async(launch policy, F&& f, Args&&... args); -#define BOOST_THREAD_VERSION 3 +//#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 #include #include +#include #include #include #include @@ -38,7 +40,7 @@ class A long data_; public: - typedef int result_type; + typedef long result_type; explicit A(long i) : data_(i) {} @@ -93,149 +95,293 @@ boost::interprocess::unique_ptr > f3(int i) return boost::interprocess::unique_ptr >(new int(i)); } -typedef boost::interprocess::unique_ptr > XXT; boost::interprocess::unique_ptr > f4( - BOOST_THREAD_RV_REF(boost::interprocess::unique_ptr > ) p) + BOOST_THREAD_RV_REF_BEG boost::interprocess::unique_ptr > BOOST_THREAD_RV_REF_END p +) { boost::this_thread::sleep_for(ms(200)); return boost::move(p); } - int main() { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(f0); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(f.get() == 3); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::async, f0); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(f.get() == 3); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::async, A(3)); + try { + boost::future f = boost::async(boost::launch::async, A(3)); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(f.get() == 3); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::async, BOOST_THREAD_MAKE_RV_REF(MoveOnly())); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(f.get() == 3); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::any, f0); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(f.get() == 3); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::deferred, f0); -// boost::this_thread::sleep_for(ms(300)); -// Clock::time_point t0 = Clock::now(); -// BOOST_TEST(f.get() == 3); -// Clock::time_point t1 = Clock::now(); -// BOOST_TEST(t1 - t0 > ms(100)); -// } -// +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::deferred, f0); + boost::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + BOOST_TEST(f.get() == 3); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 > ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(f1); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(&f.get() == &i); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::async, f1); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(&f.get() == &i); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::any, f1); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); BOOST_TEST(&f.get() == &i); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::deferred, f1); -// boost::this_thread::sleep_for(ms(300)); -// Clock::time_point t0 = Clock::now(); -// BOOST_TEST(&f.get() == &i); -// Clock::time_point t1 = Clock::now(); -// BOOST_TEST(t1 - t0 > ms(100)); -// } -// +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(f2); + try { + boost::future f = boost::async(boost::launch::deferred, f1); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); - f.get(); + BOOST_TEST(&f.get() == &i); Clock::time_point t1 = Clock::now(); - BOOST_TEST(t1 - t0 < ms(100)); + BOOST_TEST(t1 - t0 > ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(f2); + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::async, f2); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); f.get(); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::any, f2); boost::this_thread::sleep_for(ms(300)); Clock::time_point t0 = Clock::now(); f.get(); Clock::time_point t1 = Clock::now(); BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::deferred, f2); -// boost::this_thread::sleep_for(ms(300)); -// Clock::time_point t0 = Clock::now(); -// f.get(); -// Clock::time_point t1 = Clock::now(); -// BOOST_TEST(t1 - t0 > ms(100)); -// } +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + std::cout << __FILE__ <<"["<<__LINE__<<"]"< f = boost::async(boost::launch::deferred, f2); + boost::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + f.get(); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 > ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< > > f = boost::async(f3, 3); -// boost::this_thread::sleep_for(ms(300)); -// Clock::time_point t0 = Clock::now(); -// BOOST_TEST(*f.get() == 3); -// Clock::time_point t1 = Clock::now(); -// BOOST_TEST(t1 - t0 < ms(100)); -// } + // todo fixme +#if 0 && defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + std::cout << __FILE__ <<"["<<__LINE__<<"]"< > > f = boost::async(boost::launch::async, &f3, 3); + boost::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + BOOST_TEST(*f.get() == 3); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< > > f = boost::async(f4, boost::interprocess::unique_ptr >(new int(3))); -// boost::this_thread::sleep_for(ms(300)); -// Clock::time_point t0 = Clock::now(); -// BOOST_TEST(*f.get() == 3); -// Clock::time_point t1 = Clock::now(); -// BOOST_TEST(t1 - t0 < ms(100)); -// } + // todo fixme +#if 0 && defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + { + try { + boost::future > > f = boost::async(&f4, boost::interprocess::unique_ptr >(new int(3))); + boost::this_thread::sleep_for(ms(300)); + Clock::time_point t0 = Clock::now(); + BOOST_TEST(*f.get() == 3); + Clock::time_point t1 = Clock::now(); + BOOST_TEST(t1 - t0 < ms(100)); + } catch (std::exception& ex) { + std::cout << __FILE__ <<"["<<__LINE__<<"]"< -// class promise +// class future -// ~promise(); +// ~future(); #define BOOST_THREAD_VERSION 3 #include diff --git a/test/sync/futures/future/get_pass.cpp b/test/sync/futures/future/get_pass.cpp index 85b29003..5d6859d1 100755 --- a/test/sync/futures/future/get_pass.cpp +++ b/test/sync/futures/future/get_pass.cpp @@ -14,16 +14,21 @@ // -// class promise +// class future -// future get_future(); +// const R& future::get(); +// R& future::get(); +// void future::get(); -#define BOOST_THREAD_VERSION 3 +//#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 #include #include #include +#if defined BOOST_THREAD_USES_CHRONO + namespace boost { template @@ -76,7 +81,7 @@ void func5(boost::promise p) void func6(boost::promise p) { boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); - p.set_exception(boost::make_exception_ptr('c')); + p.set_exception(boost::make_exception_ptr(4)); } @@ -87,85 +92,130 @@ int main() { boost::promise p; boost::future f = p.get_future(); - boost::thread(func1, boost::move(p)).detach(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func1, boost::move(p)).detach(); +#else + p.set_value(3); +#endif BOOST_TEST(f.valid()); BOOST_TEST(f.get() == 3); +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET BOOST_TEST(!f.valid()); +#endif } { boost::promise p; boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread(func2, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(3)); +#endif try { BOOST_TEST(f.valid()); BOOST_TEST(f.get() == 3); BOOST_TEST(false); } - catch (int i) + catch (boost::wrap const& i) { - BOOST_TEST(i == 3); + BOOST_TEST(i.value == 3); } + catch (...) + { + BOOST_TEST(false); + } +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET BOOST_TEST(!f.valid()); +#endif + } + } + { + typedef int& T; + { + boost::promise p; + boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func3, boost::move(p)).detach(); +#else + int j=5; + p.set_value(j); +#endif + BOOST_TEST(f.valid()); + BOOST_TEST(f.get() == 5); +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + BOOST_TEST(!f.valid()); +#endif + } + { + boost::promise p; + boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func4, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(3.5)); +#endif + try + { + BOOST_TEST(f.valid()); + BOOST_TEST(f.get() == 3); + BOOST_TEST(false); + } + catch (boost::wrap const& i) + { + BOOST_TEST(i.value == 3.5); + } +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + BOOST_TEST(!f.valid()); +#endif } } -// { -// typedef int& T; -// { -// boost::promise p; -// boost::future f = p.get_future(); -// boost::thread(func3, boost::move(p)).detach(); -// BOOST_TEST(f.valid()); -// BOOST_TEST(f.get() == 5); -// BOOST_TEST(!f.valid()); -// } -// { -// boost::promise p; -// boost::future f = p.get_future(); -// boost::thread(func4, boost::move(p)).detach(); -// try -// { -// BOOST_TEST(f.valid()); -// BOOST_TEST(f.get() == 3); -// BOOST_TEST(false); -// } -// catch (double i) -// { -// BOOST_TEST(i == 3.5); -// } -// BOOST_TEST(!f.valid()); -// } -// } -// { -// typedef void T; -// { -// boost::promise p; -// boost::future f = p.get_future(); -// boost::thread(func5, boost::move(p)).detach(); -// BOOST_TEST(f.valid()); -// f.get(); -// BOOST_TEST(!f.valid()); -// } -// { -// boost::promise p; -// boost::future f = p.get_future(); -// boost::thread(func6, boost::move(p)).detach(); -// try -// { -// BOOST_TEST(f.valid()); -// f.get(); -// BOOST_TEST(false); -// } -// catch (char i) -// { -// BOOST_TEST(i == 'c'); -// } -// BOOST_TEST(!f.valid()); -// } -// } - + typedef void T; + { + boost::promise p; + boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func5, boost::move(p)).detach(); +#else + p.set_value(); +#endif + BOOST_TEST(f.valid()); + f.get(); +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + BOOST_TEST(!f.valid()); +#endif + } + { + boost::promise p; + boost::future f = p.get_future(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func6, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(4)); +#endif + try + { + BOOST_TEST(f.valid()); + f.get(); + BOOST_TEST(false); + } + catch (boost::wrap const& i) + { + BOOST_TEST(i.value == 4); + } + catch (...) + { + BOOST_TEST(false); + } +#ifdef BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET + BOOST_TEST(!f.valid()); +#endif + } return boost::report_errors(); } +#else +#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif diff --git a/test/sync/futures/future/move_assign_pass.cpp b/test/sync/futures/future/move_assign_pass.cpp index 67117efa..ebb13e5e 100755 --- a/test/sync/futures/future/move_assign_pass.cpp +++ b/test/sync/futures/future/move_assign_pass.cpp @@ -14,9 +14,9 @@ // -// class promise +// class future -// promise& operator=(promise&& rhs); +// future& operator=(future&& rhs); #define BOOST_THREAD_VERSION 3 diff --git a/test/sync/futures/future/move_ctor_pass.cpp b/test/sync/futures/future/move_ctor_pass.cpp index c1689118..8da893a3 100755 --- a/test/sync/futures/future/move_ctor_pass.cpp +++ b/test/sync/futures/future/move_ctor_pass.cpp @@ -14,9 +14,9 @@ // -// class promise +// class future -// promise(promise&& rhs); +// future(future&& rhs); #define BOOST_THREAD_VERSION 3 diff --git a/test/sync/futures/future/then_pass.cpp b/test/sync/futures/future/then_pass.cpp new file mode 100644 index 00000000..cb76573d --- /dev/null +++ b/test/sync/futures/future/then_pass.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2011 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// class future + +// template +// auto then(F&& func) -> BOOST_THREAD_FUTURE; + +#define BOOST_THREAD_VERSION 4 +#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET + +#include +#include + +#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION + +int p1() +{ + return 1; +} + +int p2(boost::future& f) +{ + return 2 * f.get(); +} + +int main() +{ + { + boost::future f1 = boost::async(p1); + boost::future f2 = f1.then(p2); + BOOST_TEST(f2.get()==2); + } + { + boost::future f2 = boost::async(p1).then(p2); + BOOST_TEST(f2.get()==2); + } + { + boost::future f1 = boost::async(p1); + boost::future f2 = f1.then(p2).then(p2); + BOOST_TEST(f2.get()==4); + } + { + boost::future f2 = boost::async(p1).then(p2).then(p2); + BOOST_TEST(f2.get()==4); + } + + return boost::report_errors(); +} + +#else + +int main() +{ + return 0; +} +#endif diff --git a/test/sync/futures/packaged_task/alloc_ctor_pass.cpp b/test/sync/futures/packaged_task/alloc_ctor_pass.cpp index 993c159c..9860a798 100644 --- a/test/sync/futures/packaged_task/alloc_ctor_pass.cpp +++ b/test/sync/futures/packaged_task/alloc_ctor_pass.cpp @@ -20,10 +20,18 @@ // explicit packaged_task(allocator_arg_t, const Allocator& a, F&& f); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif +#include #include #include + + #if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS #include "../test_allocator.hpp" @@ -81,7 +89,7 @@ int A::n_destroy = 0; int main() { { - boost::packaged_task p(boost::allocator_arg, + boost::packaged_task p(boost::allocator_arg, test_allocator(), BOOST_THREAD_MAKE_RV_REF(A(5))); BOOST_TEST(test_alloc_base::count > 0); BOOST_TEST(p.valid()); @@ -96,10 +104,10 @@ int main() BOOST_TEST(A::n_destroy > 0); BOOST_TEST(test_alloc_base::count == 0); A::n_copies = 0; - A::n_copies = 0; + A::n_moves = 0; { A a(5); - boost::packaged_task p(boost::allocator_arg, + boost::packaged_task p(boost::allocator_arg, test_allocator(), a); BOOST_TEST(test_alloc_base::count > 0); BOOST_TEST(p.valid()); @@ -108,14 +116,14 @@ int main() p(); BOOST_TEST(f.get() == 5.0); } - BOOST_TEST(A::n_copies > 0); - BOOST_TEST(A::n_moves > 0); + //BOOST_TEST(A::n_copies > 0); + //BOOST_TEST(A::n_moves > 0); BOOST_TEST(test_alloc_base::count == 0); A::n_copies = 0; - A::n_copies = 0; + A::n_moves = 0; { const A a(5); - boost::packaged_task p(boost::allocator_arg, + boost::packaged_task p(boost::allocator_arg, test_allocator(), a); BOOST_TEST(test_alloc_base::count > 0); BOOST_TEST(p.valid()); @@ -124,11 +132,11 @@ int main() p(); BOOST_TEST(f.get() == 5.0); } - BOOST_TEST(A::n_copies > 0); - BOOST_TEST(A::n_moves > 0); + //BOOST_TEST(A::n_copies > 0); + //BOOST_TEST(A::n_moves > 0); BOOST_TEST(test_alloc_base::count == 0); { - boost::packaged_task p(boost::allocator_arg, + boost::packaged_task p(boost::allocator_arg, test_allocator(), fct); BOOST_TEST(test_alloc_base::count > 0); BOOST_TEST(p.valid()); @@ -138,7 +146,7 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p(boost::allocator_arg, + boost::packaged_task p(boost::allocator_arg, test_allocator(), &lfct); BOOST_TEST(test_alloc_base::count > 0); BOOST_TEST(p.valid()); diff --git a/test/sync/futures/packaged_task/copy_assign_fail.cpp b/test/sync/futures/packaged_task/copy_assign_fail.cpp index 6b1f861c..7f068ece 100755 --- a/test/sync/futures/packaged_task/copy_assign_fail.cpp +++ b/test/sync/futures/packaged_task/copy_assign_fail.cpp @@ -18,7 +18,13 @@ // packaged_task& operator=(packaged_task&) = delete; -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif + #include #include @@ -37,8 +43,8 @@ public: int main() { { - boost::packaged_task p0(A(5)); - boost::packaged_task p; + boost::packaged_task p0(A(5)); + boost::packaged_task p; p = p0; } diff --git a/test/sync/futures/packaged_task/copy_ctor_fail.cpp b/test/sync/futures/packaged_task/copy_ctor_fail.cpp index 30bad1e2..22a17496 100644 --- a/test/sync/futures/packaged_task/copy_ctor_fail.cpp +++ b/test/sync/futures/packaged_task/copy_ctor_fail.cpp @@ -18,7 +18,13 @@ // packaged_task(packaged_task&) = delete; -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif + #include #include @@ -37,8 +43,8 @@ public: int main() { { - boost::packaged_task p0(A(5)); - boost::packaged_task p(p0); + boost::packaged_task p0(A(5)); + boost::packaged_task p(p0); } diff --git a/test/sync/futures/packaged_task/default_ctor_pass.cpp b/test/sync/futures/packaged_task/default_ctor_pass.cpp index b2a371f2..85f16143 100644 --- a/test/sync/futures/packaged_task/default_ctor_pass.cpp +++ b/test/sync/futures/packaged_task/default_ctor_pass.cpp @@ -18,7 +18,13 @@ // packaged_task(); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE int() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE int +#endif + #include #include @@ -26,7 +32,7 @@ int main() { { - boost::packaged_task p; + boost::packaged_task p; BOOST_TEST(!p.valid()); } diff --git a/test/sync/futures/packaged_task/dtor_pass.cpp b/test/sync/futures/packaged_task/dtor_pass.cpp index 15048a91..89620ad0 100755 --- a/test/sync/futures/packaged_task/dtor_pass.cpp +++ b/test/sync/futures/packaged_task/dtor_pass.cpp @@ -17,14 +17,34 @@ // class packaged_task // ~packaged_task(); -; -#define BOOST_THREAD_VERSION 3 +//#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 + #include #include #include +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double(int, char) +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 + 3 +'a' +#else +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double() +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 +#endif +#else +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 +#endif + class A { long data_; @@ -36,25 +56,33 @@ public: long operator()(long i, long j) const {return data_ + i + j;} }; -void func(boost::packaged_task p) +void func(boost::packaged_task ) { } -void func2(boost::packaged_task p) +void func2(boost::packaged_task p) { - //p(3, 'a'); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'a'); +#else p(); +#endif } int main() { { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread(func, boost::move(p)).detach(); +#else + boost::packaged_task* p2=new boost::packaged_task(boost::move(p)); + delete p2; +#endif try { - double i = f.get(); + f.get(); BOOST_TEST(false); } catch (const boost::future_error& e) @@ -63,13 +91,18 @@ int main() } } { - boost::packaged_task p(A(5)); + std::cout << __LINE__ << std::endl; + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread(func2, boost::move(p)).detach(); - BOOST_TEST(f.get() == 5.0); +#else + p(); +#endif + std::cout << __LINE__ << std::endl; + BOOST_TEST(f.get() == BOOST_THREAD_DETAIL_SIGNATURE_2_RES); + std::cout << __LINE__ << std::endl; } - - return boost::report_errors(); } diff --git a/test/sync/futures/packaged_task/func_ctor_pass.cpp b/test/sync/futures/packaged_task/func_ctor_pass.cpp index 9010a811..decf3aff 100644 --- a/test/sync/futures/packaged_task/func_ctor_pass.cpp +++ b/test/sync/futures/packaged_task/func_ctor_pass.cpp @@ -19,10 +19,30 @@ // explicit packaged_task(F&& f); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 + #include #include +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double(int, char) +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 + 3 +'a' +#else +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double() +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 +#endif +#else +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 +#endif + double fct() { return 5.0; @@ -69,44 +89,47 @@ int A::n_copies = 0; int main() { { - boost::packaged_task p(BOOST_THREAD_MAKE_RV_REF(A(5))); + boost::packaged_task p(BOOST_THREAD_MAKE_RV_REF(A(5))); BOOST_TEST(p.valid()); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); - //p(3, 'a'); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'a'); +#else p(); - BOOST_TEST(f.get() == 5.0); +#endif + BOOST_TEST(f.get() == BOOST_THREAD_DETAIL_SIGNATURE_2_RES); BOOST_TEST(A::n_copies == 0); BOOST_TEST(A::n_moves > 0); } A::n_copies = 0; - A::n_copies = 0; + A::n_moves = 0; { A a(5); - boost::packaged_task p(a); + boost::packaged_task p(a); BOOST_TEST(p.valid()); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); //p(3, 'a'); p(); BOOST_TEST(f.get() == 5.0); - BOOST_TEST(A::n_copies > 0); - BOOST_TEST(A::n_moves > 0); + //BOOST_TEST(A::n_copies > 0); + //BOOST_TEST(A::n_moves > 0); } A::n_copies = 0; - A::n_copies = 0; + A::n_moves = 0; { const A a(5); - boost::packaged_task p(a); + boost::packaged_task p(a); BOOST_TEST(p.valid()); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); //p(3, 'a'); p(); BOOST_TEST(f.get() == 5.0); - BOOST_TEST(A::n_copies > 0); - BOOST_TEST(A::n_moves > 0); + //BOOST_TEST(A::n_copies > 0); + //BOOST_TEST(A::n_moves > 0); } { - boost::packaged_task p(fct); + boost::packaged_task p(fct); BOOST_TEST(p.valid()); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); //p(3, 'a'); @@ -114,7 +137,7 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p(&lfct); + boost::packaged_task p(&lfct); BOOST_TEST(p.valid()); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); //p(3, 'a'); diff --git a/test/sync/futures/packaged_task/get_future_pass.cpp b/test/sync/futures/packaged_task/get_future_pass.cpp index 05c68634..7b298579 100755 --- a/test/sync/futures/packaged_task/get_future_pass.cpp +++ b/test/sync/futures/packaged_task/get_future_pass.cpp @@ -19,7 +19,12 @@ // future get_future(); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif #include #include @@ -38,14 +43,14 @@ public: int main() { { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); //p(3, 'a'); p(); BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); try { @@ -58,7 +63,7 @@ int main() } } { - boost::packaged_task p; + boost::packaged_task p; try { boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); diff --git a/test/sync/futures/packaged_task/make_ready_at_thread_exit_pass.cpp b/test/sync/futures/packaged_task/make_ready_at_thread_exit_pass.cpp new file mode 100644 index 00000000..134103d8 --- /dev/null +++ b/test/sync/futures/packaged_task/make_ready_at_thread_exit_pass.cpp @@ -0,0 +1,146 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class packaged_task + +// packaged_task(packaged_task&& other); + +#define BOOST_THREAD_VERSION 4 + +#include +#include + +#if defined BOOST_THREAD_USES_CHRONO && \ + defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && \ + defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + +class E : public std::exception +{ +public: + long data; + explicit E(long i) : + data(i) + { + } + + const char* what() const throw() { return ""; } + + ~E() throw() {} +}; +class A +{ + long data_; + +public: + explicit A(long i) : + data_(i) + { + } + + long operator()(long i, long j) const + { + if (j == 'z') BOOST_THROW_EXCEPTION( E(6) ); + return data_ + i + j; + } +}; + +void func0(boost::packaged_task *p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p->make_ready_at_thread_exit(3, 'a'); +} + +void func1(boost::packaged_task *p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p->make_ready_at_thread_exit(3, 'z'); +} + +void func2(boost::packaged_task *p) +{ + p->make_ready_at_thread_exit(3, 'a'); + try + { + p->make_ready_at_thread_exit(3, 'c'); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); + } +} + +void func3(boost::packaged_task *p) +{ + try + { + p->make_ready_at_thread_exit(3, 'a'); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::no_state)); + } +} + +int main() +{ + { + boost::packaged_task p(A(5)); + boost::future f = p.get_future(); + // BUG boost::thread(func0, boost::move(p)).detach(); + boost::thread(func0, &p).detach(); + BOOST_TEST(f.get() == 105.0); + } + { + boost::packaged_task p(A(5)); + boost::future f = p.get_future(); + //boost::thread(func1, boost::move(p)).detach(); + boost::thread(func1, &p).detach(); + try + { + f.get(); + BOOST_TEST(false); + } + catch (const E& e) + { + BOOST_TEST(e.data == 6); + } + } + { + boost::packaged_task p(A(5)); + boost::future f = p.get_future(); + //boost::thread(func2, boost::move(p)).detach(); + boost::thread(func2, &p).detach(); + BOOST_TEST(f.get() == 105.0); + } + { + boost::packaged_task p; + //boost::thread t(func3, boost::move(p)); + boost::thread t(func3, &p); + t.join(); + } + + return boost::report_errors(); +} + +#else +int main() +{ + return boost::report_errors(); +} +//#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif + + diff --git a/test/sync/futures/packaged_task/member_swap_pass.cpp b/test/sync/futures/packaged_task/member_swap_pass.cpp index 4cd7a139..fe3c062f 100755 --- a/test/sync/futures/packaged_task/member_swap_pass.cpp +++ b/test/sync/futures/packaged_task/member_swap_pass.cpp @@ -18,7 +18,12 @@ // void swap(packaged_task& other); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif #include #include @@ -46,8 +51,8 @@ public: int main() { { - boost::packaged_task p0(A(5)); - boost::packaged_task p; + boost::packaged_task p0(A(5)); + boost::packaged_task p; p.swap(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(p.valid()); @@ -57,8 +62,8 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p0; - boost::packaged_task p; + boost::packaged_task p0; + boost::packaged_task p; p.swap(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(!p.valid()); diff --git a/test/sync/futures/packaged_task/move_assign_pass.cpp b/test/sync/futures/packaged_task/move_assign_pass.cpp index 60c34ca3..fe696c8f 100755 --- a/test/sync/futures/packaged_task/move_assign_pass.cpp +++ b/test/sync/futures/packaged_task/move_assign_pass.cpp @@ -18,7 +18,12 @@ // promise& operator=(promise&& rhs); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif #include #include @@ -39,8 +44,8 @@ int main() { { - boost::packaged_task p0(A(5)); - boost::packaged_task p; + boost::packaged_task p0(A(5)); + boost::packaged_task p; p = boost::move(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(p.valid()); @@ -50,8 +55,8 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p0; - boost::packaged_task p; + boost::packaged_task p0; + boost::packaged_task p; p = boost::move(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(!p.valid()); diff --git a/test/sync/futures/packaged_task/move_ctor_pass.cpp b/test/sync/futures/packaged_task/move_ctor_pass.cpp index 4c383cf7..a5085b31 100755 --- a/test/sync/futures/packaged_task/move_ctor_pass.cpp +++ b/test/sync/futures/packaged_task/move_ctor_pass.cpp @@ -18,7 +18,12 @@ // packaged_task(packaged_task&& other); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif #include #include @@ -38,8 +43,8 @@ public: int main() { { - boost::packaged_task p0(A(5)); - boost::packaged_task p = boost::move(p0); + boost::packaged_task p0(A(5)); + boost::packaged_task p = boost::move(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(p.valid()); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); @@ -48,8 +53,8 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p0; - boost::packaged_task p = boost::move(p0); + boost::packaged_task p0; + boost::packaged_task p = boost::move(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(!p.valid()); } diff --git a/test/sync/futures/packaged_task/non_member_swap_pass.cpp b/test/sync/futures/packaged_task/non_member_swap_pass.cpp index 6f91d3c9..26d68367 100755 --- a/test/sync/futures/packaged_task/non_member_swap_pass.cpp +++ b/test/sync/futures/packaged_task/non_member_swap_pass.cpp @@ -18,7 +18,12 @@ // void // swap(packaged_task& x, packaged_task& y); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif #include #include @@ -37,8 +42,8 @@ public: int main() { { - boost::packaged_task p0(A(5)); - boost::packaged_task p; + boost::packaged_task p0(A(5)); + boost::packaged_task p; p.swap(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(p.valid()); @@ -48,8 +53,8 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p0; - boost::packaged_task p; + boost::packaged_task p0; + boost::packaged_task p; p.swap(p0); BOOST_TEST(!p0.valid()); BOOST_TEST(!p.valid()); diff --git a/test/sync/futures/packaged_task/operator_pass.cpp b/test/sync/futures/packaged_task/operator_pass.cpp index 3d7fd9d0..db932f72 100644 --- a/test/sync/futures/packaged_task/operator_pass.cpp +++ b/test/sync/futures/packaged_task/operator_pass.cpp @@ -18,10 +18,46 @@ // void operator()(); -#define BOOST_THREAD_VERSION 3 +//#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 + #include #include +#if defined BOOST_THREAD_USES_CHRONO + +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif + +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double(int, char) +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 + 3 +'a' +#else +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double() +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 +#endif +#else +#define BOOST_THREAD_DETAIL_SIGNATURE_2 double +#define BOOST_THREAD_DETAIL_SIGNATURE_2_RES 5 +#endif +class E : public std::exception +{ +public: + long data; + explicit E(long i) : + data(i) + { + } + + const char* what() const throw() { return ""; } + + ~E() throw() {} +}; + class A { long data_; @@ -34,93 +70,149 @@ public: long operator()() const { + if (data_ == 0) BOOST_THROW_EXCEPTION(E(6)); return data_; } long operator()(long i, long j) const { - if (j == 'z') throw A(6); + if (j == 'z') BOOST_THROW_EXCEPTION(E(6)); return data_ + i + j; } + ~A() {} }; -void func0(boost::packaged_task p) +void func0(boost::packaged_task p) { boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); - //p(3, 'a'); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'a'); +#else p(); +#endif } -void func1(boost::packaged_task p) +void func1(boost::packaged_task p) { boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); - //p(3, 'z'); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'z'); +#else p(); +#endif } -void func2(boost::packaged_task p) +void func2(boost::packaged_task p) { - //p(3, 'a'); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'a'); +#else p(); +#endif try { - //p(3, 'c'); - p(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'c'); +#else + p(); +#endif } catch (const boost::future_error& e) { - BOOST_TEST(e.code() == make_error_code(boost::future_errc::promise_already_satisfied)); + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); } } -void func3(boost::packaged_task p) +void func3(boost::packaged_task p) { try { - //p(3, 'a'); - p(); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'a'); +#else + p(); +#endif } catch (const boost::future_error& e) { - BOOST_TEST(e.code() == make_error_code(boost::future_errc::no_state)); + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::no_state)); } } int main() { { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread(func0, boost::move(p)).detach(); - BOOST_TEST(f.get() == 5.0); +#else + //p(); +#endif + //BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(0)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread(func1, boost::move(p)).detach(); +#endif try { +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) +#else + p(); +#endif f.get(); BOOST_TEST(false); } - catch (const A& e) + catch (const E& e) { - //BOOST_TEST(e(3, 'a') == 106); - BOOST_TEST(e() == 5); + BOOST_TEST(e.data == 6); + } + catch (...) + { + BOOST_TEST(false); } } { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread t(func2, boost::move(p)); - BOOST_TEST(f.get() == 5.0); +#else + p(); +#endif +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + BOOST_TEST(f.get() == 105); t.join(); +#else + BOOST_TEST(f.get() == 5.0); +#endif } { - boost::packaged_task p; + boost::packaged_task p; +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) boost::thread t(func3, boost::move(p)); t.join(); +#else + try + { + #if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + p(3, 'a'); + #else + p(); + #endif + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::no_state)); + } +#endif } return boost::report_errors(); } +#else +#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif diff --git a/test/sync/futures/packaged_task/reset_pass.cpp b/test/sync/futures/packaged_task/reset_pass.cpp index 558c118d..711e7a57 100644 --- a/test/sync/futures/packaged_task/reset_pass.cpp +++ b/test/sync/futures/packaged_task/reset_pass.cpp @@ -18,7 +18,13 @@ // void operator()(); -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif + #include #include @@ -46,7 +52,7 @@ public: int main() { { - boost::packaged_task p(A(5)); + boost::packaged_task p(A(5)); boost::future f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); //p(3, 'a'); p(); @@ -58,7 +64,7 @@ int main() BOOST_TEST(f.get() == 5.0); } { - boost::packaged_task p; + boost::packaged_task p; try { p.reset(); diff --git a/test/sync/futures/packaged_task/types_pass.cpp b/test/sync/futures/packaged_task/types_pass.cpp index d574c76d..a52fb043 100755 --- a/test/sync/futures/packaged_task/types_pass.cpp +++ b/test/sync/futures/packaged_task/types_pass.cpp @@ -29,7 +29,7 @@ struct A {}; int main() { - BOOST_STATIC_ASSERT_MSG((boost::is_same::result_type, A>::value), ""); + //BOOST_STATIC_ASSERT_MSG((boost::is_same::result_type, A>::value), ""); return boost::report_errors(); } diff --git a/test/sync/futures/packaged_task/use_allocator_pass.cpp b/test/sync/futures/packaged_task/use_allocator_pass.cpp index 9d582814..3c604dd9 100644 --- a/test/sync/futures/packaged_task/use_allocator_pass.cpp +++ b/test/sync/futures/packaged_task/use_allocator_pass.cpp @@ -21,7 +21,12 @@ // : true_type { }; -#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 +#if BOOST_THREAD_VERSION == 4 +#define BOOST_THREAD_DETAIL_SIGNATURE double() +#else +#define BOOST_THREAD_DETAIL_SIGNATURE double +#endif #include #include @@ -33,7 +38,7 @@ int main() { - BOOST_STATIC_ASSERT_MSG((boost::uses_allocator, test_allocator >::value), ""); + BOOST_STATIC_ASSERT_MSG((boost::uses_allocator, test_allocator >::value), ""); return boost::report_errors(); } diff --git a/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp b/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp new file mode 100644 index 00000000..7fd7a4f5 --- /dev/null +++ b/test/sync/futures/promise/set_exception_at_thread_exit_pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_exception_at_thread_exit(exception_ptr p); + +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include + +namespace boost +{ + template + struct wrap + { + wrap(T const& v) : + value(v) + { + } + T value; + + }; + + template + exception_ptr make_exception_ptr(T v) + { + return copy_exception(wrap (v)); + } +} + +//void func(boost::promise p) +boost::promise p; +void func() +{ + p.set_exception_at_thread_exit(boost::make_exception_ptr(3)); +} + +int main() +{ + { + typedef int T; + //boost::promise p; + boost::future f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + try + { + f.get(); + BOOST_TEST(false); + } + catch (boost::wrap i) + { + BOOST_TEST(i.value == 3); + } + catch (...) + { + BOOST_TEST(false); + } + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_exception_pass.cpp b/test/sync/futures/promise/set_exception_pass.cpp new file mode 100644 index 00000000..30b5a5a9 --- /dev/null +++ b/test/sync/futures/promise/set_exception_pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void set_exception(exception_ptr p); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include + +namespace boost +{ + template + struct wrap + { + wrap(T const& v) : + value(v) + { + } + T value; + + }; + + template + exception_ptr make_exception_ptr(T v) + { + return copy_exception(wrap (v)); + } +} + +int main() +{ + + { + typedef int T; + boost::promise p; + boost::future f = p.get_future(); + p.set_exception(boost::make_exception_ptr(3)); + try + { + f.get(); + BOOST_TEST(false); + } + catch (boost::wrap i) + { + BOOST_TEST(i.value == 3); + } + try + { + p.set_exception(boost::make_exception_ptr(3)); + BOOST_TEST(false); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); + } + catch (...) + { + BOOST_TEST(false); + } + } + + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp b/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp new file mode 100644 index 00000000..a143dc63 --- /dev/null +++ b/test/sync/futures/promise/set_lvalue_at_thread_exit_pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_value_at_thread_exit(R& r); + +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include + +int i = 0; + +//void func(boost::promise p) +boost::promise p; +void func() +{ + p.set_value_at_thread_exit(i); + i = 4; +} + +int main() +{ + { + //boost::promise p; + boost::future f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + int r = f.get(); + BOOST_TEST(r == 4); + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_lvalue_pass.cpp b/test/sync/futures/promise/set_lvalue_pass.cpp new file mode 100644 index 00000000..a95a3ea5 --- /dev/null +++ b/test/sync/futures/promise/set_lvalue_pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_value(R& r); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include + +int main() +{ + + { + typedef int& T; + int i = 3; + boost::promise p; + boost::future f = p.get_future(); + p.set_value(i); + int& j = f.get(); + BOOST_TEST(j == 3); + ++i; + BOOST_TEST(j == 4); + try + { + p.set_value(i); + BOOST_TEST(false); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); + } + catch (...) + { + BOOST_TEST(false); + } + } + + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp b/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp new file mode 100644 index 00000000..c7822983 --- /dev/null +++ b/test/sync/futures/promise/set_rvalue_at_thread_exit_pass.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_exception_at_thread_exit(exception_ptr p); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include +#include + +//void func(boost::promise > > p) +boost::promise > > p; +void func() +{ + boost::interprocess::unique_ptr > uptr(new int(5)); + p.set_value_at_thread_exit(boost::move(uptr)); +} + +int main() +{ + { + //boost::promise> > p; + boost::future > > f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + BOOST_TEST(*f.get() == 5); + } + + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_rvalue_pass.cpp b/test/sync/futures/promise/set_rvalue_pass.cpp new file mode 100644 index 00000000..1416db98 --- /dev/null +++ b/test/sync/futures/promise/set_rvalue_pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_value(R&& r); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + +struct A +{ + A() : + value(0) + { + } + A(int i) : + value(i) + { + } + BOOST_THREAD_DELETE_COPY_CTOR(A) + A(A&& rhs) + { + if(rhs.value==0) + throw 9; + else + { + value=rhs.value; + rhs.value=0; + } + } + int value; +}; + +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES +int main() +{ + +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES + + { + typedef A T; + T i; + boost::promise p; + boost::future f = p.get_future(); + try + { + p.set_value(boost::move(i)); + BOOST_TEST(false); + } + catch (int j) + { + BOOST_TEST(j == 9); + } + catch (...) + { + BOOST_TEST(false); + } + } + { + typedef A T; + T i(3); + boost::promise p; + boost::future f = p.get_future(); + p.set_value(boost::move(i)); + BOOST_TEST(f.get().value == 3); + try + { + T j(3); + p.set_value(boost::move(j)); + BOOST_TEST(false); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); + } + catch (...) + { + BOOST_TEST(false); + } + + } + { + typedef A T; + T i(3); + boost::promise p; + boost::future f = p.get_future(); + p.set_value(boost::move(i)); + BOOST_TEST(i.value == 0); + boost::promise p2(boost::move(p)); + BOOST_TEST(f.get().value == 3); + + } + { + typedef A T; + T i(3); + boost::promise p; + boost::future f = p.get_future(); + p.set_value(boost::move(i)); + BOOST_TEST(i.value == 0); + boost::promise p2(boost::move(p)); + boost::future f2(boost::move(f)); + BOOST_TEST(f2.get().value == 3); + + } + { + typedef A T; + T i(3); + boost::promise p; + p.set_value(boost::move(i)); + BOOST_TEST(i.value == 0); + boost::promise p2(boost::move(p)); + boost::future f = p2.get_future(); + BOOST_TEST(f.get().value == 3); + + } + + { + typedef boost::future T; + boost::promise pi; + T fi=pi.get_future(); + pi.set_value(3); + + boost::promise p; + boost::future f = p.get_future(); + p.set_value(boost::move(fi)); + boost::future f2(boost::move(f)); + BOOST_TEST(f2.get().get() == 3); + } + +#endif // BOOST_NO_CXX11_RVALUE_REFERENCES + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp b/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp new file mode 100644 index 00000000..a4abb431 --- /dev/null +++ b/test/sync/futures/promise/set_value_at_thread_exit_const_pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_value_at_thread_exit(const R& r); + +#define BOOST_THREAD_VERSION 4 + +#include +#include + +boost::promise p; +//void func(boost::promise p) +void func() +{ + const int i = 5; + p.set_value_at_thread_exit(i); +} + +int main() +{ + { + //boost::promise p; + boost::future f = p.get_future(); + //boost::thread(func, boost::move(p)).detach(); + boost::thread(func).detach(); + BOOST_TEST(f.get() == 5); + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp b/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp new file mode 100644 index 00000000..b434652a --- /dev/null +++ b/test/sync/futures/promise/set_value_at_thread_exit_void_pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_value_at_thread_exit(); + +#define BOOST_THREAD_VERSION 4 + +#include +#include + +int i = 0; + +boost::promise p; +void func() +{ + p.set_value_at_thread_exit(); + i = 1; +} + +void func2(boost::promise p2) +{ + p2.set_value_at_thread_exit(); + i = 1; +} + +int main() +{ + try + { + boost::future f = p.get_future(); + boost::thread(func).detach(); + f.get(); + BOOST_TEST(i == 1); + + } + catch(std::exception ex) + { + BOOST_TEST(false); + } + catch(...) + { + BOOST_TEST(false); + } + + // BUG when moving promise. fixme +// try +// { +// std::cout << __FILE__ << ":" << __LINE__ < p2; // BUG +// std::cout << __FILE__ << ":" << __LINE__ < f = p2.get_future(); +// std::cout << __FILE__ << ":" << __LINE__ < + +// class promise + +// void promise::set_value(const R& r); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include + +struct A +{ + A() + { + } + A(const A&) + { + throw 10; + } +}; + +int main() +{ + + { + typedef int T; + T i = 3; + boost::promise p; + boost::future f = p.get_future(); + p.set_value(i); + ++i; + BOOST_TEST(f.get() == 3); + --i; + try + { + p.set_value(i); + BOOST_TEST(false); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); + } + catch (...) + { + BOOST_TEST(false); + } + } + { + typedef A T; + T i; + boost::promise p; + boost::future f = p.get_future(); + try + { + p.set_value(i); + BOOST_TEST(false); + } + catch (int j) + { + BOOST_TEST(j == 10); + } + catch (...) + { + BOOST_TEST(false); + } + } + + return boost::report_errors(); +} + diff --git a/test/sync/futures/promise/set_value_void_pass.cpp b/test/sync/futures/promise/set_value_void_pass.cpp new file mode 100644 index 00000000..d1f6357a --- /dev/null +++ b/test/sync/futures/promise/set_value_void_pass.cpp @@ -0,0 +1,64 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class promise + +// void promise::set_value(); + +#define BOOST_THREAD_VERSION 3 + +#include +#include +#include + +struct A +{ + A() + { + } + A(const A&) + { + throw 10; + } +}; + +int main() +{ + + { + typedef void T; + boost::promise p; + boost::future f = p.get_future(); + p.set_value(); + f.get(); + try + { + p.set_value(); + BOOST_TEST(false); + } + catch (const boost::future_error& e) + { + BOOST_TEST(e.code() == boost::system::make_error_code(boost::future_errc::promise_already_satisfied)); + } + catch (...) + { + BOOST_TEST(false); + } + } + + return boost::report_errors(); +} + diff --git a/test/sync/futures/shared_future/copy_assign_pass.cpp b/test/sync/futures/shared_future/copy_assign_pass.cpp new file mode 100755 index 00000000..1b23b2d1 --- /dev/null +++ b/test/sync/futures/shared_future/copy_assign_pass.cpp @@ -0,0 +1,85 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class shared_future + +// shared_future& operator=(const shared_future&); + + +#define BOOST_THREAD_VERSION 3 +#include +#include + +int main() +{ + { + typedef int T; + boost::promise p; + boost::shared_future f0((p.get_future())); + boost::shared_future f; + f = f0; + BOOST_TEST(f0.valid()); + BOOST_TEST(f.valid()); + + } + { + typedef int T; + boost::shared_future f0; + boost::shared_future f; + f = f0; + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef int& T; + boost::promise p; + boost::shared_future f0((p.get_future())); + boost::shared_future f; + f = f0; + BOOST_TEST(f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int& T; + boost::shared_future f0; + boost::shared_future f; + f = f0; + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef void T; + boost::promise p; + boost::shared_future f0((p.get_future())); + boost::shared_future f; + f = f0; + BOOST_TEST(f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef void T; + boost::shared_future f0; + boost::shared_future f; + f = f0; + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + + return boost::report_errors(); +} + +//#include "../../../remove_error_code_unused_warning.hpp" + diff --git a/test/sync/futures/shared_future/copy_ctor_pass.cpp b/test/sync/futures/shared_future/copy_ctor_pass.cpp new file mode 100644 index 00000000..fd29c0fe --- /dev/null +++ b/test/sync/futures/shared_future/copy_ctor_pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// +// class shared_future + +// shared_future(const future&); + + +#define BOOST_THREAD_VERSION 3 +#include +#include + +int main() +{ + { + typedef int T; + boost::promise p; + boost::shared_future f0((p.get_future())); + boost::shared_future f = f0; + BOOST_TEST(f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int T; + boost::shared_future < T > f0; + boost::shared_future f = f0; + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef int& T; + boost::promise p; + boost::shared_future f0((p.get_future())); + boost::shared_future f = f0; + BOOST_TEST(f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int& T; + boost::shared_future < T > f0; + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef void T; + boost::promise p; + boost::shared_future f0((p.get_future())); + boost::shared_future f = f0; + BOOST_TEST(f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef void T; + boost::shared_future < T > f0; + boost::shared_future f = f0; + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + + return boost::report_errors(); +} + +//#include "../../../remove_error_code_unused_warning.hpp" + diff --git a/test/sync/futures/shared_future/default_pass.cpp b/test/sync/futures/shared_future/default_pass.cpp new file mode 100755 index 00000000..59ecea3a --- /dev/null +++ b/test/sync/futures/shared_future/default_pass.cpp @@ -0,0 +1,45 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class shared_future + +// shared_future(); + +#define BOOST_THREAD_VERSION 3 + +#include +#include + +int main() +{ + + { + boost::shared_future f; + BOOST_TEST(!f.valid()); + } + { + boost::shared_future f; + BOOST_TEST(!f.valid()); + } + { + boost::shared_future f; + BOOST_TEST(!f.valid()); + } + + + return boost::report_errors(); +} + diff --git a/test/sync/futures/shared_future/dtor_pass.cpp b/test/sync/futures/shared_future/dtor_pass.cpp new file mode 100755 index 00000000..01fb591c --- /dev/null +++ b/test/sync/futures/shared_future/dtor_pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class shared_future + +// ~shared_future(); + +#define BOOST_THREAD_VERSION 3 +#include + +#include +#include +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS +#include "../test_allocator.hpp" +#endif + +int main() +{ +#if defined BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS + BOOST_TEST(test_alloc_base::count == 0); + { + typedef int T; + boost::shared_future f; + { + boost::promise p(boost::allocator_arg, test_allocator()); + BOOST_TEST(test_alloc_base::count == 1); + f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + BOOST_TEST(test_alloc_base::count == 1); + BOOST_TEST(f.valid()); + } + BOOST_TEST(test_alloc_base::count == 1); + BOOST_TEST(f.valid()); + } + BOOST_TEST(test_alloc_base::count == 0); + { + typedef int& T; + boost::shared_future f; + { + boost::promise p(boost::allocator_arg, test_allocator()); + BOOST_TEST(test_alloc_base::count == 1); + f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + BOOST_TEST(test_alloc_base::count == 1); + BOOST_TEST(f.valid()); + } + BOOST_TEST(test_alloc_base::count == 1); + BOOST_TEST(f.valid()); + } + BOOST_TEST(test_alloc_base::count == 0); + { + typedef void T; + boost::shared_future f; + { + boost::promise p(boost::allocator_arg, test_allocator()); + BOOST_TEST(test_alloc_base::count == 1); + f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + BOOST_TEST(test_alloc_base::count == 1); + BOOST_TEST(f.valid()); + } + BOOST_TEST(test_alloc_base::count == 1); + BOOST_TEST(f.valid()); + } + BOOST_TEST(test_alloc_base::count == 0); +#endif + { + typedef int T; + boost::shared_future f; + { + boost::promise p; + f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + BOOST_TEST(f.valid()); + } + BOOST_TEST(f.valid()); + } + { + typedef int& T; + boost::shared_future f; + { + boost::promise p; + f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + BOOST_TEST(f.valid()); + } + BOOST_TEST(f.valid()); + } + { + typedef void T; + boost::shared_future f; + { + boost::promise p; + f = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + BOOST_TEST(f.valid()); + } + BOOST_TEST(f.valid()); + } + return boost::report_errors(); +} + diff --git a/test/sync/futures/shared_future/get_pass.cpp b/test/sync/futures/shared_future/get_pass.cpp new file mode 100755 index 00000000..558fb024 --- /dev/null +++ b/test/sync/futures/shared_future/get_pass.cpp @@ -0,0 +1,208 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class shared_future + +// const R& shared_future::get(); +// R& shared_future::get(); +// void shared_future::get(); +//#define BOOST_THREAD_VERSION 3 +#define BOOST_THREAD_VERSION 4 + +#include +#include +#include + +#if defined BOOST_THREAD_USES_CHRONO + +namespace boost +{ +template +struct wrap +{ + wrap(T const& v) : value(v){} + T value; + +}; + +template +exception_ptr make_exception_ptr(T v) { + return copy_exception(wrap(v)); +} +} + +void func1(boost::promise p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p.set_value(3); +} + +void func2(boost::promise p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p.set_exception(boost::make_exception_ptr(3)); +} + +int j = 0; + +void func3(boost::promise p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + j = 5; + p.set_value(j); +} + +void func4(boost::promise p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p.set_exception(boost::make_exception_ptr(3.5)); +} + +void func5(boost::promise p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p.set_value(); +} + +void func6(boost::promise p) +{ + boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + p.set_exception(boost::make_exception_ptr(4)); +} + + +int main() +{ + { + typedef int T; + { + boost::promise p; + boost::shared_future f((p.get_future())); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func1, boost::move(p)).detach(); +#else + p.set_value(3); +#endif + BOOST_TEST(f.valid()); + BOOST_TEST(f.get() == 3); + BOOST_TEST(f.valid()); + } + { + boost::promise p; + boost::shared_future f((p.get_future())); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func2, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(3)); +#endif + try + { + BOOST_TEST(f.valid()); + BOOST_TEST(f.get() == 3); + BOOST_TEST(false); + } + catch (boost::wrap const& i) + { + BOOST_TEST(i.value == 3); + } + catch (...) + { + BOOST_TEST(false); + } + BOOST_TEST(f.valid()); + } + } + { + typedef int& T; + { + boost::promise p; + boost::shared_future f((p.get_future())); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func3, boost::move(p)).detach(); +#else + int j=5; + p.set_value(j); +#endif + BOOST_TEST(f.valid()); + BOOST_TEST(f.get() == 5); + BOOST_TEST(f.valid()); + } + { + boost::promise p; + boost::shared_future f((p.get_future())); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func4, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(3.5)); +#endif + try + { + BOOST_TEST(f.valid()); + BOOST_TEST(f.get() == 3); + BOOST_TEST(false); + } + catch (boost::wrap const& i) + { + BOOST_TEST(i.value == 3.5); + } + BOOST_TEST(f.valid()); + } + } + + typedef void T; + { + boost::promise p; + boost::shared_future f((p.get_future())); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func5, boost::move(p)).detach(); +#else + p.set_value(); +#endif + BOOST_TEST(f.valid()); + f.get(); + BOOST_TEST(f.valid()); + } + { + boost::promise p; + boost::shared_future f((p.get_future())); +#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) + boost::thread(func6, boost::move(p)).detach(); +#else + p.set_exception(boost::make_exception_ptr(4)); +#endif + try + { + BOOST_TEST(f.valid()); + f.get(); + BOOST_TEST(false); + } + catch (boost::wrap const& i) + { + BOOST_TEST(i.value == 4); + } + catch (...) + { + BOOST_TEST(false); + } + BOOST_TEST(f.valid()); + } + + return boost::report_errors(); +} + +#else +#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif diff --git a/test/sync/futures/shared_future/move_assign_pass.cpp b/test/sync/futures/shared_future/move_assign_pass.cpp new file mode 100755 index 00000000..40ff4992 --- /dev/null +++ b/test/sync/futures/shared_future/move_assign_pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class shared_future + +// shared_future& shared_future=(shared_future&& rhs); + +#define BOOST_THREAD_VERSION 3 + +#include +#include + +boost::mutex m0; +boost::mutex m1; + +int main() +{ + { + typedef int T; + boost::promise p; + boost::shared_future f0 = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + boost::shared_future f; + f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int T; + boost::shared_future f0; + boost::shared_future f; + f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef int& T; + boost::promise p; + boost::shared_future f0 = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + boost::shared_future f; + f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int& T; + boost::shared_future f0; + boost::shared_future f; + f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef void T; + boost::promise p; + boost::shared_future f0 = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + boost::shared_future f; + f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef void T; + boost::shared_future f0; + boost::shared_future f; + f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + + + return boost::report_errors(); + +} + diff --git a/test/sync/futures/shared_future/move_ctor_pass.cpp b/test/sync/futures/shared_future/move_ctor_pass.cpp new file mode 100755 index 00000000..533f5ec9 --- /dev/null +++ b/test/sync/futures/shared_future/move_ctor_pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// class shared_future + +// shared_future(shared_future&& rhs); + +#define BOOST_THREAD_VERSION 3 + +#include +#include + +boost::mutex m; + +int main() +{ + { + typedef int T; + boost::promise p; + boost::shared_future f0 = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int T; + boost::shared_future f0; + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef int& T; + boost::promise p; + boost::shared_future f0 = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef int& T; + boost::shared_future f0; + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + { + typedef void T; + boost::promise p; + boost::shared_future f0 = BOOST_THREAD_MAKE_RV_REF(p.get_future()); + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(f.valid()); + } + { + typedef void T; + boost::shared_future f0; + boost::shared_future f = boost::move(f0); + BOOST_TEST(!f0.valid()); + BOOST_TEST(!f.valid()); + } + + return boost::report_errors(); +} + diff --git a/test/sync/mutual_exclusion/locks/lock_guard/adopt_lock_pass.cpp b/test/sync/mutual_exclusion/locks/lock_guard/adopt_lock_pass.cpp index 1f6fde98..a11cf569 100755 --- a/test/sync/mutual_exclusion/locks/lock_guard/adopt_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/lock_guard/adopt_lock_pass.cpp @@ -18,7 +18,7 @@ // lock_guard(mutex_type& m, adopt_lock_t); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/lock_guard/copy_assign_fail.cpp b/test/sync/mutual_exclusion/locks/lock_guard/copy_assign_fail.cpp index 528ed978..a3957c75 100755 --- a/test/sync/mutual_exclusion/locks/lock_guard/copy_assign_fail.cpp +++ b/test/sync/mutual_exclusion/locks/lock_guard/copy_assign_fail.cpp @@ -18,7 +18,7 @@ // lock_guard& operator=(lock_guard const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/lock_guard/copy_ctor_fail.cpp b/test/sync/mutual_exclusion/locks/lock_guard/copy_ctor_fail.cpp index 135a162a..5c1b3a1c 100755 --- a/test/sync/mutual_exclusion/locks/lock_guard/copy_ctor_fail.cpp +++ b/test/sync/mutual_exclusion/locks/lock_guard/copy_ctor_fail.cpp @@ -19,7 +19,7 @@ // lock_guard(lock_guard const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/lock_guard/default_pass.cpp b/test/sync/mutual_exclusion/locks/lock_guard/default_pass.cpp index f5784964..68cb88e0 100755 --- a/test/sync/mutual_exclusion/locks/lock_guard/default_pass.cpp +++ b/test/sync/mutual_exclusion/locks/lock_guard/default_pass.cpp @@ -16,9 +16,9 @@ // template class lock_guard; -// lock_guard(lock_guard const&) = delete; +// lock_guard(Mutex &); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_adopt_lock_pass.cpp b/test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_adopt_lock_pass.cpp new file mode 100644 index 00000000..443ac3fa --- /dev/null +++ b/test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_adopt_lock_pass.cpp @@ -0,0 +1,77 @@ +//===----------------------------------------------------------------------===// +// +// 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) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// template +// lock_guard make_lock_guard(Lockable &, adopt_lock_t); + +#include +#include +#include +#include + + +#ifdef BOOST_THREAD_USES_CHRONO +typedef boost::chrono::high_resolution_clock Clock; +typedef Clock::time_point time_point; +typedef Clock::duration duration; +typedef boost::chrono::milliseconds ms; +typedef boost::chrono::nanoseconds ns; +#endif +boost::mutex m; + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +void f() +{ +#ifdef BOOST_THREAD_USES_CHRONO + time_point t0 = Clock::now(); + time_point t1; + { + m.lock(); + auto&& lg = boost::make_lock_guard(m, boost::adopt_lock); (void)lg; + + t1 = Clock::now(); + } + ns d = t1 - t0 - ms(250); + BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +#else + //time_point t0 = Clock::now(); + //time_point t1; + { + m.lock(); + auto&& lg = boost::make_lock_guard(m, boost::adopt_lock); (void)lg; + //t1 = Clock::now(); + } + //ns d = t1 - t0 - ms(250); + //BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +#endif +} +#endif + +int main() +{ +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + m.lock(); + boost::thread t(f); +#ifdef BOOST_THREAD_USES_CHRONO + boost::this_thread::sleep_for(ms(250)); +#endif + m.unlock(); + t.join(); +#endif + return boost::report_errors(); +} + diff --git a/test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_pass.cpp b/test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_pass.cpp new file mode 100644 index 00000000..6a804c26 --- /dev/null +++ b/test/sync/mutual_exclusion/locks/lock_guard/make_lock_guard_pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 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) + +// + +// template +// lock_guard make_lock_guard(Lockable &); + +#define BOOST_THREAD_VERSION 4 +#define BOOST_THREAD_USES_LOG +#define BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS + +#include +#include +#include +#include + +#include + +#ifdef BOOST_THREAD_USES_CHRONO +typedef boost::chrono::high_resolution_clock Clock; +typedef Clock::time_point time_point; +typedef Clock::duration duration; +typedef boost::chrono::milliseconds ms; +typedef boost::chrono::nanoseconds ns; +#endif + +boost::mutex m; + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +void f() +{ + time_point t0 = Clock::now(); + time_point t1; + { + const auto&& lg = boost::make_lock_guard(m); (void)lg; + t1 = Clock::now(); + BOOST_THREAD_TRACE; + } + BOOST_THREAD_TRACE; + ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +} +#endif + +int main() +{ + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + { + m.lock(); + boost::thread t(f); + #ifdef BOOST_THREAD_USES_CHRONO + boost::this_thread::sleep_for(ms(250)); + #endif + m.unlock(); + t.join(); + } +#endif + return boost::report_errors(); +} diff --git a/test/sync/mutual_exclusion/locks/lock_guard/types_pass.cpp b/test/sync/mutual_exclusion/locks/lock_guard/types_pass.cpp index 161d69d5..7c2d3937 100755 --- a/test/sync/mutual_exclusion/locks/lock_guard/types_pass.cpp +++ b/test/sync/mutual_exclusion/locks/lock_guard/types_pass.cpp @@ -25,8 +25,10 @@ // }; +#include #include #include +#include #include int main() diff --git a/test/sync/mutual_exclusion/locks/reverse_lock/copy_assign_fail.cpp b/test/sync/mutual_exclusion/locks/reverse_lock/copy_assign_fail.cpp index 0a15a149..408e0f26 100755 --- a/test/sync/mutual_exclusion/locks/reverse_lock/copy_assign_fail.cpp +++ b/test/sync/mutual_exclusion/locks/reverse_lock/copy_assign_fail.cpp @@ -9,10 +9,10 @@ // reverse_lock& operator=(reverse_lock const&) = delete; -#include +#include #include #include -#include +#include int main() diff --git a/test/sync/mutual_exclusion/locks/reverse_lock/copy_ctor_fail.cpp b/test/sync/mutual_exclusion/locks/reverse_lock/copy_ctor_fail.cpp index bdc51007..c936c11b 100755 --- a/test/sync/mutual_exclusion/locks/reverse_lock/copy_ctor_fail.cpp +++ b/test/sync/mutual_exclusion/locks/reverse_lock/copy_ctor_fail.cpp @@ -10,10 +10,10 @@ // reverse_lock(reverse_lock const&) = delete; -#include +#include #include #include -#include +#include boost::mutex m0; boost::mutex m1; diff --git a/test/sync/mutual_exclusion/locks/reverse_lock/types_pass.cpp b/test/sync/mutual_exclusion/locks/reverse_lock/types_pass.cpp index 30dafa1f..13a17fd3 100755 --- a/test/sync/mutual_exclusion/locks/reverse_lock/types_pass.cpp +++ b/test/sync/mutual_exclusion/locks/reverse_lock/types_pass.cpp @@ -18,9 +18,10 @@ #include #include -#include +#include #include #include +#include #include int main() diff --git a/test/sync/mutual_exclusion/locks/reverse_lock/unique_lock_ctor_pass.cpp b/test/sync/mutual_exclusion/locks/reverse_lock/unique_lock_ctor_pass.cpp index 99b4f00c..57a1f1e0 100755 --- a/test/sync/mutual_exclusion/locks/reverse_lock/unique_lock_ctor_pass.cpp +++ b/test/sync/mutual_exclusion/locks/reverse_lock/unique_lock_ctor_pass.cpp @@ -10,7 +10,7 @@ // unlock_guard(unlock_guard const&) = delete; #include -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/adopt_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/adopt_lock_pass.cpp index 732ad632..8787126b 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/adopt_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/adopt_lock_pass.cpp @@ -19,7 +19,7 @@ // shared_lock(mutex_type& m, adopt_lock_t); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_assign_fail.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_assign_fail.cpp index 015e2af5..2bc99f34 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_assign_fail.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_assign_fail.cpp @@ -18,7 +18,7 @@ // shared_lock& operator=(shared_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_ctor_fail.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_ctor_fail.cpp index b24b4442..43fddebe 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_ctor_fail.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/copy_ctor_fail.cpp @@ -19,7 +19,7 @@ // shared_lock(shared_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/default_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/default_pass.cpp index e7b81277..9ccae93b 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/default_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/default_pass.cpp @@ -18,7 +18,7 @@ // shared_lock(shared_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/defer_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/defer_lock_pass.cpp index caeec9c2..84388aca 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/defer_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/defer_lock_pass.cpp @@ -18,7 +18,7 @@ // shared_lock(mutex_type& m, adopt_lock_t); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/duration_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/duration_pass.cpp index d08304f7..ef985822 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/duration_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/duration_pass.cpp @@ -19,7 +19,7 @@ // template // shared_lock(mutex_type& m, const chrono::duration& rel_time); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_assign_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_assign_pass.cpp index b3348f70..ef54e229 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_assign_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_assign_pass.cpp @@ -19,7 +19,7 @@ // shared_lock(shared_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_pass.cpp index 173f6b5c..307c7614 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_pass.cpp @@ -19,7 +19,7 @@ // shared_lock& operator=(shared_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp index 90325ed6..38f6e7d7 100644 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_unique_lock_pass.cpp @@ -19,7 +19,7 @@ // shared_lock& operator=(shared_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp index b98183e2..36ecb6a5 100644 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/move_ctor_upgrade_lock_pass.cpp @@ -19,7 +19,7 @@ // shared_lock& operator=(shared_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/mutex_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/mutex_pass.cpp index 0a0d191a..aaa987d3 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/mutex_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/mutex_pass.cpp @@ -19,7 +19,7 @@ // explicit shared_lock(Mutex& m); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/time_point_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/time_point_pass.cpp index 9308b855..5c27d2e3 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/time_point_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/time_point_pass.cpp @@ -19,7 +19,7 @@ // template // shared_lock(mutex_type& m, const chrono::time_point& abs_time); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/cons/try_to_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/cons/try_to_lock_pass.cpp index 9f4251e9..e37eadf2 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/cons/try_to_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/cons/try_to_lock_pass.cpp @@ -19,7 +19,7 @@ // shared_lock(mutex_type& m, try_to_lock_t); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/locking/lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/locking/lock_pass.cpp index 3ef6f7c2..8dfa8914 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/locking/lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/locking/lock_pass.cpp @@ -18,7 +18,7 @@ // void lock(); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_for_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_for_pass.cpp index 027cf64d..07d32df3 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_for_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_for_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_pass.cpp index 5ba50cc3..6a199723 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_until_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_until_pass.cpp index 77dd7dc8..cdfd0e16 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_until_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/locking/try_lock_until_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_until(const chrono::time_point& abs_time); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/locking/unlock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/locking/unlock_pass.cpp index 1eaba78c..e8ed7c74 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/locking/unlock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/locking/unlock_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/mod/member_swap_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/mod/member_swap_pass.cpp index 949166f5..11f366bd 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/mod/member_swap_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/mod/member_swap_pass.cpp @@ -18,7 +18,7 @@ // void swap(shared_lock& u); -#include +#include #include struct shared_mutex diff --git a/test/sync/mutual_exclusion/locks/shared_lock/mod/non_member_swap_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/mod/non_member_swap_pass.cpp index 766d63ec..c0ccb8b9 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/mod/non_member_swap_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/mod/non_member_swap_pass.cpp @@ -17,7 +17,7 @@ // template // void swap(shared_lock& x, shared_lock& y); -#include +#include #include struct shared_mutex diff --git a/test/sync/mutual_exclusion/locks/shared_lock/mod/release_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/mod/release_pass.cpp index 5a88c1f2..c39ca50a 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/mod/release_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/mod/release_pass.cpp @@ -18,7 +18,7 @@ // void Mutex* release(); -#include +#include #include struct shared_mutex diff --git a/test/sync/mutual_exclusion/locks/shared_lock/obs/mutex_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/obs/mutex_pass.cpp index 49c051be..2012186a 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/obs/mutex_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/obs/mutex_pass.cpp @@ -18,7 +18,7 @@ // Mutex *mutex() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/obs/op_bool_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/obs/op_bool_pass.cpp index 71712fee..407bfcc6 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/obs/op_bool_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/obs/op_bool_pass.cpp @@ -18,7 +18,7 @@ // explicit operator bool() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/obs/owns_lock_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/obs/owns_lock_pass.cpp index 900300b6..dce14d3e 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/obs/owns_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/obs/owns_lock_pass.cpp @@ -18,7 +18,7 @@ // bool owns_lock() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock/types_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock/types_pass.cpp index f919586d..2f83ef98 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock/types_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock/types_pass.cpp @@ -25,7 +25,7 @@ // }; -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/shared_lock_guard/types_pass.cpp b/test/sync/mutual_exclusion/locks/shared_lock_guard/types_pass.cpp index 2fe4c9a4..57a2116d 100755 --- a/test/sync/mutual_exclusion/locks/shared_lock_guard/types_pass.cpp +++ b/test/sync/mutual_exclusion/locks/shared_lock_guard/types_pass.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include int main() diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/adopt_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/adopt_lock_pass.cpp index 1d40d903..42d33378 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/adopt_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/adopt_lock_pass.cpp @@ -18,7 +18,7 @@ // unique_lock(mutex_type& m, adopt_lock_t); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_assign_fail.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_assign_fail.cpp index 43b26e2a..d69a1eec 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_assign_fail.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_assign_fail.cpp @@ -18,7 +18,7 @@ // unique_lock& operator=(unique_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_ctor_fail.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_ctor_fail.cpp index 8fb0aaab..08fc3c34 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_ctor_fail.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/copy_ctor_fail.cpp @@ -19,7 +19,7 @@ // unique_lock(unique_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/default_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/default_pass.cpp index 409d30e8..7989b817 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/default_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/default_pass.cpp @@ -18,7 +18,7 @@ // unique_lock(unique_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/defer_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/defer_lock_pass.cpp index 9aae0544..fc7e5f78 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/defer_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/defer_lock_pass.cpp @@ -18,7 +18,7 @@ // unique_lock(mutex_type& m, adopt_lock_t); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/duration_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/duration_pass.cpp index 679b19f4..10a6de84 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/duration_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/duration_pass.cpp @@ -21,7 +21,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_adopt_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_adopt_lock_pass.cpp new file mode 100644 index 00000000..1450e096 --- /dev/null +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_adopt_lock_pass.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// template class unique_lock; +// unique_lock make_unique_lock(Mutex&, adopt_lock_t); + +#include +#include +#include + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +int main() +{ + boost::mutex m; + m.lock(); + auto lk = boost::make_unique_lock(m, boost::adopt_lock); + BOOST_TEST(lk.mutex() == &m); + BOOST_TEST(lk.owns_lock() == true); + + return boost::report_errors(); +} + +#else +int main() +{ + return boost::report_errors(); +} +#endif + diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_defer_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_defer_lock_pass.cpp new file mode 100644 index 00000000..42dc94f9 --- /dev/null +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_defer_lock_pass.cpp @@ -0,0 +1,35 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// template class unique_lock; +// unique_lock make_unique_lock(Mutex&, defer_lock_t); + +// unique_lock(mutex_type& m, adopt_lock_t); + +#include +#include +#include + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST +int main() +{ + boost::mutex m; + m.lock(); + auto lk = boost::make_unique_lock(m, boost::defer_lock); + BOOST_TEST(lk.mutex() == &m); + BOOST_TEST(lk.owns_lock() == false); + + return boost::report_errors(); +} + +#else +int main() +{ + return boost::report_errors(); +} +#endif + diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_mutex_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_mutex_pass.cpp new file mode 100644 index 00000000..55ef855a --- /dev/null +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_mutex_pass.cpp @@ -0,0 +1,74 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// template +// unique_lock make_unique_lock(Mutex&); + +#include +#include +#include +#include + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +boost::mutex m; + +#if defined BOOST_THREAD_USES_CHRONO + +typedef boost::chrono::system_clock Clock; +typedef Clock::time_point time_point; +typedef Clock::duration duration; +typedef boost::chrono::milliseconds ms; +typedef boost::chrono::nanoseconds ns; +#else +#endif + +void f() +{ +#if defined BOOST_THREAD_USES_CHRONO + time_point t0 = Clock::now(); + time_point t1; + { + auto&& _ = boost::make_unique_lock(m); (void)_; + t1 = Clock::now(); + } + ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +#else + //time_point t0 = Clock::now(); + //time_point t1; + { + auto _ = boost::make_unique_lock(m); (void)_; + //t1 = Clock::now(); + } + //ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + //BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +#endif +} + +int main() +{ + m.lock(); + boost::thread t(f); +#if defined BOOST_THREAD_USES_CHRONO + boost::this_thread::sleep_for(ms(250)); +#else +#endif + m.unlock(); + t.join(); + + return boost::report_errors(); +} +#else +int main() +{ + return boost::report_errors(); +} +#endif + diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_try_to_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_try_to_lock_pass.cpp new file mode 100644 index 00000000..b5d7a1ab --- /dev/null +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_lock_try_to_lock_pass.cpp @@ -0,0 +1,101 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// template class unique_lock; +// unique_lock make_unique_lock(Mutex&, try_to_lock_t); + +#include +#include +#include +#include + +#if ! defined(BOOST_NO_CXX11_AUTO) && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +boost::mutex m; + +#if defined BOOST_THREAD_USES_CHRONO +typedef boost::chrono::system_clock Clock; +typedef Clock::time_point time_point; +typedef Clock::duration duration; +typedef boost::chrono::milliseconds ms; +typedef boost::chrono::nanoseconds ns; +#else +#endif + +void f() +{ +#if defined BOOST_THREAD_USES_CHRONO + time_point t0 = Clock::now(); + { + auto lk = boost::make_unique_lock(m, boost::try_to_lock); + BOOST_TEST(lk.owns_lock() == false); + } + { + auto lk = boost::make_unique_lock(m, boost::try_to_lock); + BOOST_TEST(lk.owns_lock() == false); + } + { + auto lk = boost::make_unique_lock(m, boost::try_to_lock); + BOOST_TEST(lk.owns_lock() == false); + } + while (true) + { + auto lk = boost::make_unique_lock(m, boost::try_to_lock); + if (lk.owns_lock()) break; + } + time_point t1 = Clock::now(); + //m.unlock(); + ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_TEST(d < ns(50000000)+ms(1000)); // within 50ms +#else +// time_point t0 = Clock::now(); +// { +// boost::unique_lock lk(m, boost::try_to_lock); +// BOOST_TEST(lk.owns_lock() == false); +// } +// { +// boost::unique_lock lk(m, boost::try_to_lock); +// BOOST_TEST(lk.owns_lock() == false); +// } +// { +// boost::unique_lock lk(m, boost::try_to_lock); +// BOOST_TEST(lk.owns_lock() == false); +// } + while (true) + { + auto lk = boost::make_unique_lock(m, boost::try_to_lock); + if (lk.owns_lock()) break; + } + //time_point t1 = Clock::now(); + //ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + //BOOST_TEST(d < ns(50000000)+ms(1000)); // within 50ms +#endif +} + +int main() +{ + m.lock(); + boost::thread t(f); +#if defined BOOST_THREAD_USES_CHRONO + boost::this_thread::sleep_for(ms(250)); +#else +#endif + m.unlock(); + t.join(); + + return boost::report_errors(); +} + +#else +int main() +{ + return boost::report_errors(); +} +#endif + diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_locks_mutex_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_locks_mutex_pass.cpp new file mode 100644 index 00000000..d1944f5f --- /dev/null +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/make_unique_locks_mutex_pass.cpp @@ -0,0 +1,81 @@ +// Copyright (C) 2012 Vicente J. Botet Escriba +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// + +// template +// unique_lock make_unique_lock(Mutex&); + +#include +#include +#include +#include + +#if ! defined(BOOST_NO_CXX11_AUTO) && defined BOOST_NO_CXX11_HDR_TUPLE && ! defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST + +boost::mutex m1; +boost::mutex m2; +boost::mutex m3; + + +#if defined BOOST_THREAD_USES_CHRONO + +typedef boost::chrono::system_clock Clock; +typedef Clock::time_point time_point; +typedef Clock::duration duration; +typedef boost::chrono::milliseconds ms; +typedef boost::chrono::nanoseconds ns; +#else +#endif + +void f() +{ +#if defined BOOST_THREAD_USES_CHRONO + time_point t0 = Clock::now(); + time_point t1; + { + auto&& _ = boost::make_unique_locks(m1,m2,m3); + t1 = Clock::now(); + } + ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +#else + //time_point t0 = Clock::now(); + //time_point t1; + { + auto&& _ = boost::make_unique_locks(m1,m2,m3); + //t1 = Clock::now(); + } + //ns d = t1 - t0 - ms(250); + // This test is spurious as it depends on the time the thread system switches the threads + //BOOST_TEST(d < ns(2500000)+ms(1000)); // within 2.5ms +#endif +} + +int main() +{ + m1.lock(); + m2.lock(); + m3.lock(); + boost::thread t(f); +#if defined BOOST_THREAD_USES_CHRONO + boost::this_thread::sleep_for(ms(250)); +#else +#endif + m1.unlock(); + m2.unlock(); + m3.unlock(); + t.join(); + + return boost::report_errors(); +} +#else +int main() +{ + return boost::report_errors(); +} +#endif + diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_assign_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_assign_pass.cpp index 09e5d98f..7c84d152 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_assign_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_assign_pass.cpp @@ -19,7 +19,7 @@ // unique_lock(unique_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_pass.cpp index ee0d2a8c..cf682fbd 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_pass.cpp @@ -19,7 +19,7 @@ // unique_lock(unique_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp index 3c27882d..0e61cb1a 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_for_pass.cpp @@ -24,7 +24,7 @@ #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp index 796be4d9..3068866f 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_try_pass.cpp @@ -22,7 +22,7 @@ #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp index be61c91d..f1e54cf4 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_shared_lock_until_pass.cpp @@ -24,7 +24,7 @@ #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp index bfa2cbb2..7437ee0e 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_for_pass.cpp @@ -22,7 +22,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp index ad7a8e7b..c72067ae 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_pass.cpp @@ -19,7 +19,7 @@ // unique_lock(upgrade_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp index e1fa9fc4..fdbdf216 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_try_pass.cpp @@ -20,7 +20,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp index 11051e22..cd33f709 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/move_ctor_upgrade_lock_until_pass.cpp @@ -22,7 +22,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/mutex_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/mutex_pass.cpp index aa393be2..808c0346 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/mutex_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/mutex_pass.cpp @@ -19,7 +19,7 @@ // explicit unique_lock(Mutex& m); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/time_point_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/time_point_pass.cpp index 629cb470..10006e32 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/time_point_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/time_point_pass.cpp @@ -21,7 +21,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/cons/try_to_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/cons/try_to_lock_pass.cpp index e542ff9c..d1180839 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/cons/try_to_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/cons/try_to_lock_pass.cpp @@ -19,7 +19,7 @@ // unique_lock(mutex_type& m, try_to_lock_t); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/locking/lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/locking/lock_pass.cpp index 919637c9..83ec7456 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/locking/lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/locking/lock_pass.cpp @@ -18,7 +18,7 @@ // void lock(); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_for_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_for_pass.cpp index 078b8c7c..2be8416e 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_for_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_for_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_pass.cpp index af7a8408..8553c1c0 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_until_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_until_pass.cpp index a642cf8f..df6e7369 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_until_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/locking/try_lock_until_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_until(const chrono::time_point& abs_time); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/locking/unlock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/locking/unlock_pass.cpp index 21a6306a..4ad954f2 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/locking/unlock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/locking/unlock_pass.cpp @@ -18,7 +18,7 @@ // bool unlock(); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/mod/member_swap_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/mod/member_swap_pass.cpp index b0334907..617682fe 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/mod/member_swap_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/mod/member_swap_pass.cpp @@ -18,7 +18,7 @@ // void swap(unique_lock& u); -#include +#include #include struct mutex diff --git a/test/sync/mutual_exclusion/locks/unique_lock/mod/non_member_swap_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/mod/non_member_swap_pass.cpp index 90ec4b0d..74ba5ff3 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/mod/non_member_swap_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/mod/non_member_swap_pass.cpp @@ -17,7 +17,7 @@ // template // void swap(unique_lock& x, unique_lock& y); -#include +#include #include struct mutex diff --git a/test/sync/mutual_exclusion/locks/unique_lock/mod/release_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/mod/release_pass.cpp index c755bc4d..63c3831e 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/mod/release_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/mod/release_pass.cpp @@ -18,7 +18,7 @@ // void Mutex* release(); -#include +#include #include struct mutex diff --git a/test/sync/mutual_exclusion/locks/unique_lock/obs/mutex_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/obs/mutex_pass.cpp index 8eb92420..68f1bbb6 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/obs/mutex_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/obs/mutex_pass.cpp @@ -18,7 +18,7 @@ // Mutex *mutex() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/obs/op_bool_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/obs/op_bool_pass.cpp index 21b65a1e..3fa18225 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/obs/op_bool_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/obs/op_bool_pass.cpp @@ -18,7 +18,7 @@ // explicit operator bool() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/obs/op_int_fail.cpp b/test/sync/mutual_exclusion/locks/unique_lock/obs/op_int_fail.cpp index ffa3e53e..92fe0ffc 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/obs/op_int_fail.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/obs/op_int_fail.cpp @@ -18,7 +18,7 @@ // explicit operator bool() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/obs/owns_lock_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/obs/owns_lock_pass.cpp index 6a78db9c..9956adb2 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/obs/owns_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/obs/owns_lock_pass.cpp @@ -18,7 +18,7 @@ // bool owns_lock() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/unique_lock/types_pass.cpp b/test/sync/mutual_exclusion/locks/unique_lock/types_pass.cpp index db65d79f..69b963a6 100644 --- a/test/sync/mutual_exclusion/locks/unique_lock/types_pass.cpp +++ b/test/sync/mutual_exclusion/locks/unique_lock/types_pass.cpp @@ -25,6 +25,7 @@ // }; +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/adopt_lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/adopt_lock_pass.cpp index 865301c1..d1cead80 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/adopt_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/adopt_lock_pass.cpp @@ -19,7 +19,7 @@ // upgrade_lock(mutex_type& m, adopt_lock_t); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_assign_fail.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_assign_fail.cpp index a2e7c61f..521304d8 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_assign_fail.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_assign_fail.cpp @@ -18,7 +18,7 @@ // upgrade_lock& operator=(upgrade_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_ctor_fail.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_ctor_fail.cpp index b6a92f8e..8e20196b 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_ctor_fail.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/copy_ctor_fail.cpp @@ -19,7 +19,7 @@ // upgrade_lock(upgrade_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/default_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/default_pass.cpp index bd8108fb..59ea2a9a 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/default_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/default_pass.cpp @@ -18,7 +18,7 @@ // upgrade_lock(upgrade_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/defer_lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/defer_lock_pass.cpp index 33a5bf88..ececb845 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/defer_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/defer_lock_pass.cpp @@ -18,7 +18,7 @@ // upgrade_lock(mutex_type& m, adopt_lock_t); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/duration_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/duration_pass.cpp index a62438a8..d2f67150 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/duration_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/duration_pass.cpp @@ -21,7 +21,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_assign_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_assign_pass.cpp index 2bea7a40..42ef355c 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_assign_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_assign_pass.cpp @@ -19,7 +19,7 @@ // upgrade_lock(upgrade_lock const&) = delete; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_pass.cpp index f41c7047..5d5c0a94 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_pass.cpp @@ -19,7 +19,7 @@ // upgrade_lock& operator=(upgrade_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp index e2abb394..ccad7b1a 100644 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_for_pass.cpp @@ -24,7 +24,7 @@ #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp index 9cb79805..93deda8c 100644 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_try_pass.cpp @@ -22,7 +22,7 @@ #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp index 66025c6f..3d2c2871 100644 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_shared_lock_until_pass.cpp @@ -24,7 +24,7 @@ #define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp index 8afac637..3d591d17 100644 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/move_ctor_unique_lock_pass.cpp @@ -19,7 +19,7 @@ // upgrade_lock& operator=(unique_lock&& u); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/mutex_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/mutex_pass.cpp index 104a171e..8873f07e 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/mutex_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/mutex_pass.cpp @@ -19,7 +19,7 @@ // explicit upgrade_lock(Mutex& m); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/time_point_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/time_point_pass.cpp index 26ad92ac..383b9719 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/time_point_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/time_point_pass.cpp @@ -21,7 +21,7 @@ #define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/try_to_lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/try_to_lock_pass.cpp index 9cad5cb6..9d30e0a9 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/cons/try_to_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/cons/try_to_lock_pass.cpp @@ -19,7 +19,7 @@ // upgrade_lock(mutex_type& m, try_to_lock_t); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/lock_pass.cpp index cf95c372..9cd2c6fc 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/lock_pass.cpp @@ -18,7 +18,7 @@ // void lock(); -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_for_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_for_pass.cpp index 9298e947..5f8f4f5f 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_for_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_for_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_pass.cpp index 1136ae48..820fd71a 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_until_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_until_pass.cpp index aca6708d..1c53d6a5 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_until_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/try_lock_until_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_until(const chrono::time_point& abs_time); -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/unlock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/unlock_pass.cpp index 2116561d..bc49a043 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/locking/unlock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/locking/unlock_pass.cpp @@ -19,7 +19,7 @@ // template // bool try_lock_for(const chrono::duration& rel_time); -#include +#include //#include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/mod/member_swap_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/mod/member_swap_pass.cpp index e892aa63..4b0752ef 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/mod/member_swap_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/mod/member_swap_pass.cpp @@ -18,7 +18,7 @@ // void swap(upgrade_lock& u); -#include +#include #include struct shared_mutex diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/mod/non_member_swap_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/mod/non_member_swap_pass.cpp index b7983bef..c7ebaa27 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/mod/non_member_swap_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/mod/non_member_swap_pass.cpp @@ -17,7 +17,7 @@ // template // void swap(upgrade_lock& x, upgrade_lock& y); -#include +#include #include struct shared_mutex diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/mod/release_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/mod/release_pass.cpp index b5976023..22681944 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/mod/release_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/mod/release_pass.cpp @@ -18,7 +18,7 @@ // void Mutex* release(); -#include +#include #include struct shared_mutex diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/obs/mutex_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/obs/mutex_pass.cpp index a730f2c2..276cd0a9 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/obs/mutex_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/obs/mutex_pass.cpp @@ -18,7 +18,7 @@ // Mutex *mutex() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/obs/op_bool_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/obs/op_bool_pass.cpp index dedd3899..4e722d17 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/obs/op_bool_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/obs/op_bool_pass.cpp @@ -18,7 +18,7 @@ // explicit operator bool() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/obs/owns_lock_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/obs/owns_lock_pass.cpp index e6969f2c..9d8b80d6 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/obs/owns_lock_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/obs/owns_lock_pass.cpp @@ -18,7 +18,7 @@ // bool owns_lock() const; -#include +#include #include #include diff --git a/test/sync/mutual_exclusion/locks/upgrade_lock/types_pass.cpp b/test/sync/mutual_exclusion/locks/upgrade_lock/types_pass.cpp index 660ed5ef..876428e4 100755 --- a/test/sync/mutual_exclusion/locks/upgrade_lock/types_pass.cpp +++ b/test/sync/mutual_exclusion/locks/upgrade_lock/types_pass.cpp @@ -25,7 +25,7 @@ // }; -#include +#include #include #include #include diff --git a/test/sync/mutual_exclusion/timed_mutex/assign_fail.cpp b/test/sync/mutual_exclusion/timed_mutex/assign_fail.cpp index 2ef77c8f..49188e13 100644 --- a/test/sync/mutual_exclusion/timed_mutex/assign_fail.cpp +++ b/test/sync/mutual_exclusion/timed_mutex/assign_fail.cpp @@ -27,5 +27,5 @@ int main() boost::timed_mutex m1(m0); } -#include "impl/thread/test/remove_error_code_unused_warning.hpp" +#include "../../../remove_error_code_unused_warning.hpp" diff --git a/test/sync/mutual_exclusion/timed_mutex/copy_fail.cpp b/test/sync/mutual_exclusion/timed_mutex/copy_fail.cpp index 08b9393d..ed0a4c95 100644 --- a/test/sync/mutual_exclusion/timed_mutex/copy_fail.cpp +++ b/test/sync/mutual_exclusion/timed_mutex/copy_fail.cpp @@ -27,4 +27,4 @@ int main() boost::timed_mutex m1(m0); } -#include "impl/thread/test/remove_error_code_unused_warning.hpp" +#include "../../../remove_error_code_unused_warning.hpp" diff --git a/test/test_2309.cpp b/test/test_2309.cpp index 1d1c3e55..78fab44c 100755 --- a/test/test_2309.cpp +++ b/test/test_2309.cpp @@ -3,6 +3,9 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include @@ -21,18 +24,18 @@ } catch (boost::thread_interrupted& interrupt) { - boost::mutex::scoped_lock lock(mutex_); + boost::unique_lock lock(mutex_); cerr << "Thread " << boost::this_thread::get_id() << " got interrupted" << endl; throw(interrupt); } catch (std::exception& e) { - boost::mutex::scoped_lock lock(mutex_); + boost::unique_lock lock(mutex_); cerr << "Thread " << boost::this_thread::get_id() << " caught std::exception" << e.what() << endl; } catch (...) { - boost::mutex::scoped_lock lock(mutex_); + boost::unique_lock lock(mutex_); cerr << "Thread " << boost::this_thread::get_id() << " caught something else" << endl; } } diff --git a/test/test_2741.cpp b/test/test_2741.cpp index cccf0462..06d86ec7 100644 --- a/test/test_2741.cpp +++ b/test/test_2741.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include diff --git a/test/test_3628.cpp b/test/test_3628.cpp index 72256545..02914d81 100644 --- a/test/test_3628.cpp +++ b/test/test_3628.cpp @@ -3,12 +3,16 @@ // Distributed under the 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 2 + #include #include #include #include #include +#if defined BOOST_THREAD_USES_CHRONO + using namespace std; boost::recursive_mutex theMutex; @@ -23,7 +27,7 @@ void ThreadFuncWaiter() for (int j = 0; j < 10; j++) { { - boost::recursive_mutex::scoped_lock lockMtx(theMutex); + boost::unique_lock lockMtx(theMutex); theConditions.push_back(&con1); cout << "Added " << boost::this_thread::get_id() << " " << &con1 << endl; @@ -52,7 +56,7 @@ void ThreadFuncNotifier() for (int j = 0; j < 70; j++) { { - boost::recursive_mutex::scoped_lock lockMtx(theMutex); + boost::unique_lock lockMtx(theMutex); cout << " int calculate_the_answer_to_life_the_universe_and_everything() diff --git a/test/test_4882.cpp b/test/test_4882.cpp index bd6e1e61..d2a7124d 100644 --- a/test/test_4882.cpp +++ b/test/test_4882.cpp @@ -3,47 +3,63 @@ // Distributed under the 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 2 +#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN +//#define BOOST_THREAD_USES_LOG + #include #include #include - -#include +//#include boost::shared_mutex mutex; void thread() { - std::cout << __FILE__ << ":" << __LINE__ << std::endl; + //BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG; } BOOST_CATCH (...) { - std::cerr << " exception\n"; + //BOOST_THREAD_LOG << "exception thrd>" << BOOST_THREAD_END_LOG; } BOOST_CATCH_END - std::cout << __FILE__ << ":" << __LINE__ << std::endl; + //BOOST_THREAD_LOG << "thrd>" << BOOST_THREAD_END_LOG; } int main() { - std::cout << __FILE__ << ":" << __LINE__ << std::endl; + //BOOST_THREAD_LOG << "join(); - std::cout << __FILE__ << ":" << __LINE__ << std::endl; + //BOOST_THREAD_LOG << "main" << BOOST_THREAD_END_LOG; delete threads[i]; + //BOOST_THREAD_LOG << "main" << BOOST_THREAD_END_LOG; } - std::cout << __FILE__ << ":" << __LINE__ << std::endl; + //BOOST_THREAD_LOG << "main>" << BOOST_THREAD_END_LOG; return 0; } diff --git a/test/test_5351.cpp b/test/test_5351.cpp index 48d19658..92b2d696 100644 --- a/test/test_5351.cpp +++ b/test/test_5351.cpp @@ -3,6 +3,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include #include diff --git a/test/test_5542_1.cpp b/test/test_5542_1.cpp index 256ba34d..9e86e504 100644 --- a/test/test_5542_1.cpp +++ b/test/test_5542_1.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include diff --git a/test/test_5542_2.cpp b/test/test_5542_2.cpp index 39a6142b..9111f909 100644 --- a/test/test_5542_2.cpp +++ b/test/test_5542_2.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include void run_thread() { diff --git a/test/test_5542_3.cpp b/test/test_5542_3.cpp index 792bf1d0..b1c8ea28 100644 --- a/test/test_5542_3.cpp +++ b/test/test_5542_3.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include #include diff --git a/test/test_5891.cpp b/test/test_5891.cpp index 9a8c3344..bf24b8b0 100755 --- a/test/test_5891.cpp +++ b/test/test_5891.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include diff --git a/test/test_6130.cpp b/test/test_6130.cpp index d8e84c34..3a92591e 100644 --- a/test/test_6130.cpp +++ b/test/test_6130.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include #include @@ -28,7 +30,7 @@ int main() time_t end_time; assert(now_time < wait_time); - boost::mutex::scoped_lock lk(mtx); + boost::unique_lock lk(mtx); //const bool res = (void)cv.timed_wait(lk, from_time_t(wait_time)); end_time = ::time(0); diff --git a/test/test_6174.cpp b/test/test_6174.cpp index cd7ed4e7..4775c774 100644 --- a/test/test_6174.cpp +++ b/test/test_6174.cpp @@ -4,13 +4,14 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 3 #include #include -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES struct MovableButNonCopyable { -#if ! defined BOOST_NO_DELETED_FUNCTIONS +#if ! defined BOOST_NO_CXX11_DELETED_FUNCTIONS MovableButNonCopyable(MovableButNonCopyable const&) = delete; MovableButNonCopyable& operator=(MovableButNonCopyable const&) = delete; #else diff --git a/test/test_7328.cpp b/test/test_7328.cpp index 87ad8708..6cea415b 100644 --- a/test/test_7328.cpp +++ b/test/test_7328.cpp @@ -3,10 +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) +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include #include +#if defined BOOST_THREAD_USES_CHRONO + //using namespace boost; using namespace boost::chrono; @@ -37,3 +41,7 @@ int main() BOOST_TEST(interrupted); return boost::report_errors(); } + +#else +#error "Test not applicable: BOOST_THREAD_USES_CHRONO not defined for this platform as not supported" +#endif diff --git a/test/test_7571.cpp b/test/test_7571.cpp new file mode 100644 index 00000000..e272c2ad --- /dev/null +++ b/test/test_7571.cpp @@ -0,0 +1,93 @@ +// 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) + +#define BOOST_THREAD_VERSION 2 + +#include +#include +#include +#include + +// Number should be big enough to allow context switch between threads, otherwise the bug doesn't show. +static int MAX_COUNTS; + +class ItemKeeper { + +public: + ItemKeeper() { } + + void doSomething() { + boost::unique_lock scoped_lock(mutex); + int counts = MAX_COUNTS; + while (counts--); + } + +private: + boost::mutex mutex; +}; + +ItemKeeper itemKeeper; + +int MAX_ITERATIONS(5); + +void threadFunc(int invokerID, bool& exceptionOccurred) { + try { + for (int i = 0; i < MAX_ITERATIONS; i++) { + std::cout << "Thread " << invokerID << ", iteration " << i << std::endl; + itemKeeper.doSomething(); + } + } catch (...) { + exceptionOccurred = true; + } +} + + +int main(int argc, char* argv[]) { + if (argc < 2) { + MAX_COUNTS = 5000000; + } else { + std::string valueStr(argv[1]); + bool has_only_digits = (valueStr.find_first_not_of( "0123456789" ) == std::string::npos); + if (has_only_digits) { + std::istringstream aStream(valueStr); + aStream >> MAX_COUNTS; + } else { + std::cerr << "Argument should be an integer\n"; + return 1; + } + } + + bool exceptionOccurred1(false); + bool exceptionOccurred2(false); + + boost::thread thread1(threadFunc, 1, boost::ref(exceptionOccurred1)); + boost::thread thread2(threadFunc, 2, boost::ref(exceptionOccurred2)); + + boost::posix_time::time_duration timeout = boost::posix_time::milliseconds(10000*100); + + bool deadlockOccured(false); + //thread1.join(); + //thread2.join(); + + if (!thread1.timed_join(timeout)) { + deadlockOccured = true; + thread1.interrupt(); + } + if (!thread2.timed_join(timeout)) { + deadlockOccured = true; + thread2.interrupt(); + } + + if (deadlockOccured) { + std::cout << "Deadlock occurred\n"; + return 1; + } + if (exceptionOccurred1 || exceptionOccurred2) { + std::cout << "Exception occurred\n"; + return 1; + } + return 0; +} + diff --git a/test/test_7665.cpp b/test/test_7665.cpp new file mode 100644 index 00000000..ed5c58a0 --- /dev/null +++ b/test/test_7665.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2010 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_USES_LOG + +#include +#include +#include + +void thread() +{ + BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG; +} + +boost::thread example(thread); + +int main() +{ + BOOST_THREAD_LOG << "" << BOOST_THREAD_END_LOG; + return 0; +} + diff --git a/test/test_7666.cpp b/test/test_7666.cpp new file mode 100644 index 00000000..b0c8372f --- /dev/null +++ b/test/test_7666.cpp @@ -0,0 +1,23 @@ +// Copyright (C) 2010 Vicente Botet +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_CHRONO_VERSION 2 +#define BOOST_THREAD_VERSION 2 + +#include + +void myFunc() +{ + boost::this_thread::sleep(boost::posix_time::seconds(5)); +} + +int main(int, char **) +{ + boost::thread p(myFunc); + + p.join(); + + return 0; +} diff --git a/test/test_barrier.cpp b/test/test_barrier.cpp index b9d5fdf1..4a8b9b17 100644 --- a/test/test_barrier.cpp +++ b/test/test_barrier.cpp @@ -4,6 +4,8 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include @@ -26,7 +28,7 @@ void barrier_thread() { if (gen_barrier.wait()) { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); global_parameter++; } } diff --git a/test/test_condition.cpp b/test/test_condition.cpp index f26a9d16..e70d3b5b 100644 --- a/test/test_condition.cpp +++ b/test/test_condition.cpp @@ -5,6 +5,9 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include @@ -27,7 +30,7 @@ struct condition_test_data void condition_test_thread(condition_test_data* data) { - boost::mutex::scoped_lock lock(data->mutex); + boost::unique_lock lock(data->mutex); BOOST_CHECK(lock ? true : false); while (!(data->notified > 0)) data->condition.wait(lock); @@ -50,7 +53,7 @@ private: void condition_test_waits(condition_test_data* data) { - boost::mutex::scoped_lock lock(data->mutex); + boost::unique_lock lock(data->mutex); BOOST_CHECK(lock ? true : false); // Test wait. @@ -104,7 +107,7 @@ void do_test_condition_waits() boost::thread thread(bind(&condition_test_waits, &data)); { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); BOOST_CHECK(lock ? true : false); boost::thread::sleep(delay(1)); diff --git a/test/test_condition_notify_all.cpp b/test/test_condition_notify_all.cpp index 0066576e..16653fdb 100644 --- a/test/test_condition_notify_all.cpp +++ b/test/test_condition_notify_all.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include @@ -28,7 +30,7 @@ void do_test_condition_notify_all_wakes_from_wait() } { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_all(); } @@ -57,7 +59,7 @@ void do_test_condition_notify_all_wakes_from_wait_with_predicate() } { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_all(); } @@ -86,7 +88,7 @@ void do_test_condition_notify_all_wakes_from_timed_wait() } { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_all(); } @@ -115,7 +117,7 @@ void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate() } { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_all(); } @@ -144,7 +146,7 @@ void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate( } { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_all(); } @@ -167,7 +169,7 @@ namespace void wait_for_condvar_and_increase_count() { - boost::mutex::scoped_lock lk(multiple_wake_mutex); + boost::unique_lock lk(multiple_wake_mutex); multiple_wake_cond.wait(lk); ++multiple_wake_count; } @@ -191,7 +193,7 @@ void do_test_notify_all_following_notify_one_wakes_all_threads() boost::this_thread::sleep(boost::posix_time::milliseconds(200)); { - boost::mutex::scoped_lock lk(multiple_wake_mutex); + boost::unique_lock lk(multiple_wake_mutex); BOOST_CHECK(multiple_wake_count==3); } diff --git a/test/test_condition_notify_one.cpp b/test/test_condition_notify_one.cpp index 06ebcf86..9ffabf4e 100644 --- a/test/test_condition_notify_one.cpp +++ b/test/test_condition_notify_one.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include @@ -19,7 +21,7 @@ void do_test_condition_notify_one_wakes_from_wait() boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data)); { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_one(); } @@ -35,7 +37,7 @@ void do_test_condition_notify_one_wakes_from_wait_with_predicate() boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data)); { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_one(); } @@ -51,7 +53,7 @@ void do_test_condition_notify_one_wakes_from_timed_wait() boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data)); { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_one(); } @@ -67,7 +69,7 @@ void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate() boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data)); { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_one(); } @@ -83,7 +85,7 @@ void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate( boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data)); { - boost::mutex::scoped_lock lock(data.mutex); + boost::unique_lock lock(data.mutex); data.flag=true; data.cond_var.notify_one(); } @@ -100,7 +102,7 @@ namespace void wait_for_condvar_and_increase_count() { - boost::mutex::scoped_lock lk(multiple_wake_mutex); + boost::unique_lock lk(multiple_wake_mutex); multiple_wake_cond.wait(lk); ++multiple_wake_count; } @@ -124,7 +126,7 @@ void do_test_multiple_notify_one_calls_wakes_multiple_threads() boost::this_thread::sleep(boost::posix_time::milliseconds(200)); { - boost::mutex::scoped_lock lk(multiple_wake_mutex); + boost::unique_lock lk(multiple_wake_mutex); BOOST_CHECK(multiple_wake_count==3); } diff --git a/test/test_condition_timed_wait_times_out.cpp b/test/test_condition_timed_wait_times_out.cpp index b4e13949..b53c60e9 100644 --- a/test/test_condition_timed_wait_times_out.cpp +++ b/test/test_condition_timed_wait_times_out.cpp @@ -3,6 +3,8 @@ // Distributed under the 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 2 + #include #include @@ -27,7 +29,7 @@ void do_test_timed_wait_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); boost::system_time const timeout=start+delay; @@ -43,7 +45,7 @@ void do_test_timed_wait_with_predicate_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); boost::system_time const timeout=start+delay; @@ -60,7 +62,7 @@ void do_test_relative_timed_wait_with_predicate_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); bool const res=cond.timed_wait(lock,delay,fake_predicate); @@ -76,7 +78,7 @@ void do_test_timed_wait_relative_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); while(cond.timed_wait(lock,delay)) {} @@ -91,7 +93,7 @@ void do_test_cv_any_timed_wait_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); boost::system_time const timeout=start+delay; @@ -107,7 +109,7 @@ void do_test_cv_any_timed_wait_with_predicate_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); boost::system_time const timeout=start+delay; @@ -124,7 +126,7 @@ void do_test_cv_any_relative_timed_wait_with_predicate_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); bool const res=cond.timed_wait(lock,delay,fake_predicate); @@ -140,7 +142,7 @@ void do_test_cv_any_timed_wait_relative_times_out() boost::mutex m; boost::posix_time::seconds const delay(timeout_seconds); - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); boost::system_time const start=boost::get_system_time(); while(cond.timed_wait(lock,delay)) {} diff --git a/test/test_futures.cpp b/test/test_futures.cpp index 68a03f53..7bf77b0e 100644 --- a/test/test_futures.cpp +++ b/test/test_futures.cpp @@ -4,6 +4,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include @@ -18,7 +20,7 @@ #define LOG \ if (false) {} else std::cout << std::endl << __FILE__ << "[" << __LINE__ << "]" -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES template typename boost::remove_reference::type&& cast_to_rval(T&& t) { diff --git a/test/test_generic_locks.cpp b/test/test_generic_locks.cpp index f175979a..91203f3f 100644 --- a/test/test_generic_locks.cpp +++ b/test/test_generic_locks.cpp @@ -3,6 +3,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include @@ -13,7 +15,7 @@ void test_lock_two_uncontended() { boost::mutex m1,m2; - boost::mutex::scoped_lock l1(m1,boost::defer_lock), + boost::unique_lock l1(m1,boost::defer_lock), l2(m2,boost::defer_lock); BOOST_CHECK(!l1.owns_lock()); @@ -37,7 +39,7 @@ struct wait_data void wait() { - boost::mutex::scoped_lock l(m); + boost::unique_lock l(m); while(!flag) { cond.wait(l); @@ -49,7 +51,7 @@ struct wait_data { boost::system_time const target=boost::get_system_time()+d; - boost::mutex::scoped_lock l(m); + boost::unique_lock l(m); while(!flag) { if(!cond.timed_wait(l,target)) @@ -62,7 +64,7 @@ struct wait_data void signal() { - boost::mutex::scoped_lock l(m); + boost::unique_lock l(m); flag=true; cond.notify_all(); } @@ -81,7 +83,7 @@ void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wai void lock_pair(boost::mutex* m1,boost::mutex* m2) { boost::lock(*m1,*m2); - boost::mutex::scoped_lock l1(*m1,boost::adopt_lock), + boost::unique_lock l1(*m1,boost::adopt_lock), l2(*m2,boost::adopt_lock); } @@ -127,7 +129,7 @@ void test_lock_five_uncontended() { boost::mutex m1,m2,m3,m4,m5; - boost::mutex::scoped_lock l1(m1,boost::defer_lock), + boost::unique_lock l1(m1,boost::defer_lock), l2(m2,boost::defer_lock), l3(m3,boost::defer_lock), l4(m4,boost::defer_lock), diff --git a/test/test_lock_concept.cpp b/test/test_lock_concept.cpp index cc9d518c..21f822b2 100644 --- a/test/test_lock_concept.cpp +++ b/test/test_lock_concept.cpp @@ -3,9 +3,12 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include +#include #include #include #include @@ -64,7 +67,7 @@ struct test_initially_unlocked_if_other_thread_has_lock try { { - boost::mutex::scoped_lock lk(done_mutex); + boost::unique_lock lk(done_mutex); BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), boost::bind(&this_type::is_done,this))); BOOST_CHECK(!locked); @@ -122,7 +125,7 @@ struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock try { { - boost::mutex::scoped_lock lk(done_mutex); + boost::unique_lock lk(done_mutex); BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), boost::bind(&this_type::is_done,this))); BOOST_CHECK(!locked); @@ -180,7 +183,7 @@ struct test_initially_locked_if_other_thread_has_shared_lock try { { - boost::mutex::scoped_lock lk(done_mutex); + boost::unique_lock lk(done_mutex); BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), boost::bind(&this_type::is_done,this))); BOOST_CHECK(locked); @@ -305,7 +308,7 @@ struct test_unlocked_after_try_lock_if_other_thread_has_lock try { { - boost::mutex::scoped_lock lk(done_mutex); + boost::unique_lock lk(done_mutex); BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), boost::bind(&this_type::is_done,this))); BOOST_CHECK(!locked); diff --git a/test/test_ml.cpp b/test/test_ml.cpp index 51268d3d..61b7eff5 100755 --- a/test/test_ml.cpp +++ b/test/test_ml.cpp @@ -4,7 +4,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES #include #include diff --git a/test/test_move_function.cpp b/test/test_move_function.cpp index 8d9cd933..c2cefd6d 100644 --- a/test/test_move_function.cpp +++ b/test/test_move_function.cpp @@ -2,6 +2,9 @@ // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_THREAD_VERSION 2 + #include #include #include @@ -94,7 +97,7 @@ namespace user_test_ns struct nc: public boost::shared_ptr { -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES nc() {} nc(nc&&) { @@ -117,7 +120,7 @@ namespace boost void test_move_for_user_defined_type_unaffected() { user_test_ns::nc src; -#ifndef BOOST_NO_RVALUE_REFERENCES +#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES user_test_ns::nc dest=boost::move(src); #else user_test_ns::nc dest=move(src); diff --git a/test/test_mutex.cpp b/test/test_mutex.cpp index b2e14aa1..36ea6d18 100644 --- a/test/test_mutex.cpp +++ b/test/test_mutex.cpp @@ -4,9 +4,12 @@ // Distributed under the 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 2 + #include #include +#include #include #include #include @@ -152,7 +155,7 @@ struct test_lock_times_out_if_other_thread_has_lock try { { - boost::mutex::scoped_lock lk(done_mutex); + boost::unique_lock lk(done_mutex); BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2), boost::bind(&this_type::is_done,this))); BOOST_CHECK(!locked); diff --git a/test/test_once.cpp b/test/test_once.cpp index 8c75dcd7..43afbbd9 100644 --- a/test/test_once.cpp +++ b/test/test_once.cpp @@ -3,6 +3,9 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include #include @@ -18,7 +21,7 @@ boost::mutex m; void initialize_variable() { // ensure that if multiple threads get in here, they are serialized, so we can see the effect - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); ++var_to_init; } @@ -36,7 +39,7 @@ void call_once_thread() break; } } - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); BOOST_CHECK_EQUAL(my_once_value, 1); } @@ -76,7 +79,7 @@ struct increment_value void operator()() const { - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); ++(*value); } }; @@ -95,7 +98,7 @@ void call_once_with_functor() break; } } - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); BOOST_CHECK_EQUAL(my_once_value, 1); } @@ -134,7 +137,7 @@ struct throw_before_third_pass void operator()() const { - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); ++pass_counter; if(pass_counter<3) { @@ -155,7 +158,7 @@ void call_once_with_exception() } catch(throw_before_third_pass::my_exception) { - boost::mutex::scoped_lock lock(m); + boost::unique_lock lock(m); ++exception_counter; } } diff --git a/test/test_shared_mutex.cpp b/test/test_shared_mutex.cpp index c6069bb0..4ed0bb2d 100644 --- a/test/test_shared_mutex.cpp +++ b/test/test_shared_mutex.cpp @@ -3,6 +3,9 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include #include @@ -11,7 +14,7 @@ #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ { \ - boost::mutex::scoped_lock lock(mutex_name); \ + boost::unique_lock lock(mutex_name); \ BOOST_CHECK_EQUAL(value,expected_value); \ } @@ -28,7 +31,7 @@ void test_multiple_readers() boost::mutex unblocked_count_mutex; boost::condition_variable unblocked_condition; boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); try { @@ -39,7 +42,7 @@ void test_multiple_readers() } { - boost::mutex::scoped_lock lk(unblocked_count_mutex); + boost::unique_lock lk(unblocked_count_mutex); while(unblocked_count finish_lock(finish_mutex); try { @@ -115,7 +118,7 @@ void test_reader_blocks_writer() boost::mutex unblocked_count_mutex; boost::condition_variable unblocked_condition; boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); try { @@ -123,7 +126,7 @@ void test_reader_blocks_writer() pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, finish_mutex,simultaneous_running_count,max_simultaneous_running)); { - boost::mutex::scoped_lock lk(unblocked_count_mutex); + boost::unique_lock lk(unblocked_count_mutex); while(unblocked_count<1) { unblocked_condition.wait(lk); @@ -162,7 +165,7 @@ void test_unlocking_writer_unblocks_all_readers() boost::mutex unblocked_count_mutex; boost::condition_variable unblocked_condition; boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); unsigned const reader_count=10; @@ -179,7 +182,7 @@ void test_unlocking_writer_unblocks_all_readers() write_lock.unlock(); { - boost::mutex::scoped_lock lk(unblocked_count_mutex); + boost::unique_lock lk(unblocked_count_mutex); while(unblocked_count finish_reading_lock(finish_reading_mutex); boost::mutex finish_writing_mutex; - boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex); + boost::unique_lock finish_writing_lock(finish_writing_mutex); unsigned const reader_count=10; unsigned const writer_count=10; @@ -235,7 +238,7 @@ void test_unlocking_last_reader_only_unblocks_one_writer() finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers)); } { - boost::mutex::scoped_lock lk(unblocked_count_mutex); + boost::unique_lock lk(unblocked_count_mutex); while(unblocked_count lk(unblocked_count_mutex); while(unblocked_count<(reader_count+1)) { unblocked_condition.wait(lk); diff --git a/test/test_shared_mutex_part_2.cpp b/test/test_shared_mutex_part_2.cpp index ac48d015..e6c47690 100644 --- a/test/test_shared_mutex_part_2.cpp +++ b/test/test_shared_mutex_part_2.cpp @@ -3,6 +3,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include @@ -11,7 +13,7 @@ #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ { \ - boost::mutex::scoped_lock lock(mutex_name); \ + boost::unique_lock lock(mutex_name); \ BOOST_CHECK_EQUAL(value,expected_value); \ } @@ -38,11 +40,11 @@ public: boost::upgrade_lock lk(rwm); { - boost::mutex::scoped_lock ulk(unblocked_mutex); + boost::unique_lock ulk(unblocked_mutex); ++unblocked_count; } - boost::mutex::scoped_lock flk(finish_mutex); + boost::unique_lock flk(finish_mutex); } }; @@ -60,7 +62,7 @@ void test_only_one_upgrade_lock_permitted() boost::mutex unblocked_count_mutex; boost::condition_variable unblocked_condition; boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); try { @@ -100,7 +102,7 @@ void test_can_lock_upgrade_if_currently_locked_shared() boost::mutex unblocked_count_mutex; boost::condition_variable unblocked_condition; boost::mutex finish_mutex; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); unsigned const reader_count=10; @@ -115,7 +117,7 @@ void test_can_lock_upgrade_if_currently_locked_shared() pool.create_thread(locking_thread >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition, finish_mutex,simultaneous_running_count,max_simultaneous_running)); { - boost::mutex::scoped_lock lk(unblocked_count_mutex); + boost::unique_lock lk(unblocked_count_mutex); while(unblocked_count<(reader_count+1)) { unblocked_condition.wait(lk); @@ -153,7 +155,7 @@ void test_if_other_thread_has_write_lock_try_lock_shared_returns_false() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep(boost::posix_time::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -176,7 +178,7 @@ void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep(boost::posix_time::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -221,7 +223,7 @@ void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::thread::sleep(delay(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -244,7 +246,7 @@ void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::thread::sleep(delay(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -267,7 +269,7 @@ void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep(boost::posix_time::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); diff --git a/test/test_shared_mutex_timed_locks.cpp b/test/test_shared_mutex_timed_locks.cpp index e379aa08..7f2a242e 100644 --- a/test/test_shared_mutex_timed_locks.cpp +++ b/test/test_shared_mutex_timed_locks.cpp @@ -3,6 +3,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include @@ -11,7 +13,7 @@ #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ { \ - boost::mutex::scoped_lock lock(mutex_name); \ + boost::unique_lock lock(mutex_name); \ BOOST_CHECK_EQUAL(value,expected_value); \ } @@ -22,7 +24,7 @@ void test_timed_lock_shared_times_out_if_write_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::thread::sleep(delay(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -87,7 +89,7 @@ void test_timed_lock_shared_succeeds_if_read_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::thread::sleep(delay(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -123,7 +125,7 @@ void test_timed_lock_times_out_if_write_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::thread::sleep(delay(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -188,7 +190,7 @@ void test_timed_lock_times_out_if_read_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::thread::sleep(delay(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -224,7 +226,7 @@ void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep(boost::posix_time::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); diff --git a/test/test_shared_mutex_timed_locks_chrono.cpp b/test/test_shared_mutex_timed_locks_chrono.cpp index 2a981941..afa04868 100644 --- a/test/test_shared_mutex_timed_locks_chrono.cpp +++ b/test/test_shared_mutex_timed_locks_chrono.cpp @@ -3,6 +3,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 + #include #include #include @@ -13,7 +15,7 @@ #define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \ { \ - boost::mutex::scoped_lock lock(mutex_name); \ + boost::unique_lock lock(mutex_name); \ BOOST_CHECK_EQUAL(value,expected_value); \ } @@ -24,7 +26,7 @@ void test_timed_lock_shared_times_out_if_write_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep_for(boost::chrono::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -89,7 +91,7 @@ void test_timed_lock_shared_succeeds_if_read_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep_for(boost::chrono::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -125,7 +127,7 @@ void test_timed_lock_times_out_if_write_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep_for(boost::chrono::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -190,7 +192,7 @@ void test_timed_lock_times_out_if_read_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep_for(boost::chrono::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); @@ -226,7 +228,7 @@ void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held() boost::mutex finish_mutex; boost::mutex unblocked_mutex; unsigned unblocked_count=0; - boost::mutex::scoped_lock finish_lock(finish_mutex); + boost::unique_lock finish_lock(finish_mutex); boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count)); boost::this_thread::sleep_for(boost::chrono::seconds(1)); CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u); diff --git a/test/test_thread.cpp b/test/test_thread.cpp index b8a19f17..09717f4d 100644 --- a/test/test_thread.cpp +++ b/test/test_thread.cpp @@ -5,6 +5,9 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include @@ -74,7 +77,7 @@ void test_id_comparison() void interruption_point_thread(boost::mutex* m,bool* failed) { - boost::mutex::scoped_lock lk(*m); + boost::unique_lock lk(*m); boost::this_thread::interruption_point(); *failed=true; } @@ -83,7 +86,7 @@ void do_test_thread_interrupts_at_interruption_point() { boost::mutex m; bool failed=false; - boost::mutex::scoped_lock lk(m); + boost::unique_lock lk(m); boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed)); thrd.interrupt(); lk.unlock(); @@ -98,7 +101,7 @@ void test_thread_interrupts_at_interruption_point() void disabled_interruption_point_thread(boost::mutex* m,bool* failed) { - boost::mutex::scoped_lock lk(*m); + boost::unique_lock lk(*m); boost::this_thread::disable_interruption dc; boost::this_thread::interruption_point(); *failed=false; @@ -108,7 +111,7 @@ void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point() { boost::mutex m; bool failed=true; - boost::mutex::scoped_lock lk(m); + boost::unique_lock lk(m); boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed)); thrd.interrupt(); lk.unlock(); @@ -162,7 +165,7 @@ struct long_running_thread void operator()() { - boost::mutex::scoped_lock lk(mut); + boost::unique_lock lk(mut); while(!done) { cond.wait(lk); @@ -181,7 +184,7 @@ void do_test_timed_join() BOOST_CHECK(!joined); BOOST_CHECK(thrd.joinable()); { - boost::mutex::scoped_lock lk(f.mut); + boost::unique_lock lk(f.mut); f.done=true; f.cond.notify_one(); } diff --git a/test/test_thread_launching.cpp b/test/test_thread_launching.cpp index ee309e42..1137f1de 100644 --- a/test/test_thread_launching.cpp +++ b/test/test_thread_launching.cpp @@ -2,6 +2,9 @@ // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#define BOOST_THREAD_VERSION 3 + #include #include #include diff --git a/test/test_thread_mf.cpp b/test/test_thread_mf.cpp index aa5a5dc1..1d9145f7 100644 --- a/test/test_thread_mf.cpp +++ b/test/test_thread_mf.cpp @@ -5,6 +5,7 @@ // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // +#define BOOST_THREAD_VERSION 3 #include #include diff --git a/test/test_tss.cpp b/test/test_tss.cpp index 22f31c9c..48f1c358 100644 --- a/test/test_tss.cpp +++ b/test/test_tss.cpp @@ -5,6 +5,9 @@ // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_THREAD_VERSION 2 +#define BOOST_THREAD_PROVIDES_INTERRUPTIONS + #include #include @@ -31,14 +34,14 @@ struct tss_value_t { tss_value_t() { - boost::mutex::scoped_lock lock(tss_mutex); + boost::unique_lock lock(tss_mutex); ++tss_instances; ++tss_total; value = 0; } ~tss_value_t() { - boost::mutex::scoped_lock lock(tss_mutex); + boost::unique_lock lock(tss_mutex); --tss_instances; } int value; @@ -56,7 +59,7 @@ void test_tss_thread() // be thread safe. Must evaluate further. if (n != i) { - boost::mutex::scoped_lock lock(check_mutex); + boost::unique_lock lock(check_mutex); BOOST_CHECK_EQUAL(n, i); } ++n; diff --git a/test/test_xtime.cpp b/test/test_xtime.cpp index 2ba3013c..ed66b41b 100644 --- a/test/test_xtime.cpp +++ b/test/test_xtime.cpp @@ -5,6 +5,8 @@ // Distributed under the 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 2 + #include #include @@ -86,7 +88,7 @@ void test_xtime_condvar_backwards_compatibility() boost::condition_variable_any cond_any; boost::mutex m; - boost::mutex::scoped_lock lk(m); + boost::unique_lock lk(m); cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))); cond.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10)),predicate); cond_any.timed_wait(lk,boost::get_xtime(boost::get_system_time()+boost::posix_time::milliseconds(10))); diff --git a/test/threads/container/thread_ptr_list_pass.cpp b/test/threads/container/thread_ptr_list_pass.cpp index 3bf58110..e1266dcb 100644 --- a/test/threads/container/thread_ptr_list_pass.cpp +++ b/test/threads/container/thread_ptr_list_pass.cpp @@ -33,7 +33,7 @@ void join_all(TC & tc) void increment_count() { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); std::cout << "count = " << ++count << std::endl; } diff --git a/test/threads/container/thread_vector_pass.cpp b/test/threads/container/thread_vector_pass.cpp index 121b8ec6..fd561ab3 100644 --- a/test/threads/container/thread_vector_pass.cpp +++ b/test/threads/container/thread_vector_pass.cpp @@ -10,6 +10,7 @@ #include #include #include +#include int count = 0; boost::mutex mutex; @@ -28,19 +29,25 @@ void join_all(TC & tc) template void interrupt_all(TC & tc) { +#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS for (typename TC::iterator it = tc.begin(); it != tc.end(); ++it) { it->interrupt(); } +#endif } } void increment_count() { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); std::cout << "count = " << ++count << std::endl; } +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_THREAD_USES_MOVE +BOOST_STATIC_ASSERT(::boost::is_function >&>::value==false); +#endif + int main() { typedef boost::container::vector thread_vector; @@ -83,6 +90,7 @@ int main() threads.emplace_back(&increment_count); } interrupt_all(threads); + join_all(threads); } return boost::report_errors(); } diff --git a/test/threads/thread/assign/move_pass.cpp b/test/threads/thread/assign/move_pass.cpp index 7d2dfd8a..eb62a22f 100644 --- a/test/threads/thread/assign/move_pass.cpp +++ b/test/threads/thread/assign/move_pass.cpp @@ -92,7 +92,6 @@ int main() BOOST_TEST(G::n_alive == 0); { boost::thread t0(G(), 5, 5.5); - boost::thread::id id = t0.get_id(); boost::thread t1; t0 = boost::move(t1); BOOST_TEST(false); diff --git a/test/threads/thread/constr/FrvalueArgs_pass.cpp b/test/threads/thread/constr/FrvalueArgs_pass.cpp index fdd5be1c..881f0a2b 100644 --- a/test/threads/thread/constr/FrvalueArgs_pass.cpp +++ b/test/threads/thread/constr/FrvalueArgs_pass.cpp @@ -17,6 +17,8 @@ // template thread(F&& f, Args&&... args); +#define BOOST_THREAD_VERSION 4 + #include #include #include @@ -25,6 +27,7 @@ class MoveOnly { +public: BOOST_THREAD_MOVABLE_ONLY(MoveOnly) MoveOnly() { @@ -39,9 +42,11 @@ class MoveOnly int main() { +#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD) { - boost::thread t = boost::thread( BOOST_THREAD_MAKE_RV_REF(MoveOnly()), BOOST_THREAD_MAKE_RV_REF(MoveOnly()) ); + boost::thread t = boost::thread( MoveOnly(), MoveOnly() ); t.join(); } +#endif return boost::report_errors(); } diff --git a/test/threads/thread/constr/Frvalue_pass.cpp b/test/threads/thread/constr/Frvalue_pass.cpp index 4d89a763..5d2821fd 100644 --- a/test/threads/thread/constr/Frvalue_pass.cpp +++ b/test/threads/thread/constr/Frvalue_pass.cpp @@ -24,6 +24,7 @@ #include #include #include +#include class MoveOnly { @@ -44,6 +45,10 @@ MoveOnly MakeMoveOnly() { return BOOST_THREAD_MAKE_RV_REF(MoveOnly()); } +#if defined BOOST_NO_CXX11_RVALUE_REFERENCES && defined BOOST_THREAD_USES_MOVE +BOOST_STATIC_ASSERT(::boost::is_function >&>::value==false); +#endif + int main() { { diff --git a/test/util.inl b/test/util.inl index b85fbb08..010dc50e 100644 --- a/test/util.inl +++ b/test/util.inl @@ -74,7 +74,7 @@ public: void start() { if (type != use_sleep_only) { - boost::mutex::scoped_lock lock(mutex); done = false; + boost::unique_lock lock(mutex); done = false; } else { done = false; } @@ -82,7 +82,7 @@ public: void finish() { if (type != use_sleep_only) { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); done = true; if (type == use_condition) cond.notify_one(); @@ -96,7 +96,7 @@ public: if (type != use_condition) boost::thread::sleep(xt); if (type != use_sleep_only) { - boost::mutex::scoped_lock lock(mutex); + boost::unique_lock lock(mutex); while (type == use_condition && !done) { if (!cond.timed_wait(lock, xt)) break;