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

Compare commits

...

451 Commits

Author SHA1 Message Date
Vladimir Prus
dd51f97e44 Create branch to keep WIP patch for modular build.
[SVN r85883]
2013-09-25 08:12:19 +00:00
Tim Blechmann
04e3d918fb thread: implement physical_concurrency
[SVN r85864]
2013-09-24 06:41:24 +00:00
Vicente J. Botet Escriba
0073516f0a Thread: added missing function wrapper.
[SVN r85863]
2013-09-24 05:35:11 +00:00
Vicente J. Botet Escriba
89de3dcf4f Thread: make it possible to use non default constructible types in sync_queue, but sync_bounded_queue requires it yet.
[SVN r85861]
2013-09-23 21:40:08 +00:00
Vicente J. Botet Escriba
47f40f991f Thread: added first thread_pool.
[SVN r85855]
2013-09-23 16:45:00 +00:00
Vicente J. Botet Escriba
8b351fe473 Thread: fix some move semantic issues on sync_queue and sync_bounded_queue and add tests.
[SVN r85854]
2013-09-23 16:44:26 +00:00
Vicente J. Botet Escriba
24f1e620e8 Thread: fix some move issues on sync_queue.
[SVN r85841]
2013-09-22 22:23:58 +00:00
Vicente J. Botet Escriba
ed6459ecd2 Thread: make code uniform heap_new/heap_delete pairwise.
[SVN r85840]
2013-09-22 22:22:08 +00:00
Vicente J. Botet Escriba
858816b2d2 Thread: add detail:: to access detail::win32::GetTickCount64().
[SVN r85772]
2013-09-18 10:58:46 +00:00
Vicente J. Botet Escriba
4bc70444a4 Thread: try to fix SIGSEGV on win32 issue #7666.
[SVN r85734]
2013-09-17 21:17:02 +00:00
Vicente J. Botet Escriba
fcc027369f Thread: try to fix win32 condition_variable issue #7461.
[SVN r85733]
2013-09-17 21:01:05 +00:00
Vicente J. Botet Escriba
5c78582794 Thread: refactor make_ready_at_thread_exit + inhibit at_thread_exit functions from external threads.
[SVN r85732]
2013-09-17 20:57:46 +00:00
Vicente J. Botet Escriba
7f479a1dec Thread: Added test for tickets.
[SVN r85729]
2013-09-17 19:32:03 +00:00
Vicente J. Botet Escriba
4f2a7b2256 Thread: make use of explicit noncopyable constructor to avoid compile error with Intel compiler.
[SVN r85728]
2013-09-17 19:25:18 +00:00
Vicente J. Botet Escriba
5c88e6ce61 Thread: patch for #8070 to make use of GetTickCount64 when available.
[SVN r85714]
2013-09-16 19:43:37 +00:00
Vicente J. Botet Escriba
650e374492 Thread: Added ostream_buffer.
[SVN r85709]
2013-09-16 17:24:30 +00:00
Vicente J. Botet Escriba
6319080ef2 Thread: add test for get_exception_ptr.
[SVN r85708]
2013-09-16 17:15:05 +00:00
Vicente J. Botet Escriba
3ac48bdd65 Thread: patch for #8070 to make use of GetTickCount64 when available.
[SVN r85701]
2013-09-16 16:55:21 +00:00
Vicente J. Botet Escriba
c3c8ada97d Thread: replace TABS.
[SVN r85677]
2013-09-15 16:13:47 +00:00
Vicente J. Botet Escriba
fd5dd0c2ed Thread: added future<>::get_exception_ptr().
[SVN r85644]
2013-09-10 19:40:14 +00:00
Vicente J. Botet Escriba
4a83aa58ed Thread: add workaround for non compliants compilers on scoped_thread constructor.
[SVN r85643]
2013-09-10 18:55:52 +00:00
Vicente J. Botet Escriba
7d96aa625c Thread: update doc with history.
[SVN r85623]
2013-09-09 17:37:54 +00:00
Vicente J. Botet Escriba
d57a4c6565 Thread: link with boost_atomic conditionaly.
[SVN r85616]
2013-09-08 22:20:48 +00:00
Vicente J. Botet Escriba
c67e39f126 Thread: protect condition_variable/_any wait_for and wait_until from malicious input.
[SVN r85592]
2013-09-07 12:11:44 +00:00
Vicente J. Botet Escriba
5a3c301582 Thread: protect condition_variable/_any wait_for and wait_until from malicious input.
[SVN r85591]
2013-09-07 12:11:18 +00:00
Vicente J. Botet Escriba
dc5a8a9c4e Thread: try to handle with not needed definition of uintptr_t #8817.
[SVN r85540]
2013-09-01 07:25:56 +00:00
Vicente J. Botet Escriba
1e49343ff4 Thread: try to handle with call_once intel issue #8943.
[SVN r85539]
2013-09-01 07:22:21 +00:00
Vicente J. Botet Escriba
93d1855e64 Thread: fix scoped_thread variadic constructor.
[SVN r85494]
2013-08-27 22:37:15 +00:00
Vicente J. Botet Escriba
a39dd7e8b3 Thread: avoid conflict with thread symbol.
[SVN r85493]
2013-08-27 22:35:21 +00:00
Vicente J. Botet Escriba
7e5cb92bab Thread: fix some typos in doc.
[SVN r85492]
2013-08-27 22:31:32 +00:00
Vicente J. Botet Escriba
62cf0f86f6 Thread: fix more typos in doc.
[SVN r85485]
2013-08-27 11:32:24 +00:00
Vicente J. Botet Escriba
c12e07754a Thread: link with boost_chrono and boost_atomic independently of the platform.
[SVN r85464]
2013-08-25 15:13:17 +00:00
Vicente J. Botet Escriba
cbc4266774 Thread: rename wait_until parameter to avoid shadow with member function.
[SVN r85463]
2013-08-25 15:09:12 +00:00
Vicente J. Botet Escriba
3a038d33e5 Thread: rename check by cgeck_counter to avoid conflict with macro.
[SVN r85462]
2013-08-25 15:08:08 +00:00
Vicente J. Botet Escriba
51ba4be998 Thread: fix type and add BOOST_THREAD_USE_ATOMIC macro doc.
[SVN r85432]
2013-08-22 22:11:48 +00:00
Vicente J. Botet Escriba
2d50af8481 Thread: Added synchronized_value operator() to synchronize around a function call.
[SVN r85306]
2013-08-11 20:33:47 +00:00
Vicente J. Botet Escriba
e438c98070 Thread: Add mutex() to upgrade_to_unique_lock (#8891).
[SVN r85195]
2013-08-03 07:47:18 +00:00
Vicente J. Botet Escriba
1e2a76de47 Thread: apply pathc for #8931.
[SVN r85194]
2013-08-03 07:44:15 +00:00
Vicente J. Botet Escriba
34311a60fa Thread: update doc for latches, future continuations.
[SVN r84980]
2013-07-07 20:50:14 +00:00
Vicente J. Botet Escriba
794d54a65c Thread: fix issue with continuation's future parameter which must taken by value.
[SVN r84979]
2013-07-07 20:44:02 +00:00
Vicente J. Botet Escriba
d759dd2dba Thread: fix issue with continuation's future parameter which must taken by value.
[SVN r84978]
2013-07-07 20:36:05 +00:00
Hartmut Kaiser
fe46155997 Getting rid of 64bit warning generated by VS2012
[SVN r84960]
2013-07-06 18:51:54 +00:00
Vicente J. Botet Escriba
cacb5b19a6 Thread: fix issue with future<>::then() when th efuture was not created with async.
[SVN r84955]
2013-07-04 21:44:25 +00:00
Vicente J. Botet Escriba
30803a38b2 Thread: Added assertion on testable_mutex lock when the mutex is locked by this thread.
[SVN r84954]
2013-07-04 21:42:11 +00:00
Vicente J. Botet Escriba
9fc6fec1eb Thread: Add return type to lambda to be portable on msvc10.
[SVN r84953]
2013-07-04 21:40:15 +00:00
Vicente J. Botet Escriba
29babb974e Thread: remove warning in barrier.hpp.
[SVN r84952]
2013-07-04 21:38:33 +00:00
Vicente J. Botet Escriba
66578bf57b Thread: rollback change in #8070 as this includes a regression on windows XP.
[SVN r84946]
2013-07-03 21:16:49 +00:00
Vicente J. Botet Escriba
1da5f9563c Thread: make use of barrier on test sync_queue/multi_thread_pass.cpp and remove some warnings in sync_queue|sync_bounded_queue/single_thread_pass.cpp tests.
[SVN r84911]
2013-06-28 06:00:44 +00:00
Vicente J. Botet Escriba
52039f75a3 Thread: fix some issues with sync_bounded_queue and added tests.
[SVN r84888]
2013-06-23 20:47:03 +00:00
Vicente J. Botet Escriba
bb6fcc3b5c Thread: unused parameter warning removal.
[SVN r84887]
2013-06-23 20:45:26 +00:00
Vicente J. Botet Escriba
1fc1d8aedb Thread: Added future unwrapp constructor.
[SVN r84810]
2013-06-16 21:29:52 +00:00
Vicente J. Botet Escriba
042a86c984 Thread: added completion function on barrier class.
[SVN r84809]
2013-06-16 21:27:59 +00:00
Vicente J. Botet Escriba
364f3ea030 Thread: try to fix regression on MSVC 8/9.
[SVN r84807]
2013-06-16 19:34:25 +00:00
Vicente J. Botet Escriba
c87d27a06d Thread: update history, compliance and fix some parts in external locking doc.
[SVN r84771]
2013-06-14 05:50:29 +00:00
Vicente J. Botet Escriba
68d7c69a4b Thread: update future ref doc.
[SVN r84770]
2013-06-14 05:46:11 +00:00
Vicente J. Botet Escriba
6873d85650 Thread: Added future::unwrap()/get_or()/fallback_to().
[SVN r84719]
2013-06-09 21:41:00 +00:00
Vicente J. Botet Escriba
b59e57e4cc Thread: used cons& in deleted constructors and assignment simulation.
[SVN r84718]
2013-06-09 21:29:17 +00:00
Vicente J. Botet Escriba
d0f9d6216a Thread: remove const on strict locks mutex() function.
[SVN r84712]
2013-06-09 09:15:26 +00:00
Vicente J. Botet Escriba
28564064ff Thread: update history and document force use of Boost.Chrono on windows platforms.
[SVN r84711]
2013-06-09 09:07:05 +00:00
Vicente J. Botet Escriba
ff9636b8e0 Thread: take in account wait_abandoned.
[SVN r84710]
2013-06-09 08:28:28 +00:00
Vicente J. Botet Escriba
d83d23bee0 Thread: force use of chrono on windows.
[SVN r84709]
2013-06-09 08:27:00 +00:00
Vicente J. Botet Escriba
63f35e9f52 Thread: Added test_8674.cpp test.
[SVN r84691]
2013-06-08 16:04:46 +00:00
Vicente J. Botet Escriba
5ad38d52e8 Thread: update doc external_locking.qbk to remove const in mutex() function.
[SVN r84690]
2013-06-08 15:47:00 +00:00
Vicente J. Botet Escriba
9d6cd40d8d Thread: cleanup test_8596.cpp.
[SVN r84689]
2013-06-08 14:54:46 +00:00
Vicente J. Botet Escriba
4362cd655e Thread: update future doc with void set_exception_at_thread_exit(E p).
[SVN r84688]
2013-06-08 14:50:26 +00:00
Vicente J. Botet Escriba
0c44630029 Thread: fix bug on future::then when the continuation is void() ir T&().
[SVN r84685]
2013-06-08 10:53:46 +00:00
Vicente J. Botet Escriba
a01af79331 Thread: apply patch #8550.
[SVN r84684]
2013-06-08 08:21:34 +00:00
Vicente J. Botet Escriba
2df6ce78a4 Thread: fix promise set_at_..._thread_exit; Added preconditions.
[SVN r84678]
2013-06-07 19:03:49 +00:00
Vicente J. Botet Escriba
3951871d70 Thread: update history and fix typo on strict_lock.
[SVN r84628]
2013-06-04 06:02:20 +00:00
Vicente J. Botet Escriba
5a1a9df623 Thread: fix shared_future::get when the shared state is async; refactor the shared_state classes.
[SVN r84607]
2013-06-02 05:56:13 +00:00
Vicente J. Botet Escriba
a6f67e25e3 Thread: fix packaged_task<void()> issue and add tests.
[SVN r84597]
2013-06-01 14:27:16 +00:00
Vicente J. Botet Escriba
b69ec54695 Thread: continue the future.hpp renaming using shared_state.
[SVN r84590]
2013-06-01 07:05:35 +00:00
Vicente J. Botet Escriba
465aee1b66 Thread: Added test for #8596.
[SVN r84589]
2013-06-01 05:11:34 +00:00
Vicente J. Botet Escriba
14d3c59682 Thread added shared_future::then tests.
[SVN r84548]
2013-05-29 20:48:37 +00:00
Vicente J. Botet Escriba
3f2d8f8865 Thread: Added shared_future::then doc.
[SVN r84544]
2013-05-29 06:22:44 +00:00
Vicente J. Botet Escriba
dc8449bd0e Thread: Added shared_future::then.
[SVN r84541]
2013-05-28 20:25:34 +00:00
Vicente J. Botet Escriba
d3a6277714 Thread: Reintroduce BOOST_VERIFY on pthread_mutex_destroy return type #8626.
[SVN r84540]
2013-05-28 20:06:51 +00:00
Vicente J. Botet Escriba
81d8944b96 Thread: fix some typos on external locking.
[SVN r84539]
2013-05-28 20:01:34 +00:00
Vicente J. Botet Escriba
54faaaf087 Thread: replace asynchronous result by shared state on the future doc and add value_type on futures and promise.
[SVN r84521]
2013-05-26 21:28:17 +00:00
Vicente J. Botet Escriba
5a43d5ffe9 Thread: fix copy_exception ambiguity.
[SVN r84520]
2013-05-26 21:26:25 +00:00
Vicente J. Botet Escriba
c628e51e6c Thread: little refactoring on future.hpp; Added make_ready_future.
[SVN r84493]
2013-05-25 12:44:43 +00:00
Vicente J. Botet Escriba
a66b269198 Thread: update history.
[SVN r84489]
2013-05-25 12:01:22 +00:00
Vicente J. Botet Escriba
9e07202e21 Thread: rename internal future_object class by shared_state.
[SVN r84474]
2013-05-25 06:36:37 +00:00
Vicente J. Botet Escriba
9e2a34ca9d Thread: extend duration check from 200ms to 300ms.
[SVN r84467]
2013-05-24 21:24:13 +00:00
Vicente J. Botet Escriba
4cf80c6685 Thread: update latch to use generation to prevent spurious wake-ups.
[SVN r84421]
2013-05-22 17:18:23 +00:00
Vicente J. Botet Escriba
455c31c0e9 Thread: fix inspection issues.
[SVN r84420]
2013-05-22 17:13:03 +00:00
Vicente J. Botet Escriba
a8d5fd48c1 Thread: fix warning.
[SVN r84419]
2013-05-22 17:11:31 +00:00
Vicente J. Botet Escriba
294a5404c2 Thread: fix inspection issues
[SVN r84418]
2013-05-22 17:09:49 +00:00
Vicente J. Botet Escriba
6d01267030 Thread: manage with #8596.
[SVN r84414]
2013-05-22 05:40:58 +00:00
Vicente J. Botet Escriba
1c48d237a8 Thread: fix sur parolle.
[SVN r84331]
2013-05-17 19:24:19 +00:00
Vicente J. Botet Escriba
11ae5c8c44 Thread: fix inspection report.
[SVN r84330]
2013-05-17 19:22:25 +00:00
Vicente J. Botet Escriba
9d10bd035a Thread: fix inspection report.
[SVN r84329]
2013-05-17 19:20:45 +00:00
Vicente J. Botet Escriba
7b48c02d2f Thread: fix warning
[SVN r84185]
2013-05-07 22:18:15 +00:00
Vicente J. Botet Escriba
d8a9331464 Thread: Rollback unwanted and unchecked change
[SVN r84138]
2013-05-04 16:03:48 +00:00
Vicente J. Botet Escriba
b60968b045 Thread: remove definition of BOOST_THREAD_NOEXCEPT_OR_THROW.
[SVN r84134]
2013-05-04 09:05:11 +00:00
Vicente J. Botet Escriba
da41bdb632 Thread: update externally_locked.
[SVN r84110]
2013-05-02 15:42:12 +00:00
Vicente J. Botet Escriba
5fcfd0e4e8 Thread: update the externally_locked_stream interface.
[SVN r84109]
2013-05-02 15:32:29 +00:00
Vicente J. Botet Escriba
2d2d1112d6 Thread: replace boost:tuple in async_func.hpp as not movable until the patch is applied.
[SVN r84098]
2013-05-01 09:19:18 +00:00
Vicente J. Botet Escriba
7cf6934515 Thread: Added #8508 test.
[SVN r84097]
2013-05-01 09:17:39 +00:00
Vicente J. Botet Escriba
757327ba10 Thread: apply patch for #8530.
[SVN r84096]
2013-05-01 08:18:03 +00:00
Vicente J. Botet Escriba
a82843d3ab Thread: update Future section.
[SVN r84084]
2013-04-29 11:45:03 +00:00
Vicente J. Botet Escriba
5779f6676d Thread: update externally_locked with assignment.
[SVN r84076]
2013-04-28 20:12:28 +00:00
Vicente J. Botet Escriba
b359424858 Thread: refactor latch by adding an internal counter that has an associated condition_variable and add doc.
[SVN r84075]
2013-04-28 20:09:50 +00:00
Vicente J. Botet Escriba
a5f7d92960 Thread: fix some typos in externally_locked doc.
[SVN r84065]
2013-04-28 12:12:38 +00:00
Vicente J. Botet Escriba
83167d8c15 Thread: make barrier not copyable.
[SVN r84064]
2013-04-28 12:10:24 +00:00
Vicente J. Botet Escriba
7d2270f8c8 Thread: try to fix time based functions.
[SVN r84056]
2013-04-27 14:39:45 +00:00
Vicente J. Botet Escriba
f87dbb83b1 Thread: Added latch and completion_latch classes.
[SVN r84055]
2013-04-27 06:51:18 +00:00
Vicente J. Botet Escriba
1a613d03a9 Thread: Added call_once test with boost::ref().
[SVN r84005]
2013-04-21 16:39:04 +00:00
Vicente J. Botet Escriba
d42f4ff169 Thread: re-apply the change to invoke as it works for gcc but not for msvc.
[SVN r84004]
2013-04-21 15:32:16 +00:00
Vicente J. Botet Escriba
ffbcf96d90 Thread: let a little bit more time.
[SVN r84003]
2013-04-21 15:04:05 +00:00
Vicente J. Botet Escriba
f5e246ebb0 Thread: rollback comments on invoke as there is a regression on msvc.
[SVN r83988]
2013-04-20 16:31:10 +00:00
Vicente J. Botet Escriba
467a88c4f8 Thread: make use of _POSIX_TIMEOUTS instead of _POSIX_C_SOURCE on the definition BOOST_PTHREAD_HAS_TIMEDLOCK #8443.
[SVN r83962]
2013-04-18 21:34:32 +00:00
Vicente J. Botet Escriba
f021bad1d5 Thread: update changes.
[SVN r83951]
2013-04-18 06:45:01 +00:00
Vicente J. Botet Escriba
ecd97ec4ea Thread: make invoke/async_tuple/tuple_indices more portable.
[SVN r83950]
2013-04-18 06:44:09 +00:00
Vicente J. Botet Escriba
c71882816c Thread: add missing joinable in scoped_thread #8451 + construction from F, Args.
[SVN r83949]
2013-04-18 06:43:19 +00:00
Vicente J. Botet Escriba
ef5d43fac9 Thread: make unnifor definition of BOOST_PTHREAD_HAS_TIMEDLOCK #8443.
[SVN r83948]
2013-04-18 06:41:42 +00:00
Vicente J. Botet Escriba
fb5404947e Thread: update history.
[SVN r83910]
2013-04-14 23:07:10 +00:00
Vicente J. Botet Escriba
f24086fe89 Thread: #6966.
[SVN r83908]
2013-04-14 22:34:10 +00:00
Vicente J. Botet Escriba
3e64214e68 Thread: Added Move traits include file.
[SVN r83906]
2013-04-14 21:34:09 +00:00
Vicente J. Botet Escriba
ed4f0f7b6d Thread: apply patch for #6843.
[SVN r83904]
2013-04-14 21:29:02 +00:00
Vicente J. Botet Escriba
50c18d6274 Detail: Added undef/redef atomic intel macros #6842/#6843.
[SVN r83903]
2013-04-14 21:23:39 +00:00
Vicente J. Botet Escriba
d5cf734a21 Thread: remove noexcept on operations that can unlock the mutex.
[SVN r83902]
2013-04-14 20:31:40 +00:00
Vicente J. Botet Escriba
43f0c059d3 Thread: Added test from [Boost-users] [boost][thread] Future returning 0xfeeefeee.
[SVN r83895]
2013-04-14 12:40:44 +00:00
Vicente J. Botet Escriba
e775ef5c27 Thread: update ref doc for future::then.
[SVN r83817]
2013-04-08 20:10:47 +00:00
Vicente J. Botet Escriba
06b7a41add Thread: update ref doc for concurrent queues.
[SVN r83815]
2013-04-08 19:14:31 +00:00
Vicente J. Botet Escriba
06d2a11127 Thread: rollback BOOST_THREAD_PROVIDES_ONCE_CXX11 define. Force minwg to use BOOST_THREAD_USE_LIB.
[SVN r83796]
2013-04-07 19:01:22 +00:00
Vicente J. Botet Escriba
6dd195bbc6 Thread: Added tennis example to regression tests.
[SVN r83795]
2013-04-07 18:43:53 +00:00
Vicente J. Botet Escriba
8a259612cd Thread: renamed all the examples as ex_; Added some lambda test.
[SVN r83762]
2013-04-04 00:04:16 +00:00
Vicente J. Botet Escriba
9fb88b8f47 Thread: don't define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET on future::then tests.
[SVN r83678]
2013-04-01 17:47:17 +00:00
Vicente J. Botet Escriba
528fcbde56 Thread: major rewrite of future::then.
[SVN r83676]
2013-04-01 16:17:05 +00:00
Vicente J. Botet Escriba
a0397315b2 Thread: minor update in future.hpp to rework future::then.
[SVN r83672]
2013-04-01 07:41:32 +00:00
Vicente J. Botet Escriba
44ec248340 Thread: Added shared_future<>::wait... tests.
[SVN r83667]
2013-03-31 15:16:25 +00:00
Vicente J. Botet Escriba
7eba48576c Thread: added future<>::wait... tests.
[SVN r83666]
2013-03-31 14:47:11 +00:00
Vicente J. Botet Escriba
451027deec Thread: doc updated with sync queues draft and sections reorganization.
[SVN r83654]
2013-03-30 18:39:35 +00:00
Vicente J. Botet Escriba
16b42b6c63 Thread: added non-interleaved externally_locked stream example to regression tests.
[SVN r83653]
2013-03-30 18:38:03 +00:00
Vicente J. Botet Escriba
a543b918f0 Thread: check for time_points in the past on try_join_until to take care of #8323.
[SVN r83652]
2013-03-30 18:28:29 +00:00
Vicente J. Botet Escriba
619ddf54b9 Thread: remove what() function from future_error to take care of #8337.
[SVN r83649]
2013-03-30 14:36:41 +00:00
Vicente J. Botet Escriba
116c947af9 Thread: replace wait_and_ope by ope in sync_queues and pop by pull.
[SVN r83648]
2013-03-30 14:33:42 +00:00
Vicente J. Botet Escriba
a0931c117d Thread: return 0.
[SVN r83645]
2013-03-30 09:37:43 +00:00
Vicente J. Botet Escriba
79e1e88f2e Thread: more refactoring on pthread/shared_mutex.hpp.
[SVN r83553]
2013-03-24 23:45:33 +00:00
Vicente J. Botet Escriba
af3b5f3227 Thread: limit dependency on boost/thread/thread.hpp.
[SVN r83552]
2013-03-24 22:05:50 +00:00
Vicente J. Botet Escriba
7bebf0a062 Thread: fix typo __Lockable.
[SVN r83551]
2013-03-24 22:02:44 +00:00
Vicente J. Botet Escriba
6dad044ab7 Thread: avoid the use of boost/thread/thread.hpp to limit dependencies.
[SVN r83548]
2013-03-24 18:30:55 +00:00
Vicente J. Botet Escriba
19bd0d5eba Thread: Added first version of sync_queue.
[SVN r83547]
2013-03-24 18:29:03 +00:00
Vicente J. Botet Escriba
f922fa56e4 Thread: Added assertions on pthread/shared_mutex.hpp; fixed two shared_mutex tests that were wrong.
[SVN r83546]
2013-03-24 17:18:21 +00:00
Vicente J. Botet Escriba
290faf192d Thread: Added first version of sync_bounded_queue.
[SVN r83538]
2013-03-24 12:24:22 +00:00
Vicente J. Botet Escriba
054bbad65a Thread: update doc addin the missing traits is_recursive_lockable and is_recursive_basic_lockable; Added lock/try_lock requires clause; Added call_once restrictions.
[SVN r83534]
2013-03-23 18:05:10 +00:00
Vicente J. Botet Escriba
df7fbe085a Thread: Added constexpr to future default constructor; protect code incompatible with MSVC8.
[SVN r83521]
2013-03-22 21:50:20 +00:00
Vicente J. Botet Escriba
b03cebff7b Thread: protect some tests with BOOST_THREAD_PROVIDES_VARIADIC_THREAD.
[SVN r83503]
2013-03-19 22:35:50 +00:00
Vicente J. Botet Escriba
c9c46e87b5 Thread: Adapt win32/once.hpp to last changes to invoke..
[SVN r83471]
2013-03-17 08:07:40 +00:00
Vicente J. Botet Escriba
d4e6332eca Thread: add invoke when no variadic templates are available; adapt call_once.
[SVN r83466]
2013-03-16 15:36:21 +00:00
Vicente J. Botet Escriba
80594adcbb Thread: fixed some typos on win32/once.hpp and made use bind when there are some arguments and specialize the algorithm when there are no parameters to avoid errors with bind.
[SVN r83465]
2013-03-16 15:35:10 +00:00
Vicente J. Botet Escriba
4ea14fb9da Thread: rollback one of the changes in [83425].
[SVN r83456]
2013-03-16 08:32:22 +00:00
Vicente J. Botet Escriba
5a22af7639 Thread: force BOOST_THREAD_USES_DATETIME on windows #8198.
[SVN r83426]
2013-03-14 17:23:05 +00:00
Vicente J. Botet Escriba
7b157ab5f4 Thread: Apply patch for #8212.
[SVN r83425]
2013-03-14 17:19:59 +00:00
Vicente J. Botet Escriba
a73425eb00 Thread: use invoke/bind whenever there is atleast one parameter on call_once.
[SVN r83422]
2013-03-13 23:01:49 +00:00
Vicente J. Botet Escriba
b254afc229 Thread: use Boost/Move in invoke.
[SVN r83421]
2013-03-13 22:58:12 +00:00
Vicente J. Botet Escriba
a1edda3437 Thread: Added changes for 1.54.
[SVN r83420]
2013-03-13 22:49:22 +00:00
Vicente J. Botet Escriba
c784369f76 Thread: try to fix call_once for MSVC 8.0,9.0
[SVN r83400]
2013-03-10 17:36:40 +00:00
Vicente J. Botet Escriba
0b7462c4f2 Thread: notify win32/shared_mutex when setting new_state.exclusive_waiting_blocked=false;
[SVN r83397]
2013-03-10 15:17:50 +00:00
Vicente J. Botet Escriba
23ff6e0120 Thread: Added noexcep to some synchronized_value constructors + doc.
[SVN r83396]
2013-03-10 14:54:59 +00:00
Vicente J. Botet Escriba
06491889ea Thread: Try workaround for #8212.
[SVN r83370]
2013-03-09 16:00:22 +00:00
Vicente J. Botet Escriba
abf441ee63 Thread: try to fix double definition of GetTickCount64.
[SVN r83318]
2013-03-05 18:57:34 +00:00
Vicente J. Botet Escriba
9615a51123 Thread: #8237, 8239
[SVN r83312]
2013-03-05 18:05:48 +00:00
Vicente J. Botet Escriba
a0bfa7faeb Thread: activate synchronized_value tests
[SVN r83295]
2013-03-04 18:15:27 +00:00
Vicente J. Botet Escriba
44b741e445 Thread: make use of _WIN32_WINNT instead of WINNT.
[SVN r83294]
2013-03-04 17:52:49 +00:00
Vicente J. Botet Escriba
41d336e7fb Thread: added test for #7755.
[SVN r83286]
2013-03-03 19:13:58 +00:00
Vicente J. Botet Escriba
fc177914e1 Thread: take care of #8136
[SVN r83282]
2013-03-03 14:07:28 +00:00
Vicente J. Botet Escriba
d0056e0cc8 Thread: fix typo on synchronized_value.hp and initialize id_ on testable_mutex.
[SVN r83281]
2013-03-03 13:56:40 +00:00
Vicente J. Botet Escriba
6075cf2df6 Thread: Added test for synchronized_value + synchronize free function
[SVN r83266]
2013-03-03 11:02:31 +00:00
Vicente J. Botet Escriba
1eacb8c71d Thread: Added comments to synchronized_value + synchronize free function
[SVN r83265]
2013-03-03 11:01:07 +00:00
Vicente J. Botet Escriba
7476f71af6 Thread: go towards testable_mutex
[SVN r83264]
2013-03-03 10:55:13 +00:00
Vicente J. Botet Escriba
d86b5d2c0d Thread: Added some synchronized_value tests
[SVN r83262]
2013-03-03 10:22:35 +00:00
Vicente J. Botet Escriba
09f86d603e Thread: fix typo on return value
[SVN r83261]
2013-03-03 10:14:16 +00:00
Vicente J. Botet Escriba
ca3d7dab0b Thread: remove warning
[SVN r83260]
2013-03-03 09:53:25 +00:00
Vicente J. Botet Escriba
7e35a60650 Thread: remove warning
[SVN r83259]
2013-03-03 09:50:26 +00:00
Vicente J. Botet Escriba
2b5bd7275e Thread: Make use of GetTickCount64 when available
[SVN r83258]
2013-03-03 09:45:48 +00:00
Vicente J. Botet Escriba
ca37d07184 Thread: Added value semantics to synchronized value
[SVN r83086]
2013-02-22 17:42:44 +00:00
Vicente J. Botet Escriba
6f2efbcb32 Thread: Added doc on call_once + synchronized_value + lockable_adapter.
[SVN r83085]
2013-02-22 17:25:20 +00:00
Vicente J. Botet Escriba
1ce6a90f95 Thread: see if the use of lightweight_test removes the error: double free or corruption.
[SVN r83040]
2013-02-19 22:45:10 +00:00
Vicente J. Botet Escriba
0a101e15d1 Thread: commit proposed patch for #7720.
[SVN r82973]
2013-02-18 12:11:09 +00:00
Vicente J. Botet Escriba
d2f7766f8a Thread: inhibit msvc warning
[SVN r82955]
2013-02-17 16:16:24 +00:00
Vicente J. Botet Escriba
ba7a0935f2 Thread: added missing include for #7720.
[SVN r82954]
2013-02-17 16:13:54 +00:00
Vicente J. Botet Escriba
7277a94411 Thread: refactor may_alias on once_atomic.hpp.
[SVN r82951]
2013-02-17 15:04:06 +00:00
Vicente J. Botet Escriba
197bbc1fd3 Thread: remove warnings.
[SVN r82950]
2013-02-17 14:59:57 +00:00
Vicente J. Botet Escriba
b9e2d7b13d Thread: prepare for HH shared_mutex.
[SVN r82946]
2013-02-17 10:11:46 +00:00
Hartmut Kaiser
579501d98e Thread: Fixing annoying Windows compilation warning
[SVN r82943]
2013-02-17 04:44:05 +00:00
Vicente J. Botet Escriba
dc352450ca Thread: added load test for shared_mutex.
[SVN r82925]
2013-02-16 15:11:19 +00:00
Vicente J. Botet Escriba
21b2bbc8ca Thread: make use of atomic on the header of once_atomic to avoid not needed cast that report some warnings.
[SVN r82905]
2013-02-15 17:05:49 +00:00
Vicente J. Botet Escriba
bd9105a104 Thread: try to fix some vacpp errors on regression tests.
[SVN r82861]
2013-02-13 22:01:33 +00:00
Vicente J. Botet Escriba
935d851cdf Thread: move local static variable to file scope in future_category.
[SVN r82843]
2013-02-12 20:14:11 +00:00
Vicente J. Botet Escriba
68142e8ff8 Thread: cleanup perf_shared_mutex.cpp.
[SVN r82842]
2013-02-12 20:12:20 +00:00
Anthony Williams
1dad495280 Modify mark_waiting_and_try_lock to return modified count if mutex already locked
[SVN r82828]
2013-02-12 08:21:40 +00:00
Vicente J. Botet Escriba
fb2310b48a Thread: Add vacpp-12.1 to the compilers using chrono.
[SVN r82826]
2013-02-11 22:52:52 +00:00
Vicente J. Botet Escriba
247e9a4f09 Thread: Fixed null_mutex initialization + added tests some tests.
[SVN r82823]
2013-02-11 18:43:33 +00:00
Vicente J. Botet Escriba
c1ec1ada0e Thread: remove no more needed and failing function remove_unused_warning.
[SVN r82809]
2013-02-10 21:37:50 +00:00
Vicente J. Botet Escriba
d030dbd61c Thread: fix some issues with futures of MoveOnly types + complete the variadic async function.
[SVN r82808]
2013-02-10 18:14:49 +00:00
Vicente J. Botet Escriba
bebd56ee21 Thread: fix synchronized_value move constructor.
[SVN r82795]
2013-02-09 14:05:55 +00:00
Vicente J. Botet Escriba
75586eec0e Thread: manage #7980
[SVN r82777]
2013-02-07 18:43:50 +00:00
Vicente J. Botet Escriba
659343d287 Thread: link with Boost.Atomic when compiling for vacpp
[SVN r82776]
2013-02-07 17:06:10 +00:00
Vicente J. Botet Escriba
8e63c72867 Thread: Added timed_lock functions to HH shared_mutex implementation so that we can replace the current shared_mutex by the HH one.
[SVN r82762]
2013-02-06 17:57:16 +00:00
Vicente J. Botet Escriba
65416bb8b6 Thread: make the pthread binary to don't depend on shared_mutex.hpp + #7982
[SVN r82757]
2013-02-06 06:40:30 +00:00
Vicente J. Botet Escriba
71a647b66b Thread: make shared_mutext HH implementation header-only.
[SVN r82746]
2013-02-04 20:22:13 +00:00
Vicente J. Botet Escriba
fc57e9dde0 Thread: Update win32/once.hpp to take care of variadin rvalu call_once parameters.
[SVN r82649]
2013-01-27 21:30:51 +00:00
Vicente J. Botet Escriba
4acfe0975c Thread: Update win32/once.hpp to take care of variadin rvalu call_once parameters.
[SVN r82648]
2013-01-27 21:28:59 +00:00
Vicente J. Botet Escriba
158e8ead50 Thread: update perf shared_mutex file
[SVN r82647]
2013-01-27 21:24:38 +00:00
Vicente J. Botet Escriba
0fc69c4d9e Thread: update H.Hinnant implementation to make it work on Windows.
[SVN r82646]
2013-01-27 21:22:58 +00:00
Vicente J. Botet Escriba
e314bf03ce Thread: fix issue when BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS is defined on win32/pthread.cpp
[SVN r82645]
2013-01-27 20:16:54 +00:00
Vicente J. Botet Escriba
6f2decdacf Thread: added shred mutex impl based on H. Hinnant one
[SVN r82638]
2013-01-27 17:55:00 +00:00
Vicente J. Botet Escriba
4bd3e09a0d Thread: Added performance test for shared_mutex.
[SVN r82637]
2013-01-27 17:29:24 +00:00
Vicente J. Botet Escriba
a16f508b8a Thread: Added two more test cases for call_once for thread I/F.
[SVN r82624]
2013-01-26 16:20:05 +00:00
Vicente J. Botet Escriba
1642db3441 Thread: enable BOOST_THREAD_PROVIDES_ONCE_CXX11 on cal_once_pass test
[SVN r82613]
2013-01-25 20:53:49 +00:00
Vicente J. Botet Escriba
b389079417 Thread: improve call_once using invoke/bind and rvalue references
[SVN r82566]
2013-01-20 17:06:33 +00:00
Vicente J. Botet Escriba
8f7be637b2 Thread: comment BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN define to make evident the bug.
[SVN r82551]
2013-01-19 18:08:20 +00:00
Vicente J. Botet Escriba
94c15aa0cc Thread: changes to fix PGI compiler adding lib atomic.
[SVN r82548]
2013-01-19 08:33:06 +00:00
Vicente J. Botet Escriba
951c8952ff Thread: Added variadic call_once for windows
[SVN r82543]
2013-01-18 22:36:28 +00:00
Vicente J. Botet Escriba
59f91a2405 Thread: extend the timeout in test async_pass.
[SVN r82542]
2013-01-18 22:04:27 +00:00
Vicente J. Botet Escriba
f4a3d52654 Thread: fix call_once when atomic is not used.
[SVN r82530]
2013-01-18 07:18:55 +00:00
Vicente J. Botet Escriba
517e177d7a Thread: minor changes to fix PGI compiler adding lib atomic
[SVN r82529]
2013-01-17 21:09:55 +00:00
Vicente J. Botet Escriba
e72184e9ee Thread: Added atomic once implementation + variadi call_once for pthread
[SVN r82513]
2013-01-16 21:49:59 +00:00
Vicente J. Botet Escriba
73348d69d2 Thread: added specific macros to state if some lock factories are not provided
[SVN r82471]
2013-01-12 22:21:58 +00:00
Vicente J. Botet Escriba
15eff9e412 Thread: adjust some durations on tests
[SVN r82459]
2013-01-12 09:48:54 +00:00
Vicente J. Botet Escriba
dd70cd5b40 Thread: change text associated to exceptions #7882.
[SVN r82457]
2013-01-12 09:05:55 +00:00
Vicente J. Botet Escriba
b290f995d0 Thread: try to remove warning for #7874
[SVN r82456]
2013-01-12 09:03:19 +00:00
Vicente J. Botet Escriba
c1dd0e1e43 Thread: comment not thread-safe check for the time been. atomic<> should be used insted.
[SVN r82455]
2013-01-12 08:52:26 +00:00
Vicente J. Botet Escriba
44a02c1f5f Thread: don't set BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED by default.
[SVN r82436]
2013-01-10 21:35:13 +00:00
Vicente J. Botet Escriba
a0071b301b Thread: Added BOOST_THREAD_NO_CXX11_HDR_TUPLE to wrokarround msvc 10.0 behavior providing <tuple> without move semantics
[SVN r82410]
2013-01-08 22:00:02 +00:00
Vicente J. Botet Escriba
c77281f724 Thread: make the mutex type of externally_locked_stream a template parameter. Polymorfic recursive mutex will be needed if the stream mutex map needs to be external.
[SVN r82397]
2013-01-08 01:28:28 +00:00
Vicente J. Botet Escriba
8a0578c93c Thread: improve external lock for externally_locked_stream.
[SVN r82392]
2013-01-07 23:13:43 +00:00
Vicente J. Botet Escriba
c7dcb1daae Thread: fix typo
[SVN r82375]
2013-01-06 10:06:40 +00:00
Vicente J. Botet Escriba
af330fb61b Thread: try to not run some tests when threadapi is win32.
[SVN r82370]
2013-01-05 22:59:07 +00:00
Vicente J. Botet Escriba
ab64afa2a7 Thread: extend the vacpp versions where boost-cheono is accepted
[SVN r82369]
2013-01-05 22:57:03 +00:00
Vicente J. Botet Escriba
85792f9946 Thread: try to see if this solves some vacpp issues
[SVN r82368]
2013-01-05 22:55:50 +00:00
Vicente J. Botet Escriba
e0d4e63e48 Thread: constraint make_unique_locks when BOOST_NO_CXX11_RVALUE_REFERENCES is not defined
[SVN r82367]
2013-01-05 22:54:55 +00:00
Vicente J. Botet Escriba
b2bd9f4ca9 Thread: fix typo in make_unique_locks without ariadic templates
[SVN r82342]
2013-01-03 22:10:34 +00:00
Vicente J. Botet Escriba
189356680b Thread: make use of BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX.
[SVN r82329]
2013-01-03 11:19:14 +00:00
Vicente J. Botet Escriba
0e0cd2c950 Thread: complete externally_locked_stream.
[SVN r82318]
2013-01-02 14:14:03 +00:00
Vicente J. Botet Escriba
a849a41367 Thread: fix typo on condition BOOST_NO_CXX11_HDR_TUPLE.
[SVN r82317]
2013-01-02 11:17:13 +00:00
Vicente J. Botet Escriba
4b1c13e5cb Thread: replace BOOST_NO_CXX11_HDR_INITIALIZER_LIST by specific BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST that takes in account that gcc up to 4.6 doens't supports it as expected
[SVN r82311]
2013-01-02 00:04:33 +00:00
Vicente J. Botet Escriba
f3777b9306 Thread: extend the workaround on intel compilers up to version 13.0
[SVN r82308]
2013-01-01 10:01:56 +00:00
Vicente J. Botet Escriba
3e5e12e1ac Thread: update configuration variables taking in accont the version rollback
[SVN r82307]
2013-01-01 09:45:38 +00:00
Vicente J. Botet Escriba
a50176c259 Thread: rollback default version 3 change.
[SVN r82302]
2012-12-31 15:10:17 +00:00
Vicente J. Botet Escriba
94e524a1e6 Thread: Fix condition_variable/any::wait_for pred with boost::move
[SVN r82301]
2012-12-31 14:49:41 +00:00
Vicente J. Botet Escriba
cb3259b23f Thread: fix issue with wait_for predicate
[SVN r82299]
2012-12-31 12:42:32 +00:00
Vicente J. Botet Escriba
ec811d3c4a Thread: change resource_deadlock_would_occur from precondition to exception.
[SVN r82298]
2012-12-31 10:03:55 +00:00
Vicente J. Botet Escriba
bf67321336 Thread: wait_for description
[SVN r82297]
2012-12-31 10:02:13 +00:00
Vicente J. Botet Escriba
4b71ef9354 Thread: Added noexcept to scoped_thread
[SVN r82296]
2012-12-31 09:57:10 +00:00
Vicente J. Botet Escriba
23bf16a638 Thread: update doc
[SVN r82283]
2012-12-30 18:24:01 +00:00
Vicente J. Botet Escriba
c3ada352f4 Thread: updated history
[SVN r82162]
2012-12-21 22:52:11 +00:00
Vicente J. Botet Escriba
610bdc4aca Thread: update doc ref #7812
[SVN r82107]
2012-12-19 22:58:36 +00:00
Vicente J. Botet Escriba
6675f4645f Thread: #7422: don't use internal_mutex when interruptions not enabled
[SVN r82094]
2012-12-19 10:50:23 +00:00
Vicente J. Botet Escriba
2895bfe269 Thread: #7808
[SVN r82093]
2012-12-19 06:38:56 +00:00
Vicente J. Botet Escriba
27e2d632cd Thread: #7808
[SVN r82082]
2012-12-18 17:18:17 +00:00
Vicente J. Botet Escriba
abdaa7b5b3 Thread: update doc with internal and external locking
[SVN r82036]
2012-12-16 22:40:10 +00:00
Vicente J. Botet Escriba
e0ed1d6d61 Thread: make set_wait_callback thread-safe.
[SVN r81975]
2012-12-15 17:44:38 +00:00
Vicente J. Botet Escriba
f8b1287153 Thread: workaroun for clang-2.8
[SVN r81968]
2012-12-15 13:13:37 +00:00
Vicente J. Botet Escriba
5ed50d68f2 Thread: replace BOOST_SYSTEM_NOEXCEPT by BOOST_NOEXCEPT
[SVN r81963]
2012-12-14 23:58:46 +00:00
Vicente J. Botet Escriba
2f0a6c01c2 Thread: comment missing file
[SVN r81864]
2012-12-11 18:58:43 +00:00
Vicente J. Botet Escriba
c8edd6c795 Thread: minor refactorings
[SVN r81842]
2012-12-10 22:02:16 +00:00
Vicente J. Botet Escriba
2b8930a5bf System/FileSystem/Asio/Thread: ref #7278 Added noexcept to Boost.System to conform with C++11
[SVN r81808]
2012-12-09 14:47:39 +00:00
Vicente J. Botet Escriba
7c89563108 Thread: Fix comments -use instead BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
[SVN r81804]
2012-12-09 10:52:34 +00:00
Vicente J. Botet Escriba
fcb94bcecf Thread: Add more tests for _at_thread_exit functions when the source is moved.
[SVN r81792]
2012-12-08 14:05:52 +00:00
Vicente J. Botet Escriba
593e9e0f2f Thread: fix shared_ptr implicit conversion to bool introduced in [81780]
[SVN r81788]
2012-12-08 11:01:15 +00:00
Vicente J. Botet Escriba
4209dfaa7f Thread: Added make_strict_lock.
[SVN r81784]
2012-12-08 08:15:49 +00:00
Vicente J. Botet Escriba
0fac7be5b9 Thread: rename _synchronizer as _lock_ptr, and move them outside of synchronized_value so that they can be used in other contexts + update and show usage of unique_lock_ptr.
[SVN r81779]
2012-12-07 23:45:09 +00:00
Vicente J. Botet Escriba
0936913bf6 Thread: Added tests for strict_lock, nested_strict_lock
[SVN r81753]
2012-12-07 07:48:36 +00:00
Vicente J. Botet Escriba
03ebc320f1 Thread: set default version to 3
[SVN r81704]
2012-12-04 16:32:33 +00:00
Vicente J. Botet Escriba
ea11670593 Thread: fix strinct_synchronizer move error and update the example to be run on all compilers.
[SVN r81680]
2012-12-02 21:30:39 +00:00
Vicente J. Botet Escriba
607080857b Thread: uncomment unwanted comments:(.
[SVN r81674]
2012-12-02 20:17:08 +00:00
Vicente J. Botet Escriba
6728fdb3b1 Thread: make synchronized_value use Boost.Move and add some value based operations
[SVN r81673]
2012-12-02 18:30:00 +00:00
Vicente J. Botet Escriba
580c1b7be4 Thread: fix some issues when BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS is defined and add tests
[SVN r81672]
2012-12-02 14:14:09 +00:00
Vicente J. Botet Escriba
03a43d09a4 Thread: update unique_synchronizer
[SVN r81659]
2012-12-01 22:47:10 +00:00
Vicente J. Botet Escriba
7f043d7b07 Thread: uncomment failing indirection in synchronized_value
[SVN r81650]
2012-12-01 12:28:55 +00:00
Vicente J. Botet Escriba
77a8c6667f Thread: update sleep_for algo depending on whether BOOST_THREAD_SLEEP_FOR_IS_STEADY is defined or not
[SVN r81649]
2012-12-01 11:12:01 +00:00
Vicente J. Botet Escriba
418a3f6978 Thread: Added no interruption header-only tests for shared_mutex/shared_lock
[SVN r81648]
2012-12-01 11:10:43 +00:00
Vicente J. Botet Escriba
6b300d2e4c Thread: force BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
[SVN r81647]
2012-12-01 11:08:03 +00:00
Vicente J. Botet Escriba
50ae9d93a6 Thread: Use BOOST_THREAD_LOG
[SVN r81646]
2012-12-01 11:07:10 +00:00
Vicente J. Botet Escriba
168ee37d30 Thread: remove warnings
[SVN r81645]
2012-12-01 11:04:25 +00:00
Vicente J. Botet Escriba
81528d64d5 Thread: Added const_strict_synchronizer.
[SVN r81644]
2012-12-01 11:02:16 +00:00
Marshall Clow
e6b8a133a8 Removed missed usage of deprecated macros in Boost.Thread
[SVN r81593]
2012-11-27 17:26:10 +00:00
Vicente J. Botet Escriba
047ca43b72 Thread: don't use thread_data if no interruptions
[SVN r81583]
2012-11-26 22:58:00 +00:00
Vicente J. Botet Escriba
3c6509184a Thread: improve is_convertible workaround to take care bug for of gcc-4.4 and intel 10.1
[SVN r81534]
2012-11-25 18:38:42 +00:00
Vicente J. Botet Escriba
ec1ce4cf98 Thread: improve is_convertible workaround to take care bug for of gcc-4.4 and intel 10.1
[SVN r81533]
2012-11-25 18:30:19 +00:00
Vicente J. Botet Escriba
526478338d Thread: update log so that we can choose to don't use the this_thread::get_id.
[SVN r81532]
2012-11-25 18:27:06 +00:00
Vicente J. Botet Escriba
f49e6e8dc3 Thread: fix conversion when sizeof(intmax_t)>sizeof(ts.tv_sec).
[SVN r81531]
2012-11-25 18:25:35 +00:00
Vicente J. Botet Escriba
186d58eef7 Thread: update docs and some licenses
[SVN r81525]
2012-11-25 08:19:40 +00:00
Vicente J. Botet Escriba
d2bbc1b7c1 Thread: fix error introduced by 81514
[SVN r81522]
2012-11-24 21:33:11 +00:00
Ion Gaztañaga
2a503b5c81 Replace undocumented Boost.Move usage with new official Boost.Move utilities.
[SVN r81514]
2012-11-24 20:51:32 +00:00
Vicente J. Botet Escriba
a25b918a67 Thread: Added unique lock factories
[SVN r81508]
2012-11-24 16:24:27 +00:00
Vicente J. Botet Escriba
821376f552 Thread: Added make_lock_guard
[SVN r81506]
2012-11-24 12:36:46 +00:00
Vicente J. Botet Escriba
4387de4be8 Thread: add traces to future_then
[SVN r81505]
2012-11-24 08:08:10 +00:00
Vicente J. Botet Escriba
0663b30528 Thread: added internal thread-safe log utility
[SVN r81504]
2012-11-24 07:20:21 +00:00
Vicente J. Botet Escriba
37b0eb2c48 Thread: update is_convertible workaround to try to avoid a regression on intel.12.0
[SVN r81503]
2012-11-24 07:07:48 +00:00
Vicente J. Botet Escriba
de0272abcf Thread: patch #7716
[SVN r81490]
2012-11-23 06:29:30 +00:00
Vicente J. Botet Escriba
cfc3634108 Thread: format text
[SVN r81489]
2012-11-23 06:26:30 +00:00
Vicente J. Botet Escriba
1c62b1599d Thread: manage with #7575 for c++11 compliant compilers + try to fix issue with is_convertible on gcc-4.4.
[SVN r81410]
2012-11-18 10:09:12 +00:00
Vicente J. Botet Escriba
1d2ec17d52 Thread: Towards removing DateTime dependency on the library binary file.
[SVN r81398]
2012-11-17 13:46:49 +00:00
Vicente J. Botet Escriba
0d9e8a0c3c Thread: Towards removing DateTime dependency on the library binary file.
[SVN r81383]
2012-11-17 09:00:16 +00:00
Vicente J. Botet Escriba
9b28bb59c9 Thread: refactor time related conversions + move datetime deprecation to version 4
[SVN r81381]
2012-11-17 07:50:56 +00:00
Vicente J. Botet Escriba
0fce559711 Thread: towards future<>::then(launch, ...
[SVN r81291]
2012-11-11 01:05:55 +00:00
Vicente J. Botet Escriba
de191d213e Thread: deprecate BOOST_THREAD_USES_DATETIME only since version 4.
[SVN r81290]
2012-11-11 01:04:47 +00:00
Vicente J. Botet Escriba
ae89c307bf Thread: ref #7669
[SVN r81289]
2012-11-11 00:57:07 +00:00
Vicente J. Botet Escriba
0dba7ba99b Thread: update doc with history, configuration table
[SVN r81288]
2012-11-10 20:35:07 +00:00
Vicente J. Botet Escriba
1b67c83359 Thread: set default version to 2
[SVN r81283]
2012-11-10 10:34:42 +00:00
Vicente J. Botet Escriba
d28465b656 Thread: update doc with lockable traits, yuturial, compliance.
[SVN r81282]
2012-11-10 10:32:06 +00:00
Vicente J. Botet Escriba
bb3493bdf0 Thread: Added test for #7666
[SVN r81281]
2012-11-10 10:30:05 +00:00
Vicente J. Botet Escriba
0cd8326f21 Thread: deprecate nested scoped locks and DateTime based timed fuctions
[SVN r81279]
2012-11-10 10:25:33 +00:00
Vicente J. Botet Escriba
5c5c818bc5 Thread: manage with ref #7668
[SVN r81270]
2012-11-09 20:26:42 +00:00
Vicente J. Botet Escriba
124b99b2a4 Thread: Added missing include
[SVN r81264]
2012-11-09 16:56:36 +00:00
Vicente J. Botet Escriba
1cabac151a Thread: fix typo.
[SVN r81263]
2012-11-09 16:46:47 +00:00
Vicente J. Botet Escriba
df48b734a2 Thread: rollback to manage with #7657
[SVN r81254]
2012-11-08 20:26:32 +00:00
Vicente J. Botet Escriba
039d744960 Thread added packaged_task__make_ready_at_thread_exit_pass test
[SVN r81225]
2012-11-06 17:20:17 +00:00
Vicente J. Botet Escriba
004e8a4fcf Thread: Added packaged_task::make_ready_at_thread_exit
[SVN r81205]
2012-11-05 17:41:09 +00:00
Vicente J. Botet Escriba
d8f8acbe38 Thread: cleanup + moving lockable traits specializations to the specific files.
[SVN r81175]
2012-11-04 20:37:25 +00:00
Vicente J. Botet Escriba
8a01f9ee09 Thread: cleanup+uncomment catch all
[SVN r81173]
2012-11-04 17:38:09 +00:00
Vicente J. Botet Escriba
315af061cd Thread: Added promise::set_..._at_thread_exit
[SVN r81172]
2012-11-04 16:47:02 +00:00
Vicente J. Botet Escriba
18491c933d Thread added missing file
[SVN r81155]
2012-11-03 00:58:25 +00:00
Vicente J. Botet Escriba
d01c0232da Thread: Added asynch deferred on a specifc configuration+ prepare the work for async futures joining the producer thread
[SVN r81152]
2012-11-02 21:30:36 +00:00
Vicente J. Botet Escriba
91e32e3f02 Thread: extract invoke and make_tuple_indeces on specific files+change the condition to BOOST_NO_CXX11_DECLTYPE_N3276+ fix a warning when BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined
[SVN r81145]
2012-11-02 07:31:19 +00:00
Vicente J. Botet Escriba
88294f4161 Thread: Add the function pointer overloads with MSVC even if it supports rvalue references.
[SVN r81136]
2012-11-01 21:49:20 +00:00
Vicente J. Botet Escriba
9cdc23159a Thread: rollaback unintended default version change
[SVN r81132]
2012-11-01 09:52:13 +00:00
Vicente J. Botet Escriba
c95f1d95af Thread: update doc with warnigs for deprecated features + history
[SVN r81130]
2012-10-31 21:17:49 +00:00
Vicente J. Botet Escriba
45c87d392f Thread: Refactor futures by adding a basic_future common class + added some tests for shared_future
[SVN r81129]
2012-10-31 21:16:00 +00:00
Vicente J. Botet Escriba
1c0a4999b8 Thread: rework async and packaged task.
[SVN r81117]
2012-10-31 01:37:57 +00:00
Vicente J. Botet Escriba
30bfc7bcea Thread: remove some rvalue-references limitations for future::then and make_shared.
[SVN r81111]
2012-10-30 09:36:22 +00:00
Vicente J. Botet Escriba
48f8c1c1c8 Thread Split lock.hpp + towards allowing to disable interruptions
[SVN r81106]
2012-10-29 19:57:01 +00:00
Vicente J. Botet Escriba
c47ea136b6 Thread Split lock.hpp + towards allowing to disable interruptions
[SVN r81105]
2012-10-29 19:19:40 +00:00
Vicente J. Botet Escriba
a3d30b2a89 Thread: Added polymorphic lockables
[SVN r81104]
2012-10-29 19:13:32 +00:00
Vicente J. Botet Escriba
11e15ff0f2 Thread: Added an example using externally_locked_stream
[SVN r81103]
2012-10-29 19:09:47 +00:00
Vicente J. Botet Escriba
fb4b4fb14a Thread: Added externally_locked_stream
[SVN r81102]
2012-10-29 19:09:28 +00:00
Vicente J. Botet Escriba
0ede82e059 Thread: change strict_lock is_locking by own_lock and update lockable concepts
[SVN r81101]
2012-10-29 19:05:51 +00:00
Vicente J. Botet Escriba
708b660c0b Thread: change strict_lock is_locking by own_lock and update lockable concepts
[SVN r81100]
2012-10-29 19:05:35 +00:00
Vicente J. Botet Escriba
9f27bba490 Thread: Added test for #7571
[SVN r81097]
2012-10-29 12:37:53 +00:00
Vicente J. Botet Escriba
095da2890e Thread: deprecate boost::condition
[SVN r81090]
2012-10-29 01:27:53 +00:00
Vicente J. Botet Escriba
389d76cbc1 Thread: document the split of locks.hpp, StrictLock, strict_lock, null_mutex, configuration
[SVN r81089]
2012-10-29 01:25:12 +00:00
Vicente J. Botet Escriba
493cbc030c Thread: Added testable_mutex
[SVN r81088]
2012-10-29 01:12:57 +00:00
Vicente J. Botet Escriba
2f7b936cd6 Thread: Added externally_locked
[SVN r81087]
2012-10-29 01:09:58 +00:00
Vicente J. Botet Escriba
6f3ee1eebf Thread: Added scoped_thread doc
[SVN r81086]
2012-10-29 01:07:36 +00:00
Vicente J. Botet Escriba
32f7b212bd Thread: Added strict locks
[SVN r81084]
2012-10-29 01:03:31 +00:00
Vicente J. Botet Escriba
4fcdabca90 Thread: Added lockable concept checkers
[SVN r81083]
2012-10-29 00:59:57 +00:00
Vicente J. Botet Escriba
b03de37155 Thread: Added files needed to split locks.hpp in several files to limit depedencies
[SVN r81082]
2012-10-29 00:55:31 +00:00
Vicente J. Botet Escriba
73af713503 Thread: Added null_mutex
[SVN r81081]
2012-10-29 00:50:53 +00:00
Vicente J. Botet Escriba
a903532cef Thread: make use of the extracted thread functiors and added default constructor
[SVN r81080]
2012-10-29 00:39:59 +00:00
Vicente J. Botet Escriba
d6178b3139 Thread: update thread_guard to make it a template parameterized by thread functors
[SVN r81079]
2012-10-29 00:36:06 +00:00
Vicente J. Botet Escriba
ec1241a6d8 Thread: Added thread_joiner
[SVN r81074]
2012-10-28 17:55:32 +00:00
Vicente J. Botet Escriba
ae819901ab Thread: Added scoped_thread
[SVN r81073]
2012-10-28 17:53:42 +00:00
Vicente J. Botet Escriba
3c0294cf3a Thread: added first version of synchronized_value
[SVN r81072]
2012-10-28 17:43:40 +00:00
Vicente J. Botet Escriba
21bc767445 Thread: remove include iostream
[SVN r81034]
2012-10-21 09:26:58 +00:00
Vicente J. Botet Escriba
47b6368ef7 Thread: merge 81024
[SVN r81032]
2012-10-21 06:37:51 +00:00
Vicente J. Botet Escriba
a3098b5dfd Thread: Added BOOST_THREAD_DONT_PROVIDE_THREAD_EQ, BOOST_THREAD_DONT_USE_DATETIME and forbid their use when defined + Added BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION and future<>::then + Go towards don't throwing from the cpp files (refactor start_thread, join + Added #define BOOST_THREAD_VERSION 2 for the tests that runs only with version 2
[SVN r81023]
2012-10-20 14:05:32 +00:00
Vicente J. Botet Escriba
bd69c9382f Thread: ref #7461
[SVN r80986]
2012-10-14 16:32:41 +00:00
Vicente J. Botet Escriba
b47f43df59 Thread: Rollback SIG_ATOMIC_MAX change for once.hpp. ref #7499
[SVN r80966]
2012-10-12 00:01:30 +00:00
Vicente J. Botet Escriba
e9217d02f0 Thread: remove some minor warnings
[SVN r80854]
2012-10-04 21:57:18 +00:00
Vicente J. Botet Escriba
6741c8420a Thread: define BOOST_THREAD_PLATFORM_PTHREAD also in windows and restrict it BOOST_NO_SFINAE_EXPR is not defined
[SVN r80853]
2012-10-04 21:55:03 +00:00
Vicente J. Botet Escriba
fe45847841 Thread: remove warning
[SVN r80848]
2012-10-04 17:09:22 +00:00
Vicente J. Botet Escriba
5d13b87dd3 Thread: constraint these test to run only when BOOST_THREAD_USES_CHRONO is defined
[SVN r80847]
2012-10-04 17:08:23 +00:00
Vicente J. Botet Escriba
e1f5fbdc33 Thread: fix typo introduced while making get_id inline on posix
[SVN r80845]
2012-10-04 16:50:46 +00:00
Vicente J. Botet Escriba
b342cf683b Thread: Protect the static assert to catch bug with gcc-4.4
[SVN r80832]
2012-10-03 20:14:15 +00:00
Vicente J. Botet Escriba
e94946cc8c Thread: Added static assert to catch bug with gcc-4.4
[SVN r80830]
2012-10-03 18:47:53 +00:00
Vicente J. Botet Escriba
8604ca1b85 Thread: Fix bug with gcc4.4, prepare change to v3 by default
[SVN r80824]
2012-10-03 05:45:35 +00:00
Vicente J. Botet Escriba
9847f57ce7 Thread: Update doc
[SVN r80823]
2012-10-03 05:43:38 +00:00
Vicente J. Botet Escriba
74e2c4cbcb Thread: Fixed cout access issue
[SVN r80821]
2012-10-02 21:11:29 +00:00
Vicente J. Botet Escriba
7b54159af3 Thread: Make use of BOOST_TRY family macros on win32 code
[SVN r80799]
2012-09-30 23:46:00 +00:00
Vicente J. Botet Escriba
16ad9c868e Thread: make the code of tests set_rvalue and make_future more portable
[SVN r80789]
2012-09-30 17:33:56 +00:00
Vicente J. Botet Escriba
26f4ad3db2 Thread: try to fix some issues with packaged_task with signature parameters
[SVN r80783]
2012-09-30 14:31:52 +00:00
Vicente J. Botet Escriba
715928e143 Thread: Allow BOOST_THREAD_PROVIDES_VARIADIC_THREAD only if BOOST_NO_CXX11_HDR_TUPLE is defined + remove some -ansi flags tha make EXPERIMENTAL_CXX0X to be not defined
[SVN r80766]
2012-09-29 23:35:29 +00:00
Hartmut Kaiser
40d694e893 Thread: adding inline keyword to avoid linker errors
[SVN r80765]
2012-09-29 21:42:36 +00:00
Vicente J. Botet Escriba
4d84fb97c9 Thread: constrain make_future example to run when rvalues references are supported.
[SVN r80763]
2012-09-29 20:54:24 +00:00
Vicente J. Botet Escriba
ab7bb7a82d Thread: try to fix regression on test_once
[SVN r80759]
2012-09-29 18:22:21 +00:00
Vicente J. Botet Escriba
171be40a1f Thread: rollback preceding change and apply patch spliting the assembles so that each instruction is on one line.
[SVN r80757]
2012-09-29 16:53:11 +00:00
Vicente J. Botet Escriba
18d4a8a0f8 Thread: Added missing file
[SVN r80756]
2012-09-29 16:36:19 +00:00
Vicente J. Botet Escriba
dedaa7e617 Thread: version 4: Added variadic templates for packed_task cons, async, thread cons + added make_future + future::get() can be called just once
[SVN r80755]
2012-09-29 16:31:27 +00:00
Jürgen Hunold
6173ae42a9 Fix: C4251 warnings from msvc
Suppress those from the standard library.
Make handle_manager visible via BOOST_THREAD_DECL.

[SVN r80669]
2012-09-23 14:33:50 +00:00
Vicente J. Botet Escriba
792604127e Thread: Added missing what() virtual function of future_error
[SVN r80594]
2012-09-19 00:16:08 +00:00
Vicente J. Botet Escriba
81d0aaf7bc Thread: Added missing what() virtual function of future_error
[SVN r80593]
2012-09-18 23:10:51 +00:00
Vicente J. Botet Escriba
26c495e5b3 Thread: Complete future reference documentation
[SVN r80570]
2012-09-18 06:08:11 +00:00
Vicente J. Botet Escriba
a1f8717170 Thread: fix some typos
[SVN r80565]
2012-09-17 21:30:48 +00:00
Vicente J. Botet Escriba
460a38b994 Thread: (posix) Make use of BOOST_TRY family macros
[SVN r80544]
2012-09-16 18:50:17 +00:00
Vicente J. Botet Escriba
dbefae706c Thread: Fixed windows part of 7360
[SVN r80533]
2012-09-15 14:28:49 +00:00
Vicente J. Botet Escriba
a33e82af60 Thread: fix type on UpgradeLockable requirements
[SVN r80517]
2012-09-13 19:02:37 +00:00
Vicente J. Botet Escriba
8f283b3c2b Thread: fixe typo using std instead of boost.
[SVN r80498]
2012-09-11 22:14:52 +00:00
Vicente J. Botet Escriba
b1ae3a98e8 Thread: Remove temporarly the check on n_alive until I use a movable class
[SVN r80497]
2012-09-11 21:54:06 +00:00
Vicente J. Botet Escriba
fcaaa68f87 Thread: Apply patch for 7360
[SVN r80496]
2012-09-11 21:52:52 +00:00
Vicente J. Botet Escriba
b7622b7407 Thread: complete update for 7345 on windows.
[SVN r80475]
2012-09-09 19:26:47 +00:00
Vicente J. Botet Escriba
a56358c8f8 Thread: Apply patch for 6931.
[SVN r80474]
2012-09-09 19:25:03 +00:00
Vicente J. Botet Escriba
dafe4bea1a Thread: force SIG_ATOMIC_MAX with __STDC_LIMIT_MACROS
[SVN r80466]
2012-09-09 14:48:18 +00:00
Vicente J. Botet Escriba
408a6cb70e Thread: fix typo s/Rational/Rationale/
[SVN r80464]
2012-09-09 13:09:15 +00:00
Vicente J. Botet Escriba
97c0ddbee4 Thread: updated history
[SVN r80461]
2012-09-09 12:46:49 +00:00
Vicente J. Botet Escriba
330502ea1e Thread: Manage with statefull allocators and call destroy on the task object: #7349 and #7350
[SVN r80460]
2012-09-09 12:41:31 +00:00
Vicente J. Botet Escriba
662118b5c6 Thread: Remove BOOST_THREAD_DONT_USE_SYSTEM and update documentation to manage with 7336
[SVN r80459]
2012-09-09 12:35:37 +00:00
Vicente J. Botet Escriba
8bee2291fd Thread: start adding noexcept to recursive_mutex::try_lock. Uncomment needed after checking on windows
[SVN r80449]
2012-09-08 14:18:43 +00:00
Vicente J. Botet Escriba
39c4db3e66 Thread: cleanup include
[SVN r80448]
2012-09-08 14:18:14 +00:00
Vicente J. Botet Escriba
749b1034f9 Thread: test async with moveonly functors.
[SVN r80447]
2012-09-08 14:16:07 +00:00
Vicente J. Botet Escriba
735102d4a0 Thread: update doc with async and notify_all_at_thread_exit referece doc
[SVN r80446]
2012-09-08 14:12:05 +00:00
Vicente J. Botet Escriba
5e30d7486e Thread: Try to fix move limitation on hpux: 7329
[SVN r80439]
2012-09-08 06:43:07 +00:00
Vicente J. Botet Escriba
71f864bc5c Thread: Added notify_all_at_thread_exit+join can throw conditionally if not joinable + detach is no more noexcept
[SVN r80351]
2012-09-01 17:10:16 +00:00
Vicente J. Botet Escriba
b31c1a11d5 Thread: Avoid double definition of BOOST_THREAD_DONT_USE_CHRONO
[SVN r80342]
2012-08-31 23:27:20 +00:00
Vicente J. Botet Escriba
bf03f733a6 Thread: Avoid ambiguity on thread symbol
[SVN r80323]
2012-08-30 17:30:25 +00:00
Vicente J. Botet Escriba
ca04d699bc Thread:7280: Added noexcep to future_category
[SVN r80238]
2012-08-26 18:18:03 +00:00
Vicente J. Botet Escriba
530aaaae38 Thread: 7045: make boost_thread don't depend on boost_chrono for win and 2797: armonize win behavior with posix one.
[SVN r80236]
2012-08-26 15:17:39 +00:00
Vicente J. Botet Escriba
36970f3240 Thread: take care of #7272 warning removal
[SVN r80235]
2012-08-26 13:05:10 +00:00
Vicente J. Botet Escriba
7c97dc8131 Thread: take care of #7272 warning removal
[SVN r80203]
2012-08-25 13:21:21 +00:00
Vicente J. Botet Escriba
a7336c2c5e Thread: update doc
[SVN r80202]
2012-08-25 13:07:54 +00:00
Vicente J. Botet Escriba
8866935d0b Thread: doc shared mutex lack of priority 7284
[SVN r80201]
2012-08-25 13:06:41 +00:00
Vicente J. Botet Escriba
4f06c2392b Thread: update tss doc to take care of #2361 and #3837
[SVN r80198]
2012-08-25 12:28:42 +00:00
Vicente J. Botet Escriba
677113cfbe Thread: fix win regression
[SVN r80152]
2012-08-23 06:25:07 +00:00
Vicente J. Botet Escriba
a01faf1bb8 Thread: fix win regression
[SVN r80134]
2012-08-22 06:12:46 +00:00
Vicente J. Botet Escriba
050b43757f Thread: remove includes using lib/thread
[SVN r80125]
2012-08-21 21:30:00 +00:00
Vicente J. Botet Escriba
448c4b21b5 Thread: added test_3837
[SVN r80124]
2012-08-21 21:29:04 +00:00
Vicente J. Botet Escriba
84d8dea5ba Thread: Add dependency from boost_thread to boost_date_time.
[SVN r80123]
2012-08-21 21:22:35 +00:00
Vicente J. Botet Escriba
5fa5b680f0 Thread: remove dependency from boo_thread to boost_chrono
[SVN r80122]
2012-08-21 21:20:41 +00:00
Vicente J. Botet Escriba
5b26427079 Thread: It seems that the csignal inclusion is failing in all testers, so comment it
[SVN r80082]
2012-08-19 15:41:26 +00:00
Vicente J. Botet Escriba
d426d2ca88 Thread: try to fix 5752
[SVN r80078]
2012-08-18 14:43:06 +00:00
Vicente J. Botet Escriba
2e5bc32b33 Thread: try to fix 7238
[SVN r80076]
2012-08-18 11:26:51 +00:00
Vicente J. Botet Escriba
b0b975e8ef Thread fixes some doc typos
[SVN r80075]
2012-08-18 10:33:31 +00:00
Vicente J. Botet Escriba
1f4df63577 Thread: manage with #5274
[SVN r80053]
2012-08-15 21:29:14 +00:00
Vicente J. Botet Escriba
cf7c218a65 Thread: manage #7173
[SVN r80052]
2012-08-15 20:25:03 +00:00
Vicente J. Botet Escriba
1a1751b45d Thread fix inspecion report errors
[SVN r80049]
2012-08-15 13:11:47 +00:00
Vicente J. Botet Escriba
0354c2fcc3 Thread: apply fix for 7220
[SVN r80041]
2012-08-15 09:59:32 +00:00
Vicente J. Botet Escriba
1679cd2fff Thread: Added date trace for 6130 test
[SVN r80002]
2012-08-13 12:04:17 +00:00
Vicente J. Botet Escriba
32db9f2e71 Thread: Added date trace for 6130 test
[SVN r80001]
2012-08-13 12:03:39 +00:00
Vicente J. Botet Escriba
6b98bee683 Thread: Added test for 7160 ticket
[SVN r79991]
2012-08-12 19:20:35 +00:00
Vicente J. Botet Escriba
7de77cf13c Thread: fixes for inspection report
[SVN r79985]
2012-08-12 18:33:11 +00:00
Vicente J. Botet Escriba
8334f4e68a Thread: name type for pthread/once epoch so that we can choose better an /atomic/ type for it
[SVN r79984]
2012-08-12 18:31:09 +00:00
Vicente J. Botet Escriba
1ac7e7129d Thread: refix 6174
[SVN r79980]
2012-08-12 16:36:40 +00:00
Vicente J. Botet Escriba
daec1268f9 Thread: Added async function
[SVN r79979]
2012-08-12 16:31:21 +00:00
Hartmut Kaiser
c47bd34760 Threads: fixing a bad preprocessor directive
[SVN r79782]
2012-07-28 14:06:27 +00:00
Andrey Semashev
0d9ebfc820 Fixed compilation when Boost.Chrono is disabled by user.
[SVN r79753]
2012-07-26 08:08:06 +00:00
Vicente J. Botet Escriba
3332d8df66 Thread: fix typo - 7117
[SVN r79407]
2012-07-10 20:50:40 +00:00
Vicente J. Botet Escriba
852c173c96 Thread: fix typo - 7117
[SVN r79406]
2012-07-10 20:47:52 +00:00
Vicente J. Botet Escriba
bcf30f2dfc Thread: cleanup no-exceptions on windows
[SVN r79384]
2012-07-09 16:50:35 +00:00
Vicente J. Botet Escriba
2ea1aec7fd Thread: cleanup no-exceptions on windows
[SVN r79383]
2012-07-09 16:46:01 +00:00
Vicente J. Botet Escriba
dc5a26c5d3 Thread: Jamfile cleanup
[SVN r79366]
2012-07-08 19:10:37 +00:00
Vicente J. Botet Escriba
3c8f164371 Thread: no-exception cleanup
[SVN r79365]
2012-07-08 18:53:34 +00:00
Vicente J. Botet Escriba
93c14be188 Thread: no-exceptions cleanup
[SVN r79361]
2012-07-08 17:38:18 +00:00
Vicente J. Botet Escriba
b305cc29fc Thread: Added some changes to make it work with BOOST_NO_EXCEPTIONS
[SVN r79347]
2012-07-08 09:33:13 +00:00
Vicente J. Botet Escriba
c2001fb9d2 Thread: changed assembler for interlocked_bit_test_and_set compatible hp
[SVN r79337]
2012-07-07 14:43:18 +00:00
Vicente J. Botet Escriba
d3a8321be0 Thread: remove warning wait_until
[SVN r79336]
2012-07-07 14:41:02 +00:00
Vicente J. Botet Escriba
8bfd588b4c Thread: remove warning attribute size
[SVN r79335]
2012-07-07 14:38:53 +00:00
Vicente J. Botet Escriba
5268fd3749 Thread: Added __MINGW64_VERSION_MAJOR when __MINGW64__ is not defined
[SVN r79334]
2012-07-07 14:37:07 +00:00
Vicente J. Botet Escriba
19bbd85d9d Thread: rollback bad workaround BOOST_THREAD_WAIT_BUG - 7089
[SVN r79327]
2012-07-07 10:20:39 +00:00
Vicente J. Botet Escriba
deca987299 Thread: Fix 7074
[SVN r79288]
2012-07-05 16:42:01 +00:00
Anthony Williams
1a4eed3b69 Initialization of current_thread_tls_key is direct from macro again to re-enable static initialization
[SVN r79239]
2012-07-03 08:10:41 +00:00
Vicente J. Botet Escriba
1214f99227 Thread: apply patch in 7052
[SVN r79237]
2012-07-02 21:58:56 +00:00
Vicente J. Botet Escriba
51530e03a5 Thread: Added possible missing vector file in some platforms
[SVN r79185]
2012-06-30 09:59:57 +00:00
Vicente J. Botet Escriba
66263dd7b3 Thread: Added other fixed tickets
[SVN r79030]
2012-06-21 21:23:35 +00:00
Vicente J. Botet Escriba
6b0ce64d5e Thread: Fix max macro issue on Windows
[SVN r78920]
2012-06-13 06:34:22 +00:00
Vicente J. Botet Escriba
3b080058ed Thread: rolled back breaking changes on windows.
[SVN r78919]
2012-06-13 06:00:38 +00:00
Vicente J. Botet Escriba
00996a2a02 Thread: rollback unchecked an errored change
[SVN r78863]
2012-06-09 10:09:51 +00:00
Vicente J. Botet Escriba
c0299f4a1e Thread: Added missing BOOST_THREAD_DECL
[SVN r78823]
2012-06-05 21:19:06 +00:00
Vicente J. Botet Escriba
e09105de98 Thread: fix TIME_UTC, WINVER, constexpr for tags, and don't use local files
[SVN r78802]
2012-06-03 18:11:52 +00:00
472 changed files with 40442 additions and 5580 deletions

View File

@@ -36,16 +36,22 @@ import os ;
import feature ;
import indirect ;
import path ;
import configure ;
project boost/thread
: source-location ../src
: requirements <threading>multi
#<link>static:<define>BOOST_THREAD_STATIC_LINK=1
#<link>shared:<define>BOOST_THREAD_DYN_LINK=1
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
<tag>@$(__name__).tag
<toolset>gcc:<cxxflags>-Wno-long-long
<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
#<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
<library>/boost/system//boost_system
#-pedantic -ansi -std=gnu++0x -Wextra -fpermissive
<warnings>all
@@ -54,12 +60,18 @@ project boost/thread
<toolset>gcc:<cxxflags>-Wno-long-long
#<toolset>gcc:<cxxflags>-ansi
#<toolset>gcc:<cxxflags>-fpermissive
<toolset>gcc:<cxxflags>-Wno-variadic-macros
#<toolset>gcc:<cxxflags>-Wunused-local-typedefs
<toolset>gcc:<cxxflags>-Wunused-function
<toolset>darwin:<cxxflags>-Wextra
<toolset>darwin:<cxxflags>-pedantic
<toolset>darwin:<cxxflags>-ansi
#<toolset>darwin:<cxxflags>-ansi
<toolset>darwin:<cxxflags>-fpermissive
<toolset>darwin:<cxxflags>-Wno-long-long
<toolset>darwin:<cxxflags>-Wno-variadic-macros
#<toolset>darwin:<cxxflags>-Wunused-local-typedefs
<toolset>darwin:<cxxflags>-Wunused-function
#<toolset>pathscale:<cxxflags>-Wextra
<toolset>pathscale:<cxxflags>-Wno-long-long
@@ -67,9 +79,11 @@ project boost/thread
<toolset>clang:<cxxflags>-Wextra
<toolset>clang:<cxxflags>-pedantic
<toolset>clang:<cxxflags>-ansi
#<toolset>clang:<cxxflags>-ansi
#<toolset>clang:<cxxflags>-fpermissive
<toolset>clang:<cxxflags>-Wno-long-long
<toolset>clang:<cxxflags>-Wunused-function
<toolset>clang:<cxxflags>-Wno-variadic-macros
<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
@@ -77,6 +91,7 @@ project boost/thread
<toolset>gcc-mingw-4.6.3:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.7.0:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.8.0:<cxxflags>-fdiagnostics-show-option
#<toolset>gcc:<cxxflags>-Wno-missing-field-initializers
<toolset>darwin-4.6.2:<cxxflags>-Wno-delete-non-virtual-dtor
<toolset>darwin-4.7.0:<cxxflags>-Wno-delete-non-virtual-dtor
@@ -85,16 +100,34 @@ project boost/thread
#<toolset>clang-2.8:<cxxflags>-Wno-unused-function
#<toolset>clang-2.9:<cxxflags>-Wno-delete-non-virtual-dtor
#<toolset>clang-2.9:<cxxflags>-Wno-unused-function
<toolset>clang-3.0:<cxxflags>-Wno-delete-non-virtual-dtor
<toolset>clang-3.0:<cxxflags>-Wno-delete-non-virtual-dtor
#<toolset>clang-3.0:<cxxflags>-Wno-unused-function
#<toolset>clang-3.0:<cxxflags>-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
<toolset>intel:<cxxflags>-wd193,304,383,444
<toolset>intel:<cxxflags>-wd593,981
<toolset>intel:<cxxflags>-wd1418
<toolset>intel:<cxxflags>-wd2415
<toolset>msvc:<cxxflags>/wd4512
# : default-build <threading>multi
: usage-requirements # pass these requirement to dependents (i.e. users)
#<link>static:<define>BOOST_THREAD_STATIC_LINK=1
#<link>shared:<define>BOOST_THREAD_DYN_LINK=1
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
#<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
<library>/boost/system//boost_system
;
@@ -108,6 +141,8 @@ local rule default_threadapi ( )
feature.feature threadapi : pthread win32 : propagated ;
feature.set-default threadapi : [ default_threadapi ] ;
exe has_atomic_flag_lockfree : ../build/has_atomic_flag_lockfree_test.cpp ;
rule tag ( name : type ? : property-set )
{
local result = $(name) ;
@@ -204,10 +239,10 @@ rule usage-requirements ( properties * )
}
}
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties)
{
#if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties) || <toolset-vacpp:version>12.1.0.1 in $(properties) || <toolset-vacpp:version>12.1 in $(properties)
#{
result += <library>/boost/chrono//boost_chrono ;
}
#}
return $(result) ;
}
@@ -231,11 +266,15 @@ rule requirements ( properties * )
result = <build>no ;
}
}
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
if ! [ configure.builds has_atomic_flag_lockfree
: $(properties) : "lockfree boost::atomic_flag" ] {
result += <library>/boost/atomic//boost_atomic ;
}
} else {
result += <define>BOOST_THREAD_USES_CHRONO ;
result += <library>/boost/chrono//boost_chrono ;
}
if ! <toolset>vacpp in $(properties) || <toolset-vacpp:version>11.1 in $(properties)
{
result += <library>/boost/chrono//boost_chrono ;
}
return $(result) ;
}
@@ -245,6 +284,7 @@ alias thread_sources
win32/thread.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
future.cpp
: ## requirements ##
<threadapi>win32
;
@@ -253,6 +293,7 @@ alias thread_sources
: ## pthread sources ##
pthread/thread.cpp
pthread/once.cpp
future.cpp
: ## requirements ##
<threadapi>pthread
;
@@ -260,7 +301,7 @@ alias thread_sources
explicit thread_sources ;
lib boost_thread
: thread_sources future.cpp
: thread_sources
: <conditional>@requirements
:
: <link>shared:<define>BOOST_THREAD_USE_DLL=1

View File

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

View File

@@ -1,11 +1,12 @@
[/
(C) Copyright 2007-8 Anthony Williams.
(C) Copyright 2013 Vicente J. Botet Escriba.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:barriers Barriers]
[section:barriers Barriers -- EXTENSION]
A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is
configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have
@@ -18,15 +19,22 @@ arrived. Once the `n`-th thread has reached the barrier, all the waiting threads
class barrier
{
public:
barrier(barrier const&) = delete;
barrier& operator=(barrier const&) = delete;
barrier(unsigned int count);
template <typename F>
barrier(unsigned int count, F&&);
~barrier();
bool wait();
void count_down_and_wait();
};
Instances of __barrier__ are not copyable or movable.
[heading Constructor]
[section Constructor `barrier(unsigned int)`]
barrier(unsigned int count);
@@ -38,7 +46,24 @@ Instances of __barrier__ are not copyable or movable.
]
[heading Destructor]
[endsect]
[section Constructor `barrier(unsigned int, F&&)`]
barrier(unsigned int count, F&& completion);
[variablelist
[[Requires:] [The result type of the completion function call `completion()` is `void` or `unsigned int`.]]
[[Effects:] [Construct a barrier for `count` threads and a completion function `completion`.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
]
[endsect]
[section Destructor `~barrier()`]
~barrier();
@@ -52,21 +77,55 @@ Instances of __barrier__ are not copyable or movable.
]
[heading Member function `wait`]
[endsect]
[section Member Function `wait()`]
bool wait();
[variablelist
[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads
are unblocked, and the barrier is reset. ]]
[[Effects:] [Block until `count` threads have called `wait` or `count_down_and_wait` on `*this`. When the `count`-th thread calls `wait`, the barrier is reset and all waiting threads are unblocked.
The reset depends on whether the barrier was constructed with a completion function or not. If there is no completion function or if the completion function result is void, the reset consists in restoring the original count. Otherwise the rest consist in assigning the result of the completion function (which must not be 0).]]
[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`wait()` is an ['interruption point].]]
]
[endsect]
[section Member Function `count_down_and_wait()`]
void count_down_and_wait();
[variablelist
[[Effects:] [Block until `count` threads have called `wait` or `count_down_and_wait` on `*this`. When the `count`-th thread calls `wait`, the barrier is reset and all waiting threads are unblocked.
The reset depends on whether the barrier was constructed with a completion function or not. If there is no completion function or if the completion function result is void, the reset consists in restoring the original count. Otherwise the rest consist in assigning the result of the completion function (which must not be 0).]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,6 +1,6 @@
[/
(C) Copyright 2007-11 Anthony Williams.
(C) Copyright 2011-12 Vicente J. Botet Escriba.
(C) Copyright 2011-13 Vicente J. Botet Escriba.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
@@ -8,8 +8,247 @@
[section:changes History]
[heading Version 4.2.0 - boost 1.55]
[*New Features:]
* [@http://svn.boost.org/trac/boost/ticket/8519 #8519] Synchro: Update class barrier with a completion function.
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then.
* [@http://svn.boost.org/trac/boost/ticket/8615 #8615] Async: Replace make_future/make_shared_future by make_ready_future.
* [@http://svn.boost.org/trac/boost/ticket/8627 #8627] Async: Add future<>::unwrap and unwrapping constructor.
* [@http://svn.boost.org/trac/boost/ticket/8677 #8677] Async: Add future<>::get_or.
* [@http://svn.boost.org/trac/boost/ticket/8678 #8678] Async: Add future<>::fallback_to.
* [@http://svn.boost.org/trac/boost/ticket/8955 #8955] Request for more efficient way to get exception_ptr from future.
* [@http://svn.boost.org/trac/boost/ticket/8891 #8891] upgrade_to_unique_lock: missing mutex() function.
[*Fixed Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/8768 #8768] win32 condition_variable::wait_until infinite wait in rare cases.
* [@http://svn.boost.org/trac/boost/ticket/8817 #8817] Boost Thread Windows CE _createthreadex handling breaks mingw w64.
* [@http://svn.boost.org/trac/boost/ticket/8943 #8943] Failed to compile code using boost::call_once with Intel C++ Composer XE 2013 on Windows.
* [@http://svn.boost.org/trac/boost/ticket/8931 #8931] Typos in external_locking reference.
* [@http://svn.boost.org/trac/boost/ticket/9029 #9029] Misprint in documentation.
* [@http://svn.boost.org/trac/boost/ticket/9037 #9037] gcc -Wshadow gives warnings in condition_variable{,_fwd}.hpp.
* [@http://svn.boost.org/trac/boost/ticket/9041 #9041] Boost.Thread DSO's may need to link with Boost.Atomic.
* [@http://svn.boost.org/trac/boost/ticket/9048 #9048] boost::scoped_thread useless ctor with variadic template arguments.
* [@http://svn.boost.org/trac/boost/ticket/9079 #9079] Condition variable will wait forever for some timepoint values (Win).
[heading Version 4.1.0 - boost 1.54]
[*New Features:]
* [@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/7445 #7445] Async: Add future<>.then
* [@http://svn.boost.org/trac/boost/ticket/7449 #7449] Synchro: Add a synchronized value class
[*Fixed Bugs:]
* [@http://svn.boost.org/trac/boost/ticket/4878 #4878] MinGW 4.5.0 undefined reference to bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::t imeout target_time).
* [@http://svn.boost.org/trac/boost/ticket/4882 #4882] Win32 shared_mutex does not handle timeouts correctly.
* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms
* [@http://svn.boost.org/trac/boost/ticket/6652 #6652] Boost.Thread shared_mutex.hpp:50:99: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
* [@http://svn.boost.org/trac/boost/ticket/6843 #6843] [Intel C++] Compile Errors with '#include <atomic>'
* [@http://svn.boost.org/trac/boost/ticket/6966 #6966] future boost::future_category inconsistent dll linkage
* [@http://svn.boost.org/trac/boost/ticket/7720 #7720] exception lock_error while intensive locking/unlocking of mutex
* [@http://svn.boost.org/trac/boost/ticket/7755 #7755] Thread: deadlock with shared_mutex on Windows
* [@http://svn.boost.org/trac/boost/ticket/7980 #7980] Build error: msvc-11.0 and BOOST_THREAD_DONT_USE_DATETIME
* [@http://svn.boost.org/trac/boost/ticket/7982 #7982] pthread_delay_np() parm compile error on AIX
* [@http://svn.boost.org/trac/boost/ticket/8027 #8027] thread library fails to compile with Visual Studio 2003
* [@http://svn.boost.org/trac/boost/ticket/8070 #8070] prefer GetTickCount64 over GetTickCount
* [@http://svn.boost.org/trac/boost/ticket/8136 #8136] boost::this_thread::sleep_for() sleeps longer than it should in Windows
* [@http://svn.boost.org/trac/boost/ticket/8212 #8212] Boost thread compilation error on Solaris 10
* [@http://svn.boost.org/trac/boost/ticket/8237 #8237] fix documentation for 'thread_group'
* [@http://svn.boost.org/trac/boost/ticket/8239 #8239] barrier::wait() not marked as interruption_point
* [@http://svn.boost.org/trac/boost/ticket/8323 #8323] boost::thread::try_join_for/try_join_until may block indefinitely due to a combination of problems in Boost.Thread and Boost.Chrono
* [@http://svn.boost.org/trac/boost/ticket/8337 #8337] The internal representation of "std::string(this->code()->message())" escapes, but is destroyed when it exits scope.
* [@http://svn.boost.org/trac/boost/ticket/8371 #8371] C++11 once_flag enabled when constexpr is not available
* [@http://svn.boost.org/trac/boost/ticket/8422 #8422] Assertion in win32::WaitForSingleObject()
* [@http://svn.boost.org/trac/boost/ticket/8443 #8443] Header file inclusion order may cause crashes
* [@http://svn.boost.org/trac/boost/ticket/8451 #8451] Missing documented function 'boost::scoped_thread::joinable'
* [@http://svn.boost.org/trac/boost/ticket/8458 #8458] -DBOOST_THREAD_DONT_USE_CHRONO in thread.obj.rsp but not explicitly set
* [@http://svn.boost.org/trac/boost/ticket/8530 #8530] [Coverity] Unused variable thread_handle, uninitialized variable cond_mutex in thread/pthread/thread_data.hpp
* [@http://svn.boost.org/trac/boost/ticket/8550 #8550] static linking of Boost.Thread with an MFC-Dll
* [@http://svn.boost.org/trac/boost/ticket/8576 #8576] "sur parolle" should be "sur parole".
* [@http://svn.boost.org/trac/boost/ticket/8596 #8596] With C++0x enabled, boost::packaged_task stores a reference to function objects, instead of a copy.
* [@http://svn.boost.org/trac/boost/ticket/8626 #8626] Reintroduce BOOST_VERIFY on pthread_mutex_destroy return type
* [@http://svn.boost.org/trac/boost/ticket/8645 #8645] Typo in Strict lock definition
* [@http://svn.boost.org/trac/boost/ticket/8671 #8671] promise: set_..._at_thread_exit
* [@http://svn.boost.org/trac/boost/ticket/8672 #8672] future<>::then(void()) doesn't works
* [@http://svn.boost.org/trac/boost/ticket/8674 #8674] Futures as local named objects can't be returned with implicit move.
[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<R> is deprecated, use instead packaged_task<R()>.
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/7279 #7279] C++11 compliance: Add noexcept in system related functions
* [@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/7285 #7285] C++11 compliance: Allow to pass movable arguments for call_once
* [@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/7422 #7422] Provide a condition variable with zero-overhead performance penality.
* [@http://svn.boost.org/trac/boost/ticket/7414 #7444] Async: Add make_future/make_shared_future.
* [@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/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/5752 #5752] boost::call_once() is unreliable on some platforms
* [@http://svn.boost.org/trac/boost/ticket/7464 #7464] BOOST_TEST(n_alive == 1); fails due to race condition in a regression test tool.
* [@http://svn.boost.org/trac/boost/ticket/7657 #7657] Serious performance and memory consumption hit if condition_variable methods condition notify_one or notify_all is used repeatedly.
* [@http://svn.boost.org/trac/boost/ticket/7665 #7665] this_thread::sleep_for no longer uses steady_clock in thread.
* [@http://svn.boost.org/trac/boost/ticket/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/7671 #7671] Error including boost/thread.hpp header on iOS.
* [@http://svn.boost.org/trac/boost/ticket/7672 #7672] lockable_traits.hpp syntax error: "defined" token misspelled.
* [@http://svn.boost.org/trac/boost/ticket/7798 #7798] boost::future set_wait_callback thread safety issues.
* [@http://svn.boost.org/trac/boost/ticket/7808 #7808] Incorrect description of effects for this_thread::sleep_for and this_thread::sleep_until.
* [@http://svn.boost.org/trac/boost/ticket/7812 #7812] Returns: cv_status::no_timeout if the call is returning because the time period specified by rel_time has elapsed, cv_status::timeout otherwise.
* [@http://svn.boost.org/trac/boost/ticket/7874 #7874] compile warning: thread.hpp:342: warning: type attributes are honored only at type definition.
* [@http://svn.boost.org/trac/boost/ticket/7875 #7875] BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED should not be enabled by default.
* [@http://svn.boost.org/trac/boost/ticket/7882 #7882] wrong exception text from condition_variable::wait(unique_lock<mutex>&).
* [@http://svn.boost.org/trac/boost/ticket/7890 #7890] thread::do_try_join_until() is missing a return type.
[heading Version 3.1.0 - boost 1.52]
Deprecated Features:
Deprecated features since boost 1.50 available only until boost 1.55:
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have yet 1 year to move to the new features.
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
Breaking changes when BOOST_THREAD_VERSION==3 (Default value since Boost 1.53):
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 3, but the user can however choose the version 2 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Rename the unique_future to future following the c++11.
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
New Features:
* [@http://svn.boost.org/trac/boost/ticket/2361 #2361] thread_specific_ptr: document nature of the key, complexity and rationale.
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] C++11 compliance: Missing async().
* [@http://svn.boost.org/trac/boost/ticket/7283 #7283] C++11 compliance: Add notify_all_at_thread_exit.
* [@http://svn.boost.org/trac/boost/ticket/7345 #7345] C++11 compliance: Add noexcept to recursive mutex try_lock.
Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2797 #2797] Two problems with thread_specific_ptr.
* [@http://svn.boost.org/trac/boost/ticket/5274 #5274] failed to compile future.hpp with stlport 5.1.5 under msvc8.1, because of undefined class.
* [@http://svn.boost.org/trac/boost/ticket/5431 #5431] compile error in Windows CE 6.0(interlocked).
[/* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms.]
* [@http://svn.boost.org/trac/boost/ticket/5696 #5696] win32 detail::set_tss_data does nothing when tss_cleanup_function is NULL.
* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel C++ Compiler XE 12.1.5.344 Build 20120612
* [@http://svn.boost.org/trac/boost/ticket/7045 #7045] Thread library does not automatically compile date_time.
* [@http://svn.boost.org/trac/boost/ticket/7173 #7173] wrong function name interrupt_point().
* [@http://svn.boost.org/trac/boost/ticket/7200 #7200] Unable to build boost.thread modularized.
* [@http://svn.boost.org/trac/boost/ticket/7220 #7220] gcc 4.6.2 warns about inline+dllimport functions.
* [@http://svn.boost.org/trac/boost/ticket/7238 #7238] this_thread::sleep_for() does not respond to interrupt().
* [@http://svn.boost.org/trac/boost/ticket/7245 #7245] Minor typos on documentation related to version 3.
* [@http://svn.boost.org/trac/boost/ticket/7272 #7272] win32/thread_primitives.hpp: (Unneccessary) Warning.
* [@http://svn.boost.org/trac/boost/ticket/7284 #7284] Clarify that there is no access priority between lock and shared_lock on shared mutex.
* [@http://svn.boost.org/trac/boost/ticket/7329 #7329] boost/thread/future.hpp does not compile on HPUX.
* [@http://svn.boost.org/trac/boost/ticket/7336 #7336] BOOST_THREAD_DONT_USE_SYSTEM doesn't work.
* [@http://svn.boost.org/trac/boost/ticket/7329 #7349] packaged_task holds reference to temporary.
* [@http://svn.boost.org/trac/boost/ticket/7350 #7350] allocator_destructor does not destroy object
* [@http://svn.boost.org/trac/boost/ticket/7360 #7360] Memory leak in pthread implementation of boost::thread_specific_ptr
* [@http://svn.boost.org/trac/boost/ticket/7370 #7370] Boost.Thread documentation
* [@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]
Deprecated Features:
Deprecated features since boost 1.50 available only until boost 1.55:
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
Breaking changes when BOOST_THREAD_VERSION==3:
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 3, but the user can however choose the version 2 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Rename the unique_future to future following the c++11.
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/4258 #4258] Linking with boost thread does not work on mingw/gcc 4.5.
* [@http://svn.boost.org/trac/boost/ticket/4885 #4885] Access violation in set_tss_data at process exit due to invalid assumption about TlsAlloc.
* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel Compiler and /debug:parallel
* [@http://svn.boost.org/trac/boost/ticket/7044 #7044] boost 1.50.0 header missing.
* [@http://svn.boost.org/trac/boost/ticket/7052 #7052] Thread: BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 only masks thread::operator==, thread::operator!= forward declarations, not definitions.
* [@http://svn.boost.org/trac/boost/ticket/7066 #7066] An attempt to fix current_thread_tls_key static initialization order.
* [@http://svn.boost.org/trac/boost/ticket/7074 #7074] Multiply defined symbol boost::allocator_arg.
* [@http://svn.boost.org/trac/boost/ticket/7078 #7078] Trivial 64-bit warning fix on Windows for thread attribute stack size
* [@http://svn.boost.org/trac/boost/ticket/7089 #7089] BOOST_THREAD_WAIT_BUG limits functionality without solving anything
[/
#6787 boost::thread::sleep() hangs if system time is rolled back
#7045 Thread library does not automatically compile date_time
]
[heading Version 3.0.0 - boost 1.50]
Breaking changes when BOOST_THREAD_VERSION==3:
* [@http://svn.boost.org/trac/boost/ticket/6229 #6229] Breaking change: Rename the unique_future to future following the c++11.
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
New Features:
* [@http://svn.boost.org/trac/boost/ticket/1850 #1850] Request for unlock_guard to compliment lock_guard.
@@ -20,25 +259,31 @@ New Features:
* [@http://svn.boost.org/trac/boost/ticket/6195 #6195] c++11 compliance: Provide the standard time related interface using Boost.Chrono.
* [@http://svn.boost.org/trac/boost/ticket/6217 #6217] Enhance Boost.Thread shared mutex interface following Howard Hinnant proposal.
* [@http://svn.boost.org/trac/boost/ticket/6224 #6224] c++11 compliance: Add the use of standard noexcept on compilers supporting them.
* [@http://svn.boost.org/trac/boost/ticket/6225 #6225] Add the use of standard =delete defaulted operations on compilers supporting them.
* [@http://svn.boost.org/trac/boost/ticket/6226 #6226] c++11 compliance: Add explicit bool conversion from locks.
* [@http://svn.boost.org/trac/boost/ticket/6228 #6228] Add promise constructor with allocator following the standard c++11.
* [@http://svn.boost.org/trac/boost/ticket/6230 #6230] c++11 compliance: Follows the exception reporting mechanism as defined in the c++11.
* [@http://svn.boost.org/trac/boost/ticket/6266 #6266] Breaking change: thread destructor should call terminate if joinable.
* [@http://svn.boost.org/trac/boost/ticket/6269 #6269] Breaking change: thread move assignment should call terminate if joinable.
* [@http://svn.boost.org/trac/boost/ticket/6231 #6231] Add BasicLockable requirements in the documentation to follow c++11.
* [@http://svn.boost.org/trac/boost/ticket/6272 #6272] c++11 compliance: Add thread::id hash specialization.
* [@http://svn.boost.org/trac/boost/ticket/6273 #6273] c++11 compliance: Add cv_status enum class and use it on the conditions wait functions.
* [@http://svn.boost.org/trac/boost/ticket/6231 #6231] Add BasicLockable requirements in the documentation to follow c++11.
* [@http://svn.boost.org/trac/boost/ticket/6342 #6342] c++11 compliance: Adapt the one_flag to the c++11 interface.
* [@http://svn.boost.org/trac/boost/ticket/6671 #6671] upgrade_lock: missing mutex and release functions.
* [@http://svn.boost.org/trac/boost/ticket/6672 #6672] upgrade_lock:: missing constructors from time related types.
* [@http://svn.boost.org/trac/boost/ticket/6675 #6675] upgrade_lock:: missing non-member swap.
* [@http://svn.boost.org/trac/boost/ticket/6676 #6676] lock conversion should be explicit.
* Added missing packaged_task::result_type and packaged_task:: constructor with allocator.
* Added packaged_task::reset()
Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2380 #2380] boost::move from lvalue does not work with gcc.
* [@http://svn.boost.org/trac/boost/ticket/2430 #2430] shared_mutex for win32 doesn't have timed_lock_upgrade.
* [@http://svn.boost.org/trac/boost/ticket/2575 #2575] Bug- Boost 1.36.0 on Itanium platform.
* [@http://svn.boost.org/trac/boost/ticket/3160 #3160] Duplicate tutorial code in boost::thread.
* [@http://svn.boost.org/trac/boost/ticket/4345 #4345] thread::id and joining problem with cascade of threads.
* [@http://svn.boost.org/trac/boost/ticket/4521 #4521] Error using boost::move on packaged_task (MSVC 10).
* [@http://svn.boost.org/trac/boost/ticket/4711 #4711] Must use implementation details to return move-only types.
* [@http://svn.boost.org/trac/boost/ticket/4921 #4921] BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB are crucial and need to be documented.
* [@http://svn.boost.org/trac/boost/ticket/5013 #5013] documentation: boost::thread: pthreas_exit causes terminate().
* [@http://svn.boost.org/trac/boost/ticket/5173 #5173] boost::this_thread::get_id is very slow.
@@ -47,24 +292,15 @@ Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/5990 #5990] shared_future<T>::get() has wrong return type.
* [@http://svn.boost.org/trac/boost/ticket/6174 #6174] packaged_task doesn't correctly handle moving results.
* [@http://svn.boost.org/trac/boost/ticket/6222 #6222] Compile error with SunStudio: unique_future move.
* [@http://svn.boost.org/trac/boost/ticket/6354 #6354] PGI: Compiler threading support is not turned on.
* [@http://svn.boost.org/trac/boost/ticket/6673 #6673] shared_lock: move assign doesn't works with c++11.
* [@http://svn.boost.org/trac/boost/ticket/6674 #6674] shared_mutex: try_lock_upgrade_until doesn't works.
* [@http://svn.boost.org/trac/boost/ticket/6908 #6908] Compile error due to unprotected definitions of _WIN32_WINNT and WINVER.
* [@http://svn.boost.org/trac/boost/ticket/6940 #6940] TIME_UTC is a macro in C11.
* [@http://svn.boost.org/trac/boost/ticket/6959 #6959] call of abs is ambiguous.
* Fix issue signaled on the ML with task_object(task_object const&) in presence of task_object(task_object &&)
[/
Deprecated features since boost 1.50 available only until boost 1.55:
These deprecated features will be provided by default up to boost 1.52. If you don't want to include the deprecated features you could define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. Since 1.53 these features will not be included any more by default. Since this version, if you want to include the deprecated features yet you could define BOOST_THREAD_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0. These deprecated features will be only available until boost 1.55, that is you have 1 year and a half to move to the new features.
* Time related functions don't using the Boost.Chrono library, use the chrono overloads instead.
Breaking changes:
There are some new features which share the same interface but with different behavior. These breaking features are provided by default when BOOST_THREAD_VERSION is 2, but the user can however choose the version 1 behavior by defining the corresponding macro. As for the deprecated features, these broken features will be only available until boost 1.55.
* #6266 c++11 compliance: thread destructor should call terminate if joinable
* #6269 c++11 compliance: thread move assignment should call terminate if joinable
]
[heading Version 2.1.1 - boost 1.49]
@@ -183,11 +419,28 @@ been moved to __thread_id__.
The following features will be included in next releases.
# Complete the C++11 missing features, in particular
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] Missing async().
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] Use of variadic templates on Generic Locking Algorithms on compilers providing them.
* [@http://svn.boost.org/trac/boost/ticket/6270 #6270] Add thread constructor from movable callable and movable arguments following C++11.
# Add some minor features, in particular
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
# Add some features based on C++ proposals, in particular
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Synchro: Add concurrent queue
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Synchro: Add a latch class.
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Synchro: Add externally locked streams.
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
# Add some of the extension proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf A Standardized Representation of Asynchronous Operations] or extension to them, in particular
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
# And some additional extensions related to futures as:
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic shared_future::then.
[endsect]

View File

@@ -5,14 +5,16 @@
http://www.boost.org/LICENSE_1_0.txt).
]
[section:compliance Conformace and Extension]
[section:compliance Conformance and Extension]
[section:cpp11 C++11 standard Thread library]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3376.html C++11 standard]]
[table C++11 standard Conformace
[table C++11 standard Conformance
[[Section] [Description] [Status] [Comments] [Ticket]]
[[30] [Thread support library] [Partial] [-] [-]]
[[30] [Thread support library] [Yes] [-] [-]]
[[30.1] [General] [-] [-] [-]]
[[30.2] [Requirements] [-] [-] [-]]
[[30.2.1] [Template parameter names] [-] [-] [-]]
@@ -25,12 +27,12 @@
[[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
[[30.2.5.4] [TimedLockable requirements] [Yes] [-] [-]]
[[30.2.6] [decay_copy] [-] [-] [-]]
[[30.3] [Threads] [Partial] [-] [-]]
[[30.3.1] [Class thread] [Partial] [move,variadic,terminate] [#zzzz,#6270,#6269]]
[[30.3] [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] [#zzzz,#6270]]
[[30.3.1.3] [thread destructor] [Partial] [terminate] [#6266]]
[[30.3.1.4] [thread assignment] [Partial] [terminate] [#6269]]
[[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] [-] [-]]
[[30.3.1.6] [thread static members] [Yes] [-] [-]]
[[30.3.1.7] [thread specialized algorithms] [Yes] [-] [-]]
@@ -45,31 +47,30 @@
[[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] [-] [-]]
[[30.4.2.2.2] [unique_lock locking] [Yes] [-] [-]]
[[30.4.2.2.3] [unique_lock modifiers] [Yes] [-] [-]]
[[30.4.2.2.4] [unique_lock observers] [Yes] [] [-]]
[[30.4.2.2.4] [unique_lock observers] [Yes] [ - ] [-]]
[[30.4.3] [Generic locking algorithms] [Partial] [variadic] [#6227]]
[[30.4.4] [Call once] [Partial] [The interface doesn't corresponds] [#6342]]
[[30.4.4.1] [Struct once_flag] [Partial] [interface] [#6342]]
[[30.4.4.2] [Function call_once] [Partial] [interface] [#6342]]
[[30.5] [Condition variables] [Partial] [notify_all_at_thread_exit] [#xxxx]]
[[30.5 6-10] [Function notify_all_at_thread_exit] [No] [-] [#xxxx]]
[[30.4.4] [Call once] [Yes] [-] [-]]
[[30.4.4.1] [Struct once_flag] [Yes] [-] [-]]
[[30.4.4.2] [Function call_once] [Yes] [-] [-]]
[[30.5] [Condition variables] [Yes] [-] [-]]
[[30.5.1] [Class condition_variable] [Yes] [-] [-]]
[[30.5.2] [Class condition_variable_any] [Yes] [-] [-]]
[[30.6] [Futures] [Partial] [-] [-]]
[[30.6] [Futures] [Yes] [-] [-]]
[[30.6.1] [Overview] [Partial] [-] [-]]
[[30.6.2] [Error handling] [Yes] [-] [-]]
[[30.6.3] [Class future_error] [Yes] [-] [-]]
[[30.6.3] [Class future_error] [-] [-] [-]]
[[30.6.4] [Shared state] [-] [-] [-]]
[[30.6.5] [Class template promise] [Partial] [allocator] [#6228]]
[[30.6.6] [Class template future] [Partial] [allocator,unique_future is the closest to future, renamed in V3] [#6228]]
[[30.6.7] [Class template shared_future] [Partial] [allocator] [#6228]]
[[30.6.8] [Function template async] [No] [async] [#4710]]
[[30.6.9] [Class template packaged_task] [Partial] [move] [#yyyy]]
[[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] [Yes] [-] [-]]
[[30.6.9] [Class template packaged_task] [Yes] [-] [-]]
]
[/
@@ -87,24 +88,160 @@
[endsect]
[section:shared Shared Locking extensions]
[section:cxx14 C++14 standard Thread library - accepted changes]
[table Howard's Shared Locking Proposal Conformace
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.html C++14 on-going standard]]
[table [@http://isocpp.org/files/papers/N3659.html N3659 Shared locking in C++ revision 2] Conformance
[[Section] [Description] [Status] [Comments]]
[[X] [Shared Locking] [Yes] [Needs `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION]]
[[X.1] [Shared Lockables Concepts] [Yes] [ - ]]
[[X.1.1] [SharedLockable concept] [Yes] [ - ]]
[[X.1.2] [UpgradeLockable concept] [Yes] [ - ]]
[[X.2] [Shared Mutex Types] [Yes] [ - ]]
[[X.2.1] [shared_mutex class] [Yes] [ - ]]
[[X.2.2] [upgrade_mutex class] [Yes] [ - ]]
[[X.3] [Locks] [Yes] [-]]
[[X.3.1] [unique_lock class adaptations] [Yes] [-]]
[[X.3.2] [shared_lock class] [Yes] [ - ]]
[[X.3.3] [upgrade_lock class] [Yes] [-]]
[[30.4.1.4] [Shared Lockables Types] [Yes] [ - ]]
[[30.4.1.4.1] [shared_mutex class] [Yes] [ - ]]
[[30.4.2.3] [Class template shared_lock] [Yes] [-]]
]
[endsect]
[section:cxx1y C++1y TS Concurrency - On going proposals]
[section:latch C++ Latches and Barriers]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3600.html N3659 C++ Latches and Barriers]]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3666.html N3659 C++ Latches and Barriers]]
[table C++ Latches and Barriers Conformance
[[Section] [Description] [Status] [Comments]]
[[X.1] [Class latch] [Partial] [ A new class latch has been added. The interface is a super set of the one of the proposal, taking some of the functions of the class barrier.]]
[[X.2] [Class barrier] [No] [ Even if Boost.Thread has a class boost:barrier it doesn't provides the same kind of services. There is an experimental completion_latch that could be used instead. ]]
]
[endsect]
[section:queue C++ Concurrent Queues]
[note [@ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3533.html N3533 C++ Concurrent Queues]]
[table C++ Concurrent Queues Conformance
[[Section] [Description] [Status] [Comments]]
[[X.1] [Conceptual interface] [Partial] [ The interface provided has some differences respect to this proposal. All the functions having a queue_op_status are not provided. No lock-free concrete classes ]]
[[X.1.1] [Basic Operations] [Partial] [ - ]]
[[X.1.1.1] [push] [yes] [ - ]]
[[X.1.1.2] [value_pop] [no] [ renamed pull with two flavors + a ptr_pull that returns a sharted_ptr<>. ]]
[[X.1.2] [Non-waiting operations] [ - ] [ - ]]
[[X.1.2.1] [try_push] [Partial] [ return bool instead ]]
[[X.1.2.2] [try_pop] [Partial] [ renamed try_pull, returns null ]]
[[X.1.3] [Non-blocking operations] [ - ] [ - ]]
[[X.1.3.1] [nonblocking_push] [Partial] [ renamed try_push(no_block, ]]
[[X.1.3.2] [nonblocking_pop] [Partial] [ renamed try_pop(no_block, ]]
[[X.1.4] [Push-front operations] [No] [ - ]]
[[X.1.5] [Closed queues] [Partial] [ - ]]
[[X.1.5.1] [close] [Yes] [ - ]]
[[X.1.5.2] [is_closed] [Yes] [ - ]]
[[X.1.5.3] [wait_push] [Partial] [ - ]]
[[X.1.5.4] [wait_pop] [Partial] [ - ]]
[[X.1.5.5] [wait_push_front] [no] [ - ]]
[[X.1.5.6] [wait_pop] [Partial] [ - ]]
[[X.1.5.6] [open] [no] [ - ]]
[[X.1.6] [Empty and Full Queues] [Yes] [ - ]]
[[X.1.6.1] [is_empty] [Yes] [ - ]]
[[X.1.6.2] [is_full] [Yes] [ Added capacity ]]
[[X.1.7] [Queue Names] [No] [ Not considere a must for the time been. ]]
[[X.1.8] [Element Type Requirements] [Yes?] [ - ]]
[[X.1.9] [Exception Handling] [Yes?] [ - ]]
[[X.1.10] [Queue Ordering] [Yes?] [ - ]]
[[X.1.11] [Lock-Free Implementations] [No] [ waiting to stabilize the lock-based interface. Will use Boost.LockFree once it is Move aware. ]]
[[X.2] [Concrete queues] [Partial] [ - ]]
[[X.2.1] [Locking Buffer Queue] [Partial] [ classes sync_queue and a sync_bounded_queue. ]]
[[X.2.1] [Lock-Free Buffer Queue] [No] [ - ]]
[[X.3] [Additional Conceptual Tools] [No] [ - ]]
[[X.3.1] [Fronts and Backs] [No] [ - ]]
[[X.3.2] [Streaming Iterators] [No] [ - ]]
[[X.3.3] [Storage Iterators] [No] [ - ]]
[[X.3.4] [Binary Interfaces] [No] [ - ]]
[[X.3.4] [Managed Indirection] [No] [ - ]]
]
[endsect]
[section:executors Asynchronous Executors]
While Boost.Thread implementation of executors would not use dynamic polymorphism, it is worth comparing with the current trend on the standard.
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3378.pdf N3378 A preliminary proposal for work executors]]
[table Asynchronous Executors
[[Section] [Description] [Status] [Comments]]
[[30.X.1] [Class executor] [No] [ - ]]
[[30.X.1.1] [add] [No] [ renamed with a function template submit ]]
[[30.X.1.1] [num_of_pendin_closures] [??] [ ]]
[[30.X.2] [Class sceduled_executor] [No] [ - ]]
[[30.X.2.1] [add_at] [No] [ renamed with a function template submit_at ]]
[[30.X.2.2] [add_after] [No] [ renamed with a function template submit_after ]]
[[30.X.3] [Executor utilities functions] [No] [ - ]]
[[30.X.3.1] [default_executor] [No] [ - ]]
[[30.X.3.2] [set_default_executor] [No] [ - ]]
[[30.X.3.3] [singleton_inline_executor] [No] [ - ]]
[[30.X.4] [Concrete executor classes] [No] [ - ]]
[[30.X.4.1] [loop_executor] [No] [ - ]]
[[30.X.4.1] [serial_executor] [No] [ - ]]
[[30.X.4.1] [thread_pool] [No] [ #8513 ]]
]
[endsect]
[section:async A Standardized Representation of Asynchronous Operations]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf N3558 A Standardized Representation of Asynchronous Operations]]
[note These functions are based on the [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3634.pdf [*N3634 - Improvements to std::future<T> and related APIs]] C++1y proposal by N. Gustafsson, A. Laksberg, H. Sutter, S. Mithani.]
[table Improvements to std::future<T> and related APIs]
[[Section] [Description] [Status] [Comments]]
[[30.6.6] [Class template future] [Partial] [ - ]]
[[30.6.6.1] [then] [Partial] [ executor interface missing #8516 ]]
[[30.6.6.2] [unwrap] [Yes] [ - ]]
[[30.6.6.3] [ready] [Partial] [ is_ready ]]
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
[[30.6.7.1] [then] [Yes] [ executor interface missing #8516 ]]
[[30.6.7.2] [unwrap] [No] [ #XXXX ]]
[[30.6.7.3] [ready] [Partial] [ is_ready ]]
[[30.6.X] [Function template when_any] [No] [ #7446 ]]
[[30.6.X] [Function template when_all] [No] [ #7447 ]]
[[30.6.X] [Function template make_ready_future] [Yes] [ - ]]
[[30.6.8] [Function template async ] [No] [ executor interface missing #7448 ]]
]
[endsect]
[section:stream_mutex C++ Stream Mutexes - C++ Stream Guards]
While Boost.Thread implementation of stream mutexes differ in the approach, it is worth comparing with the current trend on the standard.
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3535.html N3535 - C++ Stream Mutexes]. This has been replaced already by N3678 - C++ Stream Guards.]
[table C++ C++ Stream MutexesConformance
[[Section] [Description] [Status] [Comments]]
[[X.1] [Class template stream_mutex] [Partial] [ externally_locked_stream<> ]]
[[X.2.1] [constructor] [Partial] [ externally_locked_stream needs a mutex in addition as argumement. ]]
[[X.2.2] [lock] [yes] [ - ]]
[[X.2.3] [unlock] [yes] [ - ]]
[[X.2.4] [try_lock] [yes] [ - ]]
[[X.2.5] [hold] [Yes] [ - ]]
[[X.2.6] [bypass] [Yes] [ - ]]
[[X.2] [Class template stream_guard] [Yes] [ - ]]
[[X.2.1] [stream_guard] [Yes] [ - ]]
[[X.2.2] [~stream_guard] [Yes] [ - ]]
[[X.2.3] [bypass] [Yes] [ - ]]
[[X.3] [Stream Operators] [Yes] [.]]
[[X.4] [Predefined Objects] [No] [.]]
]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3678.html N3678 - C++ Stream Guards]]
[endsect]
[endsect]
[endsect]

View File

@@ -19,6 +19,7 @@
};
class condition_variable;
class condition_variable_any;
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
}
The classes `condition_variable` and `condition_variable_any` provide a
@@ -86,7 +87,7 @@ optimizations in some cases, based on the knowledge of the mutex type;
[section:condition_variable Class `condition_variable`]
#include <boost/thread/condition_variable.hpp>
//#include <boost/thread/condition_variable.hpp>
namespace boost
{
@@ -130,7 +131,7 @@ optimizations in some cases, based on the knowledge of the mutex type;
const chrono::duration<Rep, Period>& d,
Predicate pred);
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
#if defined BOOST_THREAD_USES_DATETIME
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
template<typename duration_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
@@ -345,8 +346,8 @@ the thread is unblocked (for whatever reason), the lock is reacquired by
invoking `lock.lock()` before the call to `wait` returns. The lock is also
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
[[Returns:] [`cv_status::no_timeout` if the call is returning because the time specified by
`abs_time` was reached, `cv_status::timeout` otherwise.]]
[[Returns:] [`cv_status::timeout` if the call is returning because the time specified by
`abs_time` was reached, `cv_status::no_timeout` otherwise.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
@@ -377,8 +378,8 @@ reason), the lock is reacquired by invoking `lock.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
function exits with an exception.]]
[[Returns:] [`cv_status::no_timeout ` if the call is returning because the time period specified
by `rel_time` has elapsed, `cv_status::timeout ` otherwise.]]
[[Returns:] [`cv_status::timeout ` if the call is returning because the time period specified
by `rel_time` has elapsed, `cv_status::no_timeout ` otherwise.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
@@ -418,14 +419,7 @@ return true;
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
if(!wait_for(lock,rel_time))
{
return pred();
}
}
return true;
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
``]]
]
@@ -439,7 +433,7 @@ return true;
[section:condition_variable_any Class `condition_variable_any`]
#include <boost/thread/condition_variable.hpp>
//#include <boost/thread/condition_variable.hpp>
namespace boost
{
@@ -481,7 +475,7 @@ return true;
const chrono::duration<Rep, Period>& d,
Predicate pred);
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
#if defined BOOST_THREAD_USES_DATETIME
template<typename lock_type>
bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
template<typename lock_type,typename duration_type>
@@ -730,19 +724,12 @@ return true;
[endsect]
[section:wait_for_predicate `template <class lock_type, class Rep, class Period, class Predicate> bool wait_until(lock_type& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
[section:wait_for_predicate `template <class lock_type, class Rep, class Period, class Predicate> bool wait_for(lock_type& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
if(!__cvany_wait_for(lock,rel_time))
{
return pred();
}
}
return true;
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
``]]
]
@@ -751,14 +738,53 @@ return true;
[endsect]
[section:condition Typedef `condition`]
[section:condition Typedef `condition` DEPRECATED V3]
#include <boost/thread/condition.hpp>
// #include <boost/thread/condition.hpp>
namespace boost
{
typedef condition_variable_any condition;
}
The typedef `condition` is provided for backwards compatibility with previous boost releases.
[endsect]
[section:notify_all_at_thread_exit Non-member Function `notify_all_at_thread_exit`()]
// #include <boost/thread/condition_variable.hpp>
namespace boost
{
void notify_all_at_thread_exit(condition_variable& cond, unique_lock<mutex> lk);
}
[variablelist
[[Requires:] [`lk` is locked by the calling thread and either no other thread is waiting on `cond`, or `lk.mutex()` returns the same value for each of the lock arguments supplied by all concurrently waiting (via `wait`, `wait_for`, or `wait_until`) threads.]]
[[Effects:] [transfers ownership of the lock associated with `lk` into internal storage and schedules `cond` to be notified when the current thread exits, after all objects of thread storage duration associated with the current thread have been destroyed. This notification shall be as if
``
lk.unlock();
cond.notify_all();
``
]]
]
[/
[[Synchronization:] [The call to notify_all_at_thread_exit and the completion of the destructors for all the current threadÕs variables of thread storage duration synchronize with (1.10) calls to functions waiting on cond.
]]
[[Note:] [The supplied lock will be held until the thread exits, and care must be taken to ensure that this does not cause deadlock due to lock ordering issues. After calling notify_all_at_thread_exit it is recommended that the thread should be exited as soon as possible, and that no blocking or time-consuming tasks are run on that thread.
]]
[[Note:] [It is the userÕs responsibility to ensure that waiting threads do not erroneously assume that the thread has finished if they experience spurious wakeups. This typically requires that the condition being waited for is satisfied while holding the lock on lk, and that this lock is not released and reacquired prior to calling notify_all_at_thread_exit.
]]
]
[endsect]
[endsect]

View File

@@ -8,47 +8,180 @@
[section:configuration Configuration]
[section:system Boost.System]
Boost.Thread uses by default Boost.System to define the exceptions. For backward compatibility and also for compilers that don't work well with Boost.System the user can define `BOOST_THREAD_DONT_USE_SYSTEM `.
[table Default Values for Configurable Features
[[Feature] [Anti-Feature] [V2] [V3] [V4] ]
[[USES_CHRONO] [DONT_USE_CHRONO] [YES/NO] [YES/NO] [YES/NO] ]
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ]
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ]
`BOOST_THREAD_USES_SYSTEM` is defined when Boost.Thread uses Boost.Move.
[endsect]
[[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/NO] [YES/NO] [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`. If `BOOST_THREAD_DONT_USE_SYSTEM` is defined then `BOOST_THREAD_DONT_USE_CHRONO` is defined implicitly.
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.
`BOOST_THREAD_USES_CHRONO` is defined when Boost.Thread uses Boost.Chrono.
[warning When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_CHRONO is defined independently of user settings.]
[endsect]
[section:move Boost.Move]
Boost.Thread uses by default an internal move semantic implementation. Since version 3.0.0 you can use the move emulation emulation provided by Boost.Move.
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_USES_MOVE ` if you want to use Boost.Move interface.
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_USE_MOVE ` if you want to use boost::unique_future.
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<=3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `BOOST_THREAD_DONT_USE_DATETIME` if you don't want to use Boost.DateTime related interfaces.
When `BOOST_THREAD_VERSION>3` && defined BOOST_THREAD_PLATFORM_PTHREAD define `BOOST_THREAD_USES_DATETIME` if you want to use Boost.DateTime related interfaces.
[warning When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_DATETIME is defined independently of user settings.]
[endsect]
[section:move Boost.Atomic]
Boost.Thread uses by default an Boost.Atomic in POSIX platforms to implement call_once..
Define `BOOST_THREAD_USES_ATOMIC ` if you want to use Boost.Atomic.
Define `BOOST_THREAD_DONT_USE_ATOMIC ` if you don't want to use Boost.Atomic or if it is not supported in your platform.
[endsect]
[section:thread_eq `boost::thread::operator==` deprecated]
The following operators are deprecated:
* `boost::thread::operator==`
* `boost::thread::operator!=`
When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature.
Use instead
* `boost::thread::id::operator==`
* `boost::thread::id::operator!=`
[warning This is a breaking change respect to version 1.x.]
When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_PROVIDES_THREAD_EQ ` if you want this feature.
When `BOOST_THREAD_VERSION<4` 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::mutex>`,
* `boost::unique_lock<boost::mutex>` with the `try_to_lock_t` constructor,
* `boost::unique_lock<boost::timed_mutex>`
* `boost::unique_lock<boost::timed_mutex>` with the `try_to_lock_t` constructor
* `boost::unique_lock<boost::timed_mutex>`
* `boost::unique_lock<boost::recursive_mutex>`,
* `boost::unique_lock<boost::recursive_mutex>` with the `try_to_lock_t` constructor,
* `boost::unique_lock<boost::recursive_timed_mutex>`
* `boost::unique_lock<boost::recursive_timed_mutex>` with the `try_to_lock_t` constructor
* `boost::unique_lock<boost::recursive_timed_mutex>`
[warning This is a breaking change respect to version 1.x.]
When `BOOST_THREAD_VERSION>=4` define `BOOST_THREAD_PROVIDES_NESTED_LOCKS` if you want these features.
When `BOOST_THREAD_VERSION<4` 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`.
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]
[section:shared_upwards Shared Locking Upwards Conversion]
Boost.Threads includes in version 2 the Shared Locking Upwards Conversion as defined in [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking].
Boost.Threads includes in version 3 the Shared Locking Upwards Conversion as defined in [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking].
These conversions need to be used carefully to avoid deadlock or livelock. The user need to define explicitly `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION` to get these upwards conversions.
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION ` if you want these features.
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features.
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION ` if you don't want these features.
[endsect]
@@ -68,7 +201,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]
@@ -79,7 +212,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]
@@ -123,7 +256,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]
@@ -132,10 +265,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]
@@ -150,41 +283,90 @@ 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<4` 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<4` 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 1. In this case the following breaking or extending macros are defined if the opposite is not requested:
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 2 by defining `BOOST_THREAD_VERSION` to 2. In this case the following breaking or extending macros are defined if the opposite is not requested:
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.54.]
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.58.]
[endsect]
@@ -199,17 +381,31 @@ Some compilers don't work correctly with some of the added features.
If __SUNPRO_CC < 0x5100 the library defines
* `BOOST_THREAD_DONT_USE_MOVE`
If __SUNPRO_CC < 0x5100 the library defines
* `BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS`
[endsect]
[section:vacpp VACPP]
If __IBMCPP__ is defined 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]

View File

@@ -340,7 +340,7 @@ Instead of
use
switch (BOOST_SCOPED_ENUM_NATIVE(future_errc)(ev))
switch (boost::native_value(ev))
{
case future_errc::broken_promise:

592
doc/external_locking.qbk Normal file
View File

@@ -0,0 +1,592 @@
[/
/ Copyright (c) 2008,2012 Vicente J. Botet Escriba
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section External Locking -- `strict_lock` and `externally_locked` classes]
[note This tutorial is an adaptation of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System"
to the Boost library.]
[/
[section Internal locking]
Consider, for example, modeling a bank account class that supports simultaneous deposits and withdrawals from multiple locations (arguably the "Hello, World" of multi-threaded programming). In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
class BankAccount {
boost::mutex mtx_; // explicit mutex declaration
int balance_;
public:
void Deposit(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ += amount;
}
void Withdraw(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ -= amount;
}
int GetBalance() {
boost::lock_guard<boost::mutex> guard(mtx_);
return balance_;
}
};
The object-level locking idiom doesn't cover the entire richness of a threading model. For example, the model above is quite deadlock-prone when you try to coordinate multi-object transactions. Nonetheless, object-level locking is useful in many cases, and in combination with other mechanisms can provide a satisfactory solution to many threaded access problems in object-oriented programs.
[endsect]
[section Internal and external locking]
The BankAccount class above uses internal locking. Basically, a class that uses internal locking guarantees that any concurrent calls to its public member functions don't corrupt an instance of that class. This is typically ensured by having each public member function acquire a lock on the object upon entry. This way, for any given object of that class, there can be only one member function call active at any moment, so the operations are nicely serialized.
This approach is reasonably easy to implement and has an attractive simplicity. Unfortunately, "simple" might sometimes morph into "simplistic."
Internal locking is insufficient for many real-world synchronization tasks. Imagine that you want to implement an ATM withdrawal transaction with the BankAccount class. The requirements are simple. The ATM transaction consists of two withdrawals-one for the actual money and one for the $2 commission. The two withdrawals must appear in strict sequence; that is, no other transaction can exist between them.
The obvious implementation is erratic:
void ATMWithdrawal(BankAccount& acct, int sum) {
acct.Withdraw(sum);
// preemption possible
acct.Withdraw(2);
}
The problem is that between the two calls above, another thread can perform another operation on the account, thus breaking the second design requirement.
In an attempt to solve this problem, let's lock the account from the outside during the two operations:
void ATMWithdrawal(BankAccount& acct, int sum) {
boost::lock_guard<boost::mutex> guard(acct.mtx_); // mtx_ field is private
acct.Withdraw(sum);
acct.Withdraw(2);
}
Notice that the code above doesn't compiles, the `mtx_` field is private.
We have two possibilities:
* make `mtx_` public which seams odd
* make the `BankAccount` lockable by adding the lock/unlock functions
We can add these functions explicitly
class BankAccount {
boost::mutex mtx_;
int balance_;
public:
void Deposit(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ += amount;
}
void Withdraw(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ -= amount;
}
void lock() {
mtx_.lock();
}
void unlock() {
mtx_.unlock();
}
};
or inheriting from a class which add these lockable functions.
The `basic_lockable_adapter` class helps to define the `BankAccount` class as
class BankAccount
: public basic_lockable_adapter<thread_mutex>
{
int balance_;
public:
void Deposit(int amount) {
boost::lock_guard<BankAccount> guard(*this);
// boost::lock_guard<boost::mutex> guard(*this->mutex());
balance_ += amount;
}
void Withdraw(int amount) {
boost::lock_guard<BankAccount> guard(*this);
// boost::lock_guard<boost::mutex> guard(*this->mutex());
balance_ -= amount;
}
int GetBalance() {
boost::lock_guard<BankAccount> guard(*this);
// boost::lock_guard<boost::mutex> guard(*this->mutex());
return balance_;
}
};
and the code that does not compiles becomes
void ATMWithdrawal(BankAccount& acct, int sum) {
// boost::lock_guard<boost::mutex> guard(*acct.mutex());
boost::lock_guard<BankAccount> guard(acct);
acct.Withdraw(sum);
acct.Withdraw(2);
}
Notice that now acct is being locked by Withdraw after it has already been locked by guard. When running such code, one of two things happens.
* Your mutex implementation might support the so-called recursive mutex semantics. This means that the same thread can lock the same mutex several times successfully. In this case, the implementation works but has a performance overhead due to unnecessary locking. (The locking/unlocking sequence in the two Withdraw calls is not needed but performed anyway-and that costs time.)
* Your mutex implementation might not support recursive locking, which means that as soon as you try to acquire it the second time, it blocks-so the ATMWithdrawal function enters the dreaded deadlock.
As `boost::mutex` is not recursive, we need to use its recursive version `boost::recursive_mutex`.
class BankAccount
: public basic_lockable_adapter<recursive_mutex>
{
// ...
};
The caller-ensured locking approach is more flexible and the most efficient, but very dangerous. In an implementation using caller-ensured locking, BankAccount still holds a mutex, but its member functions don't manipulate it at all. Deposit and Withdraw are not thread-safe anymore. Instead, the client code is responsible for locking BankAccount properly.
class BankAccount
: public basic_lockable_adapter<boost:mutex> {
int balance_;
public:
void Deposit(int amount) {
balance_ += amount;
}
void Withdraw(int amount) {
balance_ -= amount;
}
};
Obviously, the caller-ensured locking approach has a safety problem. BankAccount's implementation code is finite, and easy to reach and maintain, but there's an unbounded amount of client code that manipulates BankAccount objects. In designing applications, it's important to differentiate between requirements imposed on bounded code and unbounded code. If your class makes undue requirements on unbounded code, that's usually a sign that encapsulation is out the window.
To conclude, if in designing a multi-threaded class you settle on internal locking, you expose yourself to inefficiency or deadlocks. On the other hand, if you rely on caller-provided locking, you make your class error-prone and difficult to use. Finally, external locking completely avoids the issue by leaving it all to the client code.
[endsect]
]
[section Locks as Permits]
So what to do? Ideally, the BankAccount class should do the following:
* Support both locking models (internal and external).
* Be efficient; that is, use no unnecessary locking.
* Be safe; that is, BankAccount objects cannot be manipulated without appropriate locking.
Let's make a worthwhile observation: Whenever you lock a BankAccount, you do so by using a `lock_guard<BankAccount>` object. Turning this statement around, wherever there's a `lock_guard<BankAccount>`, there's also a locked `BankAccount` somewhere. Thus, you can think of-and use-a `lock_guard<BankAccount>` object as a permit. Owning a `lock_guard<BankAccount>` gives you rights to do certain things. The `lock_guard<BankAccount>` object should not be copied or aliased (it's not a transmissible permit).
# As long as a permit is still alive, the `BankAccount` object stays locked.
# When the `lock_guard<BankAccount>` is destroyed, the `BankAccount`'s mutex is released.
The net effect is that at any point in your code, having access to a `lock_guard<BankAccount>` object guarantees that a `BankAccount` is locked. (You don't know exactly which `BankAccount` is locked, however-an issue that we'll address soon.)
For now, let's make a couple of enhancements to the `lock_guard` class template defined in Boost.Thread.
We'll call the enhanced version `strict_lock`. Essentially, a `strict_lock`'s role is only to live on the stack as an automatic variable.
`strict_lock` must adhere to a non-copy and non-alias policy.
`strict_lock` disables copying by making the copy constructor and the assignment operator private.
While we're at it, let's disable operator new and operator delete.
[/
`strict_lock` are not intended to be allocated on the heap.
`strict_lock` avoids aliasing by using a slightly less orthodox and less well-known technique: disable address taking.
]
template <typename Lockable>
class strict_lock {
public:
typedef Lockable lockable_type;
explicit strict_lock(lockable_type& obj) : obj_(obj) {
obj.lock(); // locks on construction
}
strict_lock() = delete;
strict_lock(strict_lock const&) = delete;
strict_lock& operator=(strict_lock const&) = delete;
~strict_lock() { obj_.unlock(); } // unlocks on destruction
bool owns_lock(mutex_type const* l) const noexcept // strict lockers specific function
{
return l == &obj_;
}
private:
lockable_type& obj_;
};
Silence can be sometimes louder than words-what's forbidden to do with a `strict_lock` is as important as what you can do. Let's see what you can and what you cannot do with a `strict_lock` instantiation:
* You can create a `strict_lock<T>` only starting from a valid T object. Notice that there is no other way you can create a `strict_lock<T>`.
BankAccount myAccount("John Doe", "123-45-6789");
strict_lock<BankAccount> myLock(myAccount); // ok
* You cannot copy `strict_lock`s to one another. In particular, you cannot pass `strict_lock`s by value to functions or have them returned by functions:
extern strict_lock<BankAccount> Foo(); // compile-time error
extern void Bar(strict_lock<BankAccount>); // compile-time error
* However, you still can pass `strict_lock`s by reference to and from functions:
// ok, Foo returns a reference to strict_lock<BankAccount>
extern strict_lock<BankAccount>& Foo();
// ok, Bar takes a reference to strict_lock<BankAccount>
extern void Bar(strict_lock<BankAccount>&);
[/
* You cannot allocate a `strict_lock` on the heap. However, you still can put `strict_lock`s on the heap if they're members of a class.
strict_lock<BankAccount>* pL =
new strict_lock<BankAccount>(myAcount); //error!
// operator new is not accessible
class Wrapper {
strict_lock memberLock_;
...
};
Wrapper* pW = new Wrapper; // ok
(Making `strict_lock` a member variable of a class is not recommended. Fortunately, disabling copying and default construction makes `strict_lock` quite an unfriendly member variable.)
* You cannot take the address of a `strict_lock` object. This interesting feature, implemented by disabling unary operator&, makes it very unlikely to alias a `strict_lock` object. Aliasing is still possible by taking references to a `strict_lock`:
strict_lock<BankAccount> myLock(myAccount); // ok
strict_lock<BankAccount>* pAlias = &myLock; // error!
// strict_lock<BankAccount>::operator& is not accessible
strict_lock<BankAccount>& rAlias = myLock; // ok
Fortunately, references don't engender as bad aliasing as pointers because they're much less versatile (references cannot be copied or reseated).
]
[/* You can even make `strict_lock` final; that is, impossible to derive from. This task is left in the form of an exercise to the reader.
]
All these rules were put in place with one purpose-enforcing that owning a `strict_lock<T>` is a reasonably strong guarantee that
# you locked a T object, and
# that object will be unlocked at a later point.
Now that we have such a strict `strict_lock`, how do we harness its power in defining a safe, flexible interface for BankAccount? The idea is as follows:
* Each of BankAccount's interface functions (in our case, Deposit and Withdraw) comes in two overloaded variants.
* One version keeps the same signature as before, and the other takes an additional argument of type `strict_lock<BankAccount>`. The first version is internally locked; the second one requires external locking. External locking is enforced at compile time by requiring client code to create a `strict_lock<BankAccount>` object.
* BankAccount avoids code bloating by having the internal locked functions forward to the external locked functions, which do the actual job.
A little code is worth 1,000 words, a (hacked into) saying goes, so here's the new BankAccount class:
class BankAccount
: public basic_lockable_adapter<boost:recursive_mutex>
{
int balance_;
public:
void Deposit(int amount, strict_lock<BankAccount>&) {
// Externally locked
balance_ += amount;
}
void Deposit(int amount) {
strict_lock<boost:mutex> guard(*this); // Internally locked
Deposit(amount, guard);
}
void Withdraw(int amount, strict_lock<BankAccount>&) {
// Externally locked
balance_ -= amount;
}
void Withdraw(int amount) {
strict_lock<boost:mutex> guard(*this); // Internally locked
Withdraw(amount, guard);
}
};
Now, if you want the benefit of internal locking, you simply call Deposit(int) and Withdraw(int). If you want to use external locking, you lock the object by constructing a `strict_lock<BankAccount>` and then you call `Deposit(int, strict_lock<BankAccount>&)` and `Withdraw(int, strict_lock<BankAccount>&)`. For example, here's the `ATMWithdrawal` function implemented correctly:
void ATMWithdrawal(BankAccount& acct, int sum) {
strict_lock<BankAccount> guard(acct);
acct.Withdraw(sum, guard);
acct.Withdraw(2, guard);
}
This function has the best of both worlds-it's reasonably safe and efficient at the same time.
It's worth noting that `strict_lock` being a template gives extra safety compared to a straight polymorphic approach. In such a design, BankAccount would derive from a Lockable interface. `strict_lock` would manipulate Lockable references so there's no need for templates. This approach is sound; however, it provides fewer compile-time guarantees. Having a `strict_lock` object would only tell that some object derived from Lockable is currently locked. In the templated approach, having a `strict_lock<BankAccount>` gives a stronger guarantee-it's a `BankAccount` that stays locked.
There's a weasel word in there-I mentioned that ATMWithdrawal is reasonably safe. It's not really safe because there's no enforcement that the `strict_lock<BankAccount>` object locks the appropriate BankAccount object. The type system only ensures that some BankAccount object is locked. For example, consider the following phony implementation of ATMWithdrawal:
void ATMWithdrawal(BankAccount& acct, int sum) {
BankAccount fakeAcct("John Doe", "123-45-6789");
strict_lock<BankAccount> guard(fakeAcct);
acct.Withdraw(sum, guard);
acct.Withdraw(2, guard);
}
This code compiles warning-free but obviously doesn't do the right thing-it locks one account and uses another.
It's important to understand what can be enforced within the realm of the C++ type system and what needs to be enforced at runtime. The mechanism we've put in place so far ensures that some BankAccount object is locked during the call to `BankAccount::Withdraw(int, strict_lock<BankAccount>&)`. We must enforce at runtime exactly what object is locked.
If our scheme still needs runtime checks, how is it useful? An unwary or malicious programmer can easily lock the wrong object and manipulate any BankAccount without actually locking it.
First, let's get the malice issue out of the way. C is a language that requires a lot of attention and discipline from the programmer. C++ made some progress by asking a little less of those, while still fundamentally trusting the programmer. These languages are not concerned with malice (as Java is, for example). After all, you can break any C/C++ design simply by using casts "appropriately" (if appropriately is an, er, appropriate word in this context).
The scheme is useful because the likelihood of a programmer forgetting about any locking whatsoever is much greater than the likelihood of a programmer who does remember about locking, but locks the wrong object.
Using `strict_lock` permits compile-time checking of the most common source of errors, and runtime checking of the less frequent problem.
Let's see how to enforce that the appropriate BankAccount object is locked. First, we need to add a member function to the `strict_lock` class template.
The `bool strict_lock<T>::owns_lock(Loclable*)` function returns a reference to the locked object.
template <class Lockable> class strict_lock {
... as before ...
public:
bool owns_lock(Lockable* mtx) const { return mtx==&obj_; }
};
Second, BankAccount needs to use this function compare the locked object against this:
class BankAccount {
: public basic_lockable_adapter<boost::recursive_mutex>
int balance_;
public:
void Deposit(int amount, strict_lock<BankAccount>& guard) {
// Externally locked
if (!guard.owns_lock(*this))
throw "Locking Error: Wrong Object Locked";
balance_ += amount;
}
// ...
};
The overhead incurred by the test above is much lower than locking a recursive mutex for the second time.
[endsect]
[section Improving External Locking]
Now let's assume that BankAccount doesn't use its own locking at all, and has only a thread-neutral implementation:
class BankAccount {
int balance_;
public:
void Deposit(int amount) {
balance_ += amount;
}
void Withdraw(int amount) {
balance_ -= amount;
}
};
Now you can use BankAccount in single-threaded and multi-threaded applications alike, but you need to provide your own synchronization in the latter case.
Say we have an AccountManager class that holds and manipulates a BankAccount object:
class AccountManager
: public basic_lockable_adapter<boost::mutex>
{
BankAccount checkingAcct_;
BankAccount savingsAcct_;
...
};
Let's also assume that, by design, AccountManager must stay locked while accessing its BankAccount members. The question is, how can we express this design constraint using the C++ type system? How can we state "You have access to this BankAccount object only after locking its parent AccountManager object"?
The solution is to use a little bridge template `externally_locked` that controls access to a BankAccount.
template <typename T, typename Lockable>
class externally_locked {
BOOST_CONCEPT_ASSERT((LockableConcept<Lockable>));
public:
externally_locked(T& obj, Lockable& lockable)
: obj_(obj)
, lockable_(lockable)
{}
externally_locked(Lockable& lockable)
: obj_()
, lockable_(lockable)
{}
T& get(strict_lock<Lockable>& lock) {
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
if (!lock.owns_lock(&lockable_)) throw lock_error(); run time check throw if not locks the same
#endif
return obj_;
}
void set(const T& obj, Lockable& lockable) {
obj_ = obj;
lockable_=lockable;
}
private:
T obj_;
Lockable& lockable_;
};
`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<Owner>` object.
Instead of making `checkingAcct_` and `savingsAcct_` of type `BankAccount`, `AccountManager` holds objects of type `externally_locked<BankAccount, AccountManager>`:
class AccountManager
: public basic_lockable_adapter<thread_mutex>
{
public:
typedef basic_lockable_adapter<thread_mutex> lockable_base_type;
AccountManager()
: checkingAcct_(*this)
, savingsAcct_(*this)
{}
inline void Checking2Savings(int amount);
inline void AMoreComplicatedChecking2Savings(int amount);
private:
externally_locked<BankAccount, AccountManager> checkingAcct_;
externally_locked<BankAccount, AccountManager> savingsAcct_;
};
The pattern is the same as before - to access the BankAccount object cloaked by `checkingAcct_`, you need to call `get`. To call `get`, you need to pass it a `strict_lock<AccountManager>`. The one thing you have to take care of is to not hold pointers or references you obtained by calling `get`. If you do that, make sure that you don't use them after the strict_lock has been destroyed. That is, if you alias the cloaked objects, you're back from "the compiler takes care of that" mode to "you must pay attention" mode.
Typically, you use `externally_locked` as shown below. Suppose you want to execute an atomic transfer from your checking account to your savings account:
void AccountManager::Checking2Savings(int amount) {
strict_lock<AccountManager> guard(*this);
checkingAcct_.get(guard).Withdraw(amount);
savingsAcct_.get(guard).Deposit(amount);
}
We achieved two important goals. First, the declaration of `checkingAcct_` and `savingsAcct_` makes it clear to the code reader that that variable is protected by a lock on an AccountManager. Second, the design makes it impossible to manipulate the two accounts without actually locking a BankAccount. `externally_locked` is what could be called active documentation.
[endsect]
[section Allowing other strict locks]
Now imagine that the AccountManager function needs to take a `unique_lock` in order to reduce the critical regions. And at some time it needs to access to the `checkingAcct_`. As `unique_lock` is not a strict lock the following code doesn't compiles:
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
unique_lock<AccountManager> guard(*this, defer_lock);
if (some_condition()) {
guard.lock();
}
checkingAcct_.get(guard).Withdraw(amount); // COMPILE ERROR
savingsAcct_.get(guard).Deposit(amount); // COMPILE ERROR
do_something_else();
}
We need a way to transfer the ownership from the `unique_lock` to a `strict_lock` the time we are working with `savingsAcct_` and then restore the ownership on `unique_lock`.
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
unique_lock<AccountManager> guard1(*this, defer_lock);
if (some_condition()) {
guard1.lock();
}
{
strict_lock<AccountManager> guard(guard1);
checkingAcct_.get(guard).Withdraw(amount);
savingsAcct_.get(guard).Deposit(amount);
}
guard1.unlock();
}
In order to make this code compilable we need to store either a Lockable or a `unique_lock<Lockable>` reference depending on the constructor. Store which kind of reference we have stored,and in the destructor call either to the Lockable `unlock` or restore the ownership.
This seams too complicated to me. Another possibility is to define a nested strict lock class. The drawback is that instead of having only one strict lock we have two and we need either to duplicate every function taking a `strict_lock` or make these function templates functions. The problem with template functions is that we don't profit anymore of the C++ type system. We must add some static metafunction that check that the Locker parameter is a strict lock. The problem is that we can not really check this or can we?. The `is_strict_lock` metafunction must be specialized by the strict lock developer. We need to belive it "sur parole". The advantage is that now we can manage with more than two strict locks without changing our code. This is really nice.
Now we need to state that both classes are `strict_lock`s.
template <typename Locker>
struct is_strict_lock : mpl::false_ {};
template <typename Lockable>
struct is_strict_lock<strict_lock<Lockable> > : mpl::true_ {}
template <typename Locker>
struct is_strict_lock<nested_strict_lock<Locker> > : mpl::true_ {}
Well let me show how this `nested_strict_lock` class looks like and the impacts on the `externally_locked` class and the `AccountManager::AMoreComplicatedFunction` function.
First `nested_strict_lock` class will store on a temporary lock the `Locker`, and transfer the lock ownership on the constructor. On destruction he will restore the ownership. Note also that the Locker needs to have already a reference to the mutex otherwise an exception is thrown and the use of the `lock_traits`.
template <typename Locker >
class nested_strict_lock
{
BOOST_CONCEPT_ASSERT((MovableLockerConcept<Locker>));
public:
typedef typename lockable_type<Locker>::type lockable_type;
typedef typename syntactic_lock_traits<lockable_type>::lock_error lock_error;
nested_strict_lock(Locker& lock)
: lock_(lock) // Store reference to locker
, tmp_lock_(lock.move()) // Move ownership to temporaty locker
{
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
if (tmp_lock_.mutex()==0) {
lock_=tmp_lock_.move(); // Rollback for coherency purposes
throw lock_error();
}
#endif
if (!tmp_lock_) tmp_lock_.lock(); // ensures it is locked
}
~nested_strict_lock() {
lock_=tmp_lock_.move(); // Move ownership to nesting locker
}
bool owns_lock() const { return true; }
lockable_type* mutex() const { return tmp_lock_.mutex(); }
bool owns_lock(lockable_type* l) const { return l==mutex(); }
private:
Locker& lock_;
Locker tmp_lock_;
};
[/
typedef bool (nested_strict_lock::*bool_type)() const;
operator bool_type() const { return &nested_strict_lock::owns_lock; }
bool operator!() const { return false; }
BOOST_ADRESS_OF_DELETE(nested_strict_lock)
BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
BOOST_DEFAULT_CONSTRUCTOR_DELETE(nested_strict_lock)
BOOST_COPY_CONSTRUCTOR_DELETE(nested_strict_lock)
BOOST_COPY_ASSIGNEMENT_DELETE(nested_strict_lock)
]
The `externally_locked` get function is now a template function taking a Locker as parameters instead of a `strict_lock`.
We can add test in debug mode that ensure that the Lockable object is locked.
template <typename T, typename Lockable>
class externally_locked {
public:
// ...
template <class Locker>
T& get(Locker& lock) {
BOOST_CONCEPT_ASSERT((StrictLockerConcept<Locker>));
BOOST_STATIC_ASSERT((is_strict_lock<Locker>::value)); // locker is a strict locker "sur parole"
BOOST_STATIC_ASSERT((is_same<Lockable,
typename lockable_type<Locker>::type>::value)); // that locks the same type
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP // define BOOST_THREAD_EXTERNALLY_LOCKED_NO_CHECK_OWNERSHIP if you don't want to check locker ownership
if (! lock ) throw lock_error(); // run time check throw if no locked
#endif
#ifdef BOOST_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
if (!lock.owns_lock(&lockable_)) throw lock_error();
#endif
return obj_;
}
};
The `AccountManager::AMoreComplicatedFunction` function needs only to replace the `strict_lock` by a `nested_strict_lock`.
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
unique_lock<AccountManager> guard1(*this);
if (some_condition()) {
guard1.lock();
}
{
nested_strict_lock<unique_lock<AccountManager> > guard(guard1);
checkingAcct_.get(guard).Withdraw(amount);
savingsAcct_.get(guard).Deposit(amount);
}
guard1.unlock();
}
[endsect]
[endsect]

File diff suppressed because it is too large Load Diff

View File

@@ -23,25 +23,26 @@
[template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]]
[def __unique_future__ [unique_future_link `boost::unique_future`]]
[def __unique_future__ [unique_future_link `future`]]
[def __unique_future `future`]
[template unique_future_get_link[link_text] [link thread.synchronization.futures.reference.unique_future.get [link_text]]]
[def __unique_future_get__ [unique_future_get_link `boost::unique_future<R>::get()`]]
[def __unique_future_get__ [unique_future_get_link `boost::future<R>::get()`]]
[template unique_future_wait_link[link_text] [link thread.synchronization.futures.reference.unique_future.wait [link_text]]]
[def __unique_future_wait__ [unique_future_wait_link `boost::unique_future<R>::wait()`]]
[def __unique_future_wait__ [unique_future_wait_link `boost::future<R>::wait()`]]
[template unique_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.unique_future.is_ready [link_text]]]
[def __unique_future_is_ready__ [unique_future_is_ready_link `boost::unique_future<R>::is_ready()`]]
[def __unique_future_is_ready__ [unique_future_is_ready_link `boost::future<R>::is_ready()`]]
[template unique_future_has_value_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_value [link_text]]]
[def __unique_future_has_value__ [unique_future_has_value_link `boost::unique_future<R>::has_value()`]]
[def __unique_future_has_value__ [unique_future_has_value_link `boost::future<R>::has_value()`]]
[template unique_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.unique_future.has_exception [link_text]]]
[def __unique_future_has_exception__ [unique_future_has_exception_link `boost::unique_future<R>::has_exception()`]]
[def __unique_future_has_exception__ [unique_future_has_exception_link `boost::future<R>::has_exception()`]]
[template unique_future_get_state_link[link_text] [link thread.synchronization.futures.reference.unique_future.get_state [link_text]]]
[def __unique_future_get_state__ [unique_future_get_state_link `boost::unique_future<R>::get_state()`]]
[def __unique_future_get_state__ [unique_future_get_state_link `boost::future<R>::get_state()`]]
[template shared_future_link[link_text] [link thread.synchronization.futures.reference.shared_future [link_text]]]
[def __shared_future__ [shared_future_link `boost::shared_future`]]
@@ -69,6 +70,7 @@
[template packaged_task_link[link_text] [link thread.synchronization.futures.reference.packaged_task [link_text]]]
[def __packaged_task__ [packaged_task_link `boost::packaged_task`]]
[def __packaged_task [packaged_task_link `boost::packaged_task`]]
[template wait_for_any_link[link_text] [link thread.synchronization.futures.reference.wait_for_any [link_text]]]
[def __wait_for_any__ [wait_for_any_link `boost::wait_for_any()`]]
@@ -91,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]
@@ -114,7 +119,7 @@ place of the return value.
}
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::unique_future<int> fi=pt.get_future();
boost::__unique_future__<int> fi=pt.get_future();
boost::thread task(boost::move(pt)); // launch task on a thread
@@ -132,7 +137,7 @@ future. A promise can therefore be used where the value may come from more than
produce multiple values.
boost::promise<int> pi;
boost::unique_future<int> fi;
boost::__unique_future__<int> fi;
fi=pi.get_future();
pi.set_value(42);
@@ -174,7 +179,7 @@ call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task t
{
boost::packaged_task<int> task(calculate_the_answer_to_life_the_universe_and_everything);
task.set_wait_callback(invoke_lazy_task);
boost::unique_future<int> f(task.get_future());
boost::__unique_future__<int> f(task.get_future());
assert(f.get()==42);
}
@@ -182,6 +187,277 @@ 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<int>&& p)
{
p.set_value_at_thread_exit(find_the_answer());
}
int main()
{
boost::promise<int> p;
boost::thread t(thread_func,boost::move(p));
t.detach(); // we're going to wait on the future
std::cout<<p.get_future().get()<<std::endl;
}
When the call to `get()` returns, we know that not only is the future value ready, but the thread specific variables
on the other thread have also been destroyed.
Such mechanisms are provided for `boost::condition_variable`, `boost::promise` and `boost::packaged_task`. e.g.
void task_executor(boost::packaged_task<void(int)> 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<std::mutex> 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<std::mutex> 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 is undefined.
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<type> 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_ready_future Making immediate futures easier]
Some functions may know the value at the point of construction. In these cases the value is immediately available,
but needs to be returned as a future or shared_future. By using make_ready_future a future
can be created which holds a pre-computed result in its shared state.
Without these features it is non-trivial to create a future directly from a value.
First a promise must be created, then the promise is set, and lastly the future is retrieved from the promise.
This can now be done with one operation.
[heading make_ready_future]
This function creates a future for a given value. If no value is given then a future<void> is returned.
This function is primarily useful in cases where sometimes, the return value is immediately available, but sometimes
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<int> compute(int x)
{
if (x == 0) return boost::make_ready_future(0);
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error"));
boost::future<int> f1 = boost::async([]() { return x+1; });
return f1;
}
There are two variations of this function. The first takes a value of any type, and returns a future of that type.
The input value is passed to the shared state of the returned future. The second version takes no input and returns a future<void>.
[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<int>` `f2` is registered to be a continuation of `future<int>` `f1` using the `.then()` member
function. This operation takes a lambda function which describes how `f2` should proceed after `f1` is ready.
#include <boost/thread/future.hpp>
using namespace boost;
int main()
{
future<int> f1 = async([]() { return 123; });
future<string> f2 = f1.then([](future<int> 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 function: One option which can be considered is to take two functions, one for
success and one for error handling. However this option has not been retained for the moment.
The lambda function takes a future as its input which carries the exception
through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
* Scheduler: Providing an overload to `.then`, to take a scheduler reference places great flexibility over the execution
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]

469
doc/internal_locking.qbk Normal file
View File

@@ -0,0 +1,469 @@
[/
/ Copyright (c) 2008 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 Internal Locking]
[note This tutorial is an adaptation of chapter Concurrency of the Object-Oriented Programming in the BETA Programming Language and of the paper of Andrei Alexandrescu "Multithreading and the C++ Type System" to the Boost library.]
[section Concurrent threads of execution]
Consider, for example, modeling a bank account class that supports simultaneous deposits and withdrawals from multiple locations (arguably the "Hello, World" of multithreaded programming).
From here a component is a model of the `Callable` concept.
On C++11 (Boost) concurrent execution of a component is obtained by means of the `std::thread`(`boost::thread`):
boost::thread thread1(S);
where `S` is a model of `Callable`. The meaning of this expression is that execution of `S()` will take place concurrently with the current thread of execution executing the expression.
The following example includes a bank account of a person (Joe) and two components, one corresponding to a bank agent depositing money in Joe's account, and one representing Joe. Joe will only be withdrawing money from the account:
class BankAccount;
BankAccount JoesAccount;
void bankAgent()
{
for (int i =10; i>0; --i) {
//...
JoesAccount.Deposit(500);
//...
}
}
void Joe() {
for (int i =10; i>0; --i) {
//...
int myPocket = JoesAccount.Withdraw(100);
std::cout << myPocket << std::endl;
//...
}
}
int main() {
//...
boost::thread thread1(bankAgent); // start concurrent execution of bankAgent
boost::thread thread2(Joe); // start concurrent execution of Joe
thread1.join();
thread2.join();
return 0;
}
From time to time, the `bankAgent` will deposit $500 in `JoesAccount`. Joe will similarly withdraw $100 from his account. These sentences describe that the bankAgent and Joe are executed concurrently.
[endsect]
[section Internal locking]
The above example works well as long as the bankAgent and Joe doesn't access JoesAccount at the same time. There is, however, no guarantee that this will not happen. We may use a mutex to guarantee exclusive access to each bank.
class BankAccount {
boost::mutex mtx_;
int balance_;
public:
void Deposit(int amount) {
mtx_.lock();
balance_ += amount;
mtx_.unlock();
}
void Withdraw(int amount) {
mtx_.lock();
balance_ -= amount;
mtx_.unlock();
}
int GetBalance() {
mtx_.lock();
int b = balance_;
mtx_.unlock();
return b;
}
};
Execution of the Deposit and Withdraw operations will no longer be able to make simultaneous access to balance.
Mutex is a simple and basic mechanism for obtaining synchronization. In the above example it is relatively easy to be convinced that the synchronization works correctly (in the absence of exception). In a system with several concurrent objects and several shared objects, it may be difficult to describe synchronization by means of mutexes. Programs that make heavy use of mutexes may be difficult to read and write. Instead, we shall introduce a number of generic classes for handling more complicated forms of synchronization and communication.
With the RAII idiom we can simplify a lot this using the scoped locks. In the code below, guard's constructor locks the passed-in object this, and guard's destructor unlocks this.
class BankAccount {
boost::mutex mtx_; // explicit mutex declaration
int balance_;
public:
void Deposit(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ += amount;
}
void Withdraw(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ -= amount;
}
int GetBalance() {
boost::lock_guard<boost::mutex> guard(mtx_);
return balance_;
}
};
The object-level locking idiom doesn't cover the entire richness of a threading model. For example, the model above is quite deadlock-prone when you try to coordinate multi-object transactions. Nonetheless, object-level locking is useful in many cases, and in combination with other mechanisms can provide a satisfactory solution to many threaded access problems in object-oriented programs.
[endsect]
[section Internal and external locking]
The BankAccount class above uses internal locking. Basically, a class that uses internal locking guarantees that any concurrent calls to its public member functions don't corrupt an instance of that class. This is typically ensured by having each public member function acquire a lock on the object upon entry. This way, for any given object of that class, there can be only one member function call active at any moment, so the operations are nicely serialized.
This approach is reasonably easy to implement and has an attractive simplicity. Unfortunately, "simple" might sometimes morph into "simplistic."
Internal locking is insufficient for many real-world synchronization tasks. Imagine that you want to implement an ATM withdrawal transaction with the BankAccount class. The requirements are simple. The ATM transaction consists of two withdrawals-one for the actual money and one for the $2 commission. The two withdrawals must appear in strict sequence; that is, no other transaction can exist between them.
The obvious implementation is erratic:
void ATMWithdrawal(BankAccount& acct, int sum) {
acct.Withdraw(sum);
// preemption possible
acct.Withdraw(2);
}
The problem is that between the two calls above, another thread can perform another operation on the account, thus breaking the second design requirement.
In an attempt to solve this problem, let's lock the account from the outside during the two operations:
void ATMWithdrawal(BankAccount& acct, int sum) {
boost::lock_guard<boost::mutex> guard(acct.mtx_); 1
acct.Withdraw(sum);
acct.Withdraw(2);
}
Notice that the code above doesn't compiles, the `mtx_` field is private.
We have two possibilities:
* make `mtx_` public which seams odd
* make the `BankAccount` lockable by adding the lock/unlock functions
We can add these functions explicitly
class BankAccount {
boost::mutex mtx_;
int balance_;
public:
void Deposit(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ += amount;
}
void Withdraw(int amount) {
boost::lock_guard<boost::mutex> guard(mtx_);
balance_ -= amount;
}
void lock() {
mtx_.lock();
}
void unlock() {
mtx_.unlock();
}
};
or inheriting from a class which add these lockable functions.
The `basic_lockable_adapter` class helps to define the `BankAccount` class as
class BankAccount
: public basic_lockable_adapter<mutex>
{
int balance_;
public:
void Deposit(int amount) {
boost::lock_guard<BankAccount> guard(*this);
balance_ += amount;
}
void Withdraw(int amount) {
boost::lock_guard<BankAccount> guard(*this);
balance_ -= amount;
}
int GetBalance() {
boost::lock_guard<BankAccount> guard(*this);
return balance_;
}
};
and the code that doesn't compiles becomes
void ATMWithdrawal(BankAccount& acct, int sum) {
boost::lock_guard<BankAccount> guard(acct);
acct.Withdraw(sum);
acct.Withdraw(2);
}
Notice that now acct is being locked by Withdraw after it has already been locked by guard. When running such code, one of two things happens.
* Your mutex implementation might support the so-called recursive mutex semantics. This means that the same thread can lock the same mutex several times successfully. In this case, the implementation works but has a performance overhead due to unnecessary locking. (The locking/unlocking sequence in the two Withdraw calls is not needed but performed anyway-and that costs time.)
* Your mutex implementation might not support recursive locking, which means that as soon as you try to acquire it the second time, it blocks-so the ATMWithdrawal function enters the dreaded deadlock.
As `boost::mutex` is not recursive, we need to use its recursive version `boost::recursive_mutex`.
class BankAccount
: public basic_lockable_adapter<recursive_mutex>
{
// ...
};
The caller-ensured locking approach is more flexible and the most efficient, but very dangerous. In an implementation using caller-ensured locking, BankAccount still holds a mutex, but its member functions don't manipulate it at all. Deposit and Withdraw are not thread-safe anymore. Instead, the client code is responsible for locking BankAccount properly.
class BankAccount
: public basic_lockable_adapter<boost:mutex> {
int balance_;
public:
void Deposit(int amount) {
balance_ += amount;
}
void Withdraw(int amount) {
balance_ -= amount;
}
};
Obviously, the caller-ensured locking approach has a safety problem. BankAccount's implementation code is finite, and easy to reach and maintain, but there's an unbounded amount of client code that manipulates BankAccount objects. In designing applications, it's important to differentiate between requirements imposed on bounded code and unbounded code. If your class makes undue requirements on unbounded code, that's usually a sign that encapsulation is out the window.
To conclude, if in designing a multi-threaded class you settle on internal locking, you expose yourself to inefficiency or deadlocks. On the other hand, if you rely on caller-provided locking, you make your class error-prone and difficult to use. Finally, external locking completely avoids the issue by leaving it all to the client code.
[endsect]
[/
[section Monitors]
The use of `mutex` and `lockers`, as in `BankAccount`, is a common way of defining objects shared by two or more concurrent components. The basic_lockable_adapter class was a first step.
We shall therefore introduce an abstraction that makes it easier to define such objects.
The following class describes a so-called monitor pattern.
template <
typename Lockable=mutex
>
class basic_monitor : protected basic_lockable_adapter<Lockable> { // behaves like an BasicLockable for the derived classes
protected:
typedef unspecified synchronizer; // is an strict lock guard
};
[/shared_monitor]
[/monitor]
A basic_monitor object behaves like a `BasicLockable` object but only for the inheriting classes.
Protected inheritance from lockable_adapter provide to all the derived classes all BasicLockable operations. In addition has a protected nested class, synchronizer, used when defining the monitor operations to synchronize the access critical regions. The BankAccount may be described using Monitor in the following way:
class BankAccount : protected basic_monitor<>
{
protected:
int balance_;
public:
BankAccount() : balance_(0) {}
BankAccount(const BankAccount &rhs) {
synchronizer _(*rhs.mutex());
balance_=rhs.balance_;
}
BankAccount& operator=(BankAccount &rhs)
{
if(&rhs == this) return *this;
int balance=0;
{
synchronizer _(*rhs.mutex());
balance=rhs.balance_;
}
synchronizer _(*this->mutex());
balance_=balance;
return *this;
}
void Deposit(int amount) {
synchronizer _(*this->mutex());
balance_ += amount;
}
int Withdraw(int amount) {
synchronizer _(*this->mutex());
balance_ -= amount;
return amount;
}
int GetBalance() {
synchronizer _(*this->mutex());
return balance_;
}
};
In the following, a monitor means some sub-class of monitor. A synchronized operation means an operation using the synchronizer guard defined within some monitor. Monitor is one example of a high-level concurrency abstraction that can be defined by means of mutexes.
[section Monitor Conditions]
It may happen that a component executing an entry operation of a monitor is unable to continue execution due to some condition not being fulfilled. Consider, for instance, a bounded buffer of characters. Such a buffer may be implemented as a monitor with two operations Push and Pull: the Puss operation cannot be executed if the buffer is full, and the Pull operation cannot be executed if the buffer is empty. A sketch of such a buffer monitor may look as
follows:
class sync_buffer {
boost::mutex mtx_; 1
public:
...
bool full() { return in_==out_; }
bool empty() { return in_==(out_%size)+1; }
void push(T& v) {
// wait if buffer is full
data_[in_]=v;
in_ = (in_% size)+1;
}
T pull() {
// wait if buffer is empty
out_ = (out_% size)+1;
return data_[out_];
}
};
The meaning of a wait is that the calling component is delayed until the condition becomes true. We can do that using Boost.Thread condition variables like:
template <typename T, unsigned size>
class sync_buffer
{
typedef boost::mutex mutex_type;
typedef boost::condition_variable condition_type;
typedef boost::unique_lock<mutex_type> unique_lock_type;
mutex_type mtx_;
condition_type not_full_;
condition_type not_empty_;
T data_[size+1];
unsigned in_, out_;
public:
sync_buffer():in_(0), out_(0) {}
bool full() { return out_==(in_+1)%(size+1); }
bool empty() { return out_==in_; }
unsigned get_in() {return in_;}
unsigned get_out() {return out_;}
void push(T v) {
unique_lock_type guard(mtx_); 1
while (full()) { 2
not_full_.wait(guard);
}
data_[in_]=v;
in_ = (in_+1)% (size+1);
not_empty_.notify_one(); 3
}
T pull() {
unique_lock_type guard(mtx_); 4
while (empty()) { 5
not_empty_.wait(guard);
}
unsigned idx = out_;
out_ = (out_+1)% (size+1);
not_full_.notify_one(); 6
return data_[idx];
}
};
The Monitor class replace the nested synchronizer unique_lock with the class `condition_unique_lock` for this purpose:
template <
typename Lockable,
class Condition=condition_safe<typename best_condition<Lockable>::type >
, typename ScopeTag=typename scope_tag<Lockable>::type
>
class condition_unique_lock
: protected unique_lock<Lockable,ScopeTag>
{
BOOST_CONCEPT_ASSERT((LockableConcept<Lockable>));
public:
typedef Lockable lockable_type;
typedef Condition condition;
explicit condition_unique_lock(lockable_type& obj); 1
condition_unique_lock(lockable_type& obj, condition &cond); 2
template <typename Predicate>
condition_unique_lock(lockable_type& obj, condition &cond, Predicate pred); 3
~condition_unique_lock() 4
typedef bool (condition_unique_lock::*bool_type)() const; 5
operator bool_type() const; 6
bool operator!() const { return false; } 7
bool owns_lock() const { return true; } 8
bool is_locking(lockable_type* l) const 9
void relock_on(condition & cond);
template<typename Clock, typename Duration>
void relock_until(condition & cond, chrono::time_point<Clock, Duration> const& abs_time);
template<typename duration_type>
void relock_on_for(condition & cond, duration_type const& rel_time);
template<typename Predicate>
void relock_when(condition &cond, Predicate pred);
template<typename Predicate>
template<typename Clock, typename Duration>
void relock_when_until(condition &cond, Predicate pred,
chrono::time_point<Clock, Duration> const& abs_time);
template<typename Predicate, typename duration_type>
void relock_when_for(condition &cond, Predicate pred,
duration_type const& rel_time);
10
};
We may now give the complete version of the buffer class. The content of the buffer is: `data_[out_+1], data_[out_+2], ... data_R[in_-1]` where all the indexes are modulo size. The buffer is full if `in_=out_` and it is empty if `in_=(out_+1)%size`.
template <typename T, unsigned size>
class sync_buffer : protected basic_monitor<>
{
condition not_full_;
condition not_empty_;
T data_[size+1];
unsigned in_, out_;
struct not_full {
explicit not_full(sync_buffer &b):that_(b){};
bool operator()() const { return !that_.full(); }
sync_buffer &that_;
};
struct not_empty {
explicit not_empty(sync_buffer &b):that_(b){};
bool operator()() const { return !that_.empty(); }
sync_buffer &that_;
};
public:
BOOST_COPY_CONSTRUCTOR_DELETE(sync_buffer) 1
BOOST_COPY_ASSIGNEMENT_DELETE(sync_buffer) 2
sync_buffer():in_(0), out_(0) {}
bool full() { return out_==(in_+1)%(size+1); }
bool empty() { return out_==in_; }
unsigned get_in() {return in_;}
unsigned get_out() {return out_;}
void push(T v) {
synchronizer _(*this->mutex(), not_full_, not_full(*this)); 3
data_[in_]=v;
in_ = (in_+1)% (size+1);
not_empty_.notify_one(); 4
}
T pull() {
synchronizer _(*this->mutex(), not_empty_, not_empty(*this)); 5
unsigned idx = out_;
out_ = (out_+1)% (size+1);
not_full_.notify_one(); 6
return data_[idx];
}
};
Monitors and conditions are useful for describing simple cases of shared objects (by simple we mean a limited use of conditions). If the conditions for delaying a calling component become complicated, the monitor may similarly become difficult to program and read.
[endsect] [/Monitor Conditions]
[endsect] [/Monitors]
]
[endsect] [/Internal Locking]

419
doc/latch.qbk Normal file
View File

@@ -0,0 +1,419 @@
[/
(C) Copyright 2013 Vicente J. Botet Escriba.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:latches Latches -- EXPERIMENTAL]
[////////////////////]
[section Introdcution]
Latches are a thread co-ordination mechanism that allow one or more threads to block until one or more threads have reached a point.
[/
An individual latch is a reusable object; once the operation has been completed, the threads can re-use the same barrier. It is thus useful for managing repeated tasks handled by multiple threads.
A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
]
[endsect]
[////////////////]
[section Examples]
Sample use cases for the latch include:
* Setting multiple threads to perform a task, and then waiting until all threads have reached a common point.
* Creating multiple threads, which wait for a signal before advancing beyond a common point.
An example of the first use case would be as follows:
void DoWork(thread_pool* pool) {
latch completion_latch(NTASKS);
for (int i = 0; i < NTASKS; ++i) {
pool->submit([&] {
// perform work
...
completion_latch.count_down();
}));
}
// Block until work is done
completion_latch.wait();
}
An example of the second use case is shown below. We need to load data and then process it using a number of threads. Loading the data is I/O bound, whereas starting threads and creating data structures is CPU bound. By running these in parallel, throughput can be increased.
void DoWork() {
latch start_latch(1);
vector<thread*> workers;
for (int i = 0; i < NTHREADS; ++i) {
workers.push_back(new thread([&] {
// Initialize data structures. This is CPU bound.
...
start_latch.wait();
// perform work
...
}));
}
// Load input data. This is I/O bound.
...
// Threads can now start processing
start_latch.count_down();
}
[/
The completion latches can be used to co-ordinate also a set of threads carrying out a repeated task. The number of threads can be adjusted dynamically to respond to changing requirements.
In the example below, a number of threads are performing a multi-stage task. Some tasks may require fewer steps than others, meaning that some threads may finish before others. We reduce the number of threads waiting on the latch when this happens.
void DoWork() {
Tasks& tasks;
size_t initial_threads;
atomic<size_t> current_threads(initial_threads)
vector<thread*> workers;
// Create a barrier, and set a lambda that will be invoked every time the
// barrier counts down. If one or more active threads have completed,
// reduce the number of threads.
completion_latch task_barrier(n_threads);
task_barrier.then([&] {
task_barrier.reset(current_threads);
});
for (int i = 0; i < n_threads; ++i) {
workers.push_back(new thread([&] {
bool active = true;
while(active) {
Task task = tasks.get();
// perform task
...
if (finished(task)) {
current_threads--;
active = false;
}
task_barrier.count_down_and_wait();
}
});
}
// Read each stage of the task until all stages are complete.
while (!finished()) {
GetNextStage(tasks);
}
}
]
[endsect]
[///////////////////////////]
[section:latch Class `latch`]
#include <boost/thread/latch.hpp>
class latch
{
public:
latch(latch const&) = delete;
latch& operator=(latch const&) = delete;
latch(std::size_t count);
~latch();
void wait();
bool try_wait();
template <class Rep, class Period>
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
template <class lock_type, class Clock, class Duration>
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
void count_down();
void count_down_and_wait();
};
[/
void reset(std::size_t count);
]
A latch maintains an internal counter that is initialized when the latch is created. One or more threads may block waiting until the counter is decremented to 0.
Instances of __latch__ are not copyable or movable.
[///////////////////]
[section Constructor `latch(std::size_t)`]
latch(std::size_t count);
[variablelist
[[Effects:] [Construct a latch with is initial value for the internal counter.]]
[[Note:] [The counter could be zero.]]
[[Throws:] [Nothing.]]
]
[endsect]
[//////////////////]
[section Destructor `~latch()`]
~latch();
[variablelist
[[Precondition:] [No threads are waiting or invoking count_down on `*this`.]]
[[Effects:] [Destroys `*this` latch.]]
[[Throws:] [Nothing.]]
]
[endsect]
[/////////////////////////////////////]
[section:wait Member Function `wait()`]
void wait();
[variablelist
[[Effects:] [Block the calling thread until the internal count reaches the value zero. Then all waiting threads
are unblocked. ]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`wait()` is an ['interruption point].]]
]
[endsect]
[/////////////////////////////////////////////]
[section:try_wait Member Function `try_wait()`]
bool try_wait();
[variablelist
[[Returns:] [Returns true if the internal count is 0, and false otherwise. Does not block the calling thread. ]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
]]
]
[endsect]
[//////////////////////////////////////////////]
[section:wait_for Member Function `wait_for() `]
template <class Rep, class Period>
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
[variablelist
[[Effects:] [Block the calling thread until the internal count reaches the value zero or the duration has been elapsed. If no timeout, all waiting threads are unblocked. ]]
[[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if duration has been elapsed. ]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`wait_for()` is an ['interruption point].]]
]
[endsect]
[/////////////////////////////////////////////////]
[section:wait_until Member Function `wait_until()`]
template <class lock_type, class Clock, class Duration>
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
[variablelist
[[Effects:] [Block the calling thread until the internal count reaches the value zero or the time_point has been reached. If no timeout, all waiting threads are unblocked. ]]
[[Returns:] [cv_status::no_timeout if the internal count is 0, and cv_status::timeout if time_point has been reached.]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`wait_until()` is an ['interruption point].]]
]
[endsect]
[/////////////////////////////////////////////////]
[section:count_down Member Function `count_down()`]
void count_down();
[variablelist
[[Requires:] [The internal counter is non zero.]]
[[Effects:] [Decrements the internal count by 1, and returns. If the count reaches 0, any threads blocked in wait() will be released. ]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`count_down()` is an ['interruption point].]]
]
[endsect]
[///////////////////////////////////////////////////////////////////]
[section:count_down_and_wait Member Function `count_down_and_wait()`]
void count_down_and_wait();
[variablelist
[[Requires:] [The internal counter is non zero.]]
[[Effects:] [Decrements the internal count by 1. If the resulting count is not 0, blocks the calling thread until the internal count is decremented to 0 by one or more other threads calling count_down() or count_down_and_wait(). ]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- __thread_interrupted__ if the wait was interrupted by a call to __interrupt__ on the __thread__ object associated with the current thread of execution.
]]
[[Notes:] [`count_down_and_wait()` is an ['interruption point].]]
]
[endsect]
[///////////////////////////////////////]
[
[section:reset Member Function `reset()`]
reset( size_t );
[variablelist
[[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions.]]
[[Returns:] [Resets the latch with a new value for the initial thread count. ]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
]]
]
[endsect]
]
[endsect] [/ latch]
[/
[//////////////////////////////////////////////////]
[section:completion_latch Class `completion_latch `]
#include <boost/thread/completion_latch.hpp>
class completion_latch
{
public:
typedef 'implementation defined' completion_function;
completion_latch(completion_latch const&) = delete;
completion_latch& operator=(completion_latch const&) = delete;
completion_latch(std::size_t count);
template <typename F>
completion_latch(std::size_t count, F&& funct);
~completion_latch();
void wait();
bool try_wait();
template <class Rep, class Period>
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time);
template <class lock_type, class Clock, class Duration>
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time);
void count_down();
void count_down_and_wait();
void reset(std::size_t count);
template <typename F>
completion_function then(F&& funct);
};
A completion latch is like a latch that allows to associate a completion function which will be called once the internal counter reaches the value 0 and all the consumer threads have taken care of the notification.
Instances of completion_latch are not copyable or movable.
Only the additional functions are documented.
[/////////////////////]
[section:c Constructor]
completion_latch(std::size_t count);
[variablelist
[[Effects:] [Construct a completion_latch with is initial value for the internal counter and a noop completion function.]]
[[Note:] [The counter could be zero and rest later.]]
[[Throws:] [Nothing.]]
]
[endsect]
[///////////////////////////////////////////////]
[section:cf Constructor with completion function]
template <typename F>
completion_latch(std::size_t count, F&& funct);
[variablelist
[[Effects:] [Construct a completion_latch with is initial value for the internal counter and the completion function `funct`.]]
[[Note:] [The counter could be zero and reset later.]]
[[Throws:] [
- Any exception thrown by the copy/move construction of funct.
]]
]
[endsect]
[///////////////////////////////////]
[section:then Member Function `then`]
template <typename F>
completion_function then(F&& funct);
[variablelist
[[Requires:] [This function may only be invoked when there are no other threads currently inside the waiting functions. It may also be invoked from within the registered completion function. ]]
[[Effects:] [Associates the parameter `funct` as completion function of the latch. The next time the internal count reaches 0, this function will be invoked.]]
[[Returns:] [The old completion function.]]
[[Throws:] [
- __thread_resource_error__ if an error occurs.
- Any exception thrown by the copy/move construction of completion functions.
]]
]
[endsect]
[endsect] [/ completion_latch]
]
[endsect] [/ Latches]

117
doc/lockable_adapter.qbk Normal file
View File

@@ -0,0 +1,117 @@
[/
(C) Copyright 2008-2013 Vicente J. Botet Escriba
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[/==========================================================================================]
[section:lockable_adapter_hpp Header `<boost/thread/lockable_adapter.hpp>`]
[/==========================================================================================]
namespace boost {
template <typename Lockable> class basic_lockable_adapter;
template <typename Lockable> class lockable_adapter;
template <typename TimedLock> class timed_lockable_adapter;
template <typename SharableLock> class shared_lockable_adapter;
template <typename UpgradableLock> class upgrade_lockable_adapter;
}
[section Template Class `basic_lockable_adapter<>`]
template <typename Lockable>
class basic_lockable_adapter {
public:
basic_lockable_adapter(basic_lockable_adapter const&) = delete
basic_lockable_adapter& opearator=(basic_lockable_adapter const&) = delete
typedef Lockable mutex_type;
basic_lockable_adapter() {}
void lock();
void unlock();
bool try_lock();
};
[endsect]
[section Template Class `lockable_adapter<>`]
template <typename Lockable>
class lockable_adapter : : public basic_lockable_adapter<Lockable> {
public:
lockable_adapter() {}
bool try_lock();
};
[endsect]
[section Template Class `timed_lockable_adapter<>`]
template <typename TimedLock>
class timed_lockable_adapter : public lockable_adapter<TimedLock> {
public:
timed_lockable_adapter() {}
bool try_lock_until(system_time const & abs_time);
template<typename TimeDuration>
bool try_lock_for(TimeDuration const & relative_time);
void lock_until(system_time const & abs_time);
template<typename TimeDuration>
void lock_for(TimeDuration const & relative_time);
};
[endsect]
[section Template Class `shared_lockable_adapter<>`]
template <typename SharableLock>
class shared_lockable_adapter : public timed_lockable_adapter<SharableLock> {
public:
shared_lockable_adapter() {}
void lock_shared();
bool try_lock_shared();
void unlock_shared();
bool try_lock_shared_until(system_time const& t);
template<typename TimeDuration>
bool try_lock_shared_for(TimeDuration const& t);
template<typename TimeDuration>
void lock_shared_for(TimeDuration const& t);
void lock_shared_until(system_time const& t);
};
[endsect]
[section Template Class `upgrade_lockable_adapter<>`]
template <typename UpgradableLock>
class upgrade_lockable_adapter : public shared_lockable_adapter<UpgradableLock>{
public:
upgrade_lockable_adapter();
void lock_upgrade();
bool try_lock_upgrade();
void unlock_upgrade();
void unlock_upgrade_and_lock();
void unlock_and_lock_upgrade();
void unlock_and_lock_shared();
void unlock_upgrade_and_lock_shared();
bool try_lock_upgrade_until(system_time const&t);
template<typename TimeDuration>
bool try_lock_upgrade_for(TimeDuration const&t);
void lock_upgrade_until(system_time const&t);
template<typename TimeDuration>
void lock_upgrade_for(TimeDuration const&t);
};
[endsect]
[endsect]

File diff suppressed because it is too large Load Diff

View File

@@ -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<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
@@ -131,7 +131,7 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
~recursive_mutex();
void lock();
bool try_lock();
bool try_lock() noexcept;
void unlock();
typedef platform-specific-type native_handle_type;
@@ -187,7 +187,7 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
~recursive_timed_mutex();
void lock();
bool try_lock();
bool try_lock() noexcept;
void unlock();
@@ -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<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
@@ -239,3 +239,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
[include shared_mutex_ref.qbk]
[endsect]

View File

@@ -12,8 +12,8 @@
namespace boost
{
struct once_flag;
template<typename Callable>
void call_once(once_flag& flag,Callable func);
template<typename Function, class ...ArgTypes>
inline void call_once(once_flag& flag, Function&& f, ArgTypes&&... args);
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
void call_once(void (*func)(),once_flag& flag);
@@ -21,6 +21,11 @@
}
[warning the variadic prototype is provided only on C++11 compilers supporting variadic templates, otherwise the interface is limited up to 3 parameters.]
[warning the move semantics is ensured only on C++11 compilers supporting SFINAE expression, decltype N3276 and auto. Waiting for a boost::bind that is move aware.]
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
[section:once_flag Typedef `once_flag`]
@@ -45,24 +50,22 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT` i
[section:call_once Non-member function `call_once`]
template<typename Callable>
void call_once(once_flag& flag,Callable func);
template<typename Function, class ...ArgTypes>
inline void call_once(once_flag& flag, Function&& f, ArgTypes&&... args);
[variablelist
[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall
be equivalent to calling the original. ]]
[[Requires:] [`Function` and each or the `ArgTypes` are `MoveConstructible` and `invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...)` shall be well formed. ]]
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
the same `once_flag` object, the argument `func` is called as-if by invoking `invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...)`, and the invocation of
`call_once` is effective if and only if `invoke(decay_copy(boost::forward<Function>(f)), decay_copy(boost::forward<ArgTypes>(args))...)` returns without exception. If an exception is thrown, the exception is propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
without invoking `func`. ]]
[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with
all subsequent `call_once` invocations on the same `once_flag` object. ]]
[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]]
[[Throws:] [`thread_resource_error` when the effects cannot be achieved or any exception propagated from `func`.]]
[[Note:] [The function passed to `call_once` must not also call
`call_once` passing the same `once_flag` object. This may cause
@@ -73,11 +76,14 @@ proceed even though the call to `call_once` didn't actually call the
function, in which case it could also avoid calling `call_once`
recursively.]]
[[Note:] [On some compilers this function has some restrictions, e.g. if variadic templates are not supported the number of arguments is limited to 3; .]]
]
void call_once(void (*func)(),once_flag& flag);
This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of
This second overload is provided for backwards compatibility and is deprecated. The effects of `call_once(func,flag)` shall be the same as those of
`call_once(flag,func)`.
[endsect]

View File

@@ -12,7 +12,9 @@ __boost_thread__ enables the use of multiple threads of execution with shared da
functions for managing the threads themselves, along with others for synchronizing data between the threads or providing separate
copies of data specific to individual threads.
The __boost_thread__ library was originally written and designed by William E. Kempf (version 0). Anthony Williams version (version 1) was a major rewrite designed to
The __boost_thread__ library was originally written and designed by William E. Kempf (version 1).
Anthony Williams version (version 2) was a major rewrite designed to
closely follow the proposals presented to the C++ Standards Committee, in particular
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html N2497],
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html N2320],
@@ -20,8 +22,8 @@ closely follow the proposals presented to the C++ Standards Committee, in partic
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
Vicente J. Botet Escriba started in version 2 the adaptation to comply with the accepted Thread C++11 library (Make use of Boost.Chrono and Boost.Move) and the [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] Howard Hinnant proposal except for the upward conversions.
Some minor features have been added also as thread attributes, reverse_lock, shared_lock_guard.
Vicente J. Botet Escriba started (version 3) the adaptation to comply with the accepted Thread C++11 library (Make use of Boost.Chrono and Boost.Move) and the [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] Howard Hinnant proposal except for the upward conversions.
Some minor non-standard features have been added also as thread attributes, reverse_lock, shared_lock_guard.
In order to use the classes and functions described here, you can
either include the specific headers specified by the descriptions of
@@ -42,6 +44,27 @@ The definition of these macros determines whether BOOST_THREAD_USE_DLL is define
The source code compiled when building the library defines a macros BOOST_THREAD_SOURCE that is used to import or export it. The user must not define this macro in any case.
Boost.Thread depends on some non header-only libraries.
* Boost.System: This dependency is mandatory and you will need to link with the library.
* Boost.Chrono: This dependency is optional (see below how to configure) and you will need to link with the library if you use some of the time related interfaces.
* Boost.DateTime: This dependency is mandatory, but even if Boost.DateTime is a non header-only library Boost.Thread uses only parts that are header-only, so in principle you should not need to link with the library.
It seems that there are some IDE (as e.g. Visual Studio) that deduce the libraries that a program needs to link to inspecting the sources. Such IDE could force to link to Boost.DateTime and/or Boost.Chrono.
As the single mandatory dependency is to Boost.System, the following
bjam toolset=msvc-11.0 --build-type=complete --with-thread
will install only boost_thread and boost_system.
Users of such IDE should force the Boost.Chrono and Boost.DateTime build using
bjam toolset=msvc-11.0 --build-type=complete --with-thread --with-chrono --with-date_time
The following section describes all the macros used to configure Boost.Thread.
[include configuration.qbk]

517
doc/scoped_thread.qbk Normal file
View File

@@ -0,0 +1,517 @@
[/
(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 <boost/thread/scoped_thread.hpp>
struct detach;
struct join_if_joinable;
struct interrupt_and_join_if_joinable;
template <class CallableThread = join_if_joinable>
class strict_scoped_thread;
template <class CallableThread = join_if_joinable>
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 <boost/thread/scoped_thread.hpp>
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 <boost/thread/scoped_thread.hpp>
template <class CallableThread = join_if_joinable>
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;
template <typename F&&, typename ...Args>
explicit strict_scoped_thread(F&&, Args&&...);
~strict_scoped_thread();
};
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 a `join_if_joinable`.
`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 Constructor from a __thread]
explicit strict_scoped_thread(thread&& t) noexcept;
[variablelist
[[Effects:] [move the thread to own `t_`]]
[[Throws:] [Nothing]]
]
[endsect]
[section:call_constructor Move Constructor from a Callable]
template <typename F&&, typename ...Args>
explicit strict_scoped_thread(F&&, Args&&...);
[variablelist
[[Effects:] [Construct a internal thread in place.]]
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
[[Throws:] [Any exception the thread construction can throw.]]
]
[endsect]
[section:destructor Destructor]
~strict_scoped_thread();
[variablelist
[[Effects:] [Equivalent to `CallableThread()(t_)`. ]]
[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]]
]
[endsect]
[endsect]
[section:scoped_thread Class `scoped_thread`]
#include <boost/thread/scoped_thread.hpp>
template <class CallableThread>
class scoped_thread
{
thread t_; // for exposition purposes only
public:
scoped_thread() noexcept;
scoped_thread(const scoped_thread&) = delete;
scoped_thread& operator=(const scoped_thread&) = delete;
explicit scoped_thread(thread&& th) noexcept;
template <typename F&&, typename ...Args>
explicit scoped_thread(F&&, Args&&...);
~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();
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_join_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_join_until(const chrono::time_point<Clock, Duration>& t);
#endif
void detach();
static unsigned hardware_concurrency() noexcept;
static unsigned physical_concurrency() noexcept;
typedef thread::native_handle_type native_handle_type;
native_handle_type native_handle();
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
void interrupt();
bool interruption_requested() const noexcept;
#endif
};
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 __thread as __thread is not designed to be derived from as a polymorphic type.
Anyway `scoped_thread` can be used in most of the contexts a __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 `t_`.]]
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
[[Throws:] [Nothing]]
]
[endsect]
[section:call_constructor Move Constructor from a Callable]
template <typename F&&, typename ...Args>
explicit scoped_thread(F&&, Args&&...);
[variablelist
[[Effects:] [Construct a internal thread in place.]]
[[Postconditions:] [`*this.t_` refers to the newly created thread of execution and `this->get_id()!=thread::id()`.]]
[[Throws:] [Any exception the thread construction can throw.]]
]
[endsect]
[section:destructor Destructor]
~scoped_thread();
[variablelist
[[Effects:] [Equivalent to `CallableThread()(t_)`. ]]
[[Throws:] [Nothing: The `CallableThread()(t_)` should not throw when joining the thread as the scoped variable is on a scope outside the thread function.]]
]
[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 <class Rep, class Period>
bool try_join_for(const chrono::duration<Rep, Period>& rel_time);
[variablelist
[[Effects:] [Equivalent to return `t_.try_join_for(rel_time)`.]]
]
[endsect]
[section:try_join_until Member function `try_join_until()`]
template <class Clock, class Duration>
bool try_join_until(const chrono::time_point<Clock, Duration>& 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:physical_concurrency Static member function `physical_concurrency()`]
unsigned physical_concurrency() noexecpt;
[variablelist
[[Effects:] [Equivalent to return `thread::physical_concurrency()`.]]
]
[endsect]
[section:nativehandle Member function `native_handle()`]
typedef thread::native_handle_type native_handle_type;
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 <boost/thread/scoped_thread.hpp>
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
[variablelist
[[Effects:] [`lhs.swap(rhs)`.]]
]
[endsect]
[endsect]

View File

@@ -5,7 +5,7 @@
http://www.boost.org/LICENSE_1_0.txt).
]
[section:shared_mutex Class `shared_mutex`]
[section:shared_mutex Class `shared_mutex` -- C++14]
#include <boost/thread/shared_mutex.hpp>
@@ -36,18 +36,18 @@
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
// use upgrade_mutex instead.
void lock_upgrade();
void unlock_upgrade();
void lock_upgrade(); // EXTENSION
void unlock_upgrade(); // EXTENSION
void unlock_upgrade_and_lock();
void unlock_and_lock_upgrade();
void unlock_and_lock_shared();
void unlock_upgrade_and_lock_shared();
void unlock_upgrade_and_lock(); // EXTENSION
void unlock_and_lock_upgrade(); // EXTENSION
void unlock_and_lock_shared(); // EXTENSION
void unlock_upgrade_and_lock_shared(); // EXTENSION
#endif
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 || defined BOOST_THREAD_DONT_USE_CHRONO
bool timed_lock_shared(system_time const& timeout);
bool timed_lock(system_time const& timeout);
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock_shared(system_time const& timeout); // DEPRECATED
bool timed_lock(system_time const& timeout); // DEPRECATED
#endif
};
@@ -58,10 +58,11 @@ __shared_lockable_concept__.
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`, `__try_lock_until()`, __timed_lock_ref__, __lock_shared_ref__,
`__try_lock_shared_for()`, `__try_lock_shared_until()`, __try_lock_shared_ref__ and __timed_lock_shared_ref__ are permitted.
Note the the lack of reader-writer priority policies in shared_mutex. This is due to an algorithm credited to Alexander Terekhov which lets the OS decide which thread is the next to get the lock without caring whether a unique lock or shared lock is being sought. This results in a complete lack of reader or writer starvation. It is simply fair.
[endsect]
[section:upgrade_mutex Class `upgrade_mutex`]
[section:upgrade_mutex Class `upgrade_mutex` -- EXTENSION]
#include <boost/thread/shared_mutex.hpp>
@@ -141,3 +142,87 @@ Multiple concurrent calls to __lock_ref__, __try_lock_ref__, `__try_lock_for()`,
[endsect]
[section:null_mutex Class `null_mutex` -- EXTENSION]
#include <boost/thread/null_mutex.hpp>
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 <class Rep, class Period>
bool try_lock_shared_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_shared_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
void unlock_shared();
void lock();
bool try_lock();
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
void unlock();
void lock_upgrade();
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
void unlock_upgrade();
// Shared <-> Exclusive
bool try_unlock_shared_and_lock();
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_unlock_shared_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_unlock_shared_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
void unlock_and_lock_shared();
// Shared <-> Upgrade
bool try_unlock_shared_and_lock_upgrade();
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_unlock_shared_and_lock_upgrade_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_unlock_shared_and_lock_upgrade_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
void unlock_upgrade_and_lock_shared();
// Upgrade <-> Exclusive
void unlock_upgrade_and_lock();
bool try_unlock_upgrade_and_lock();
#ifdef BOOST_THREAD_USES_CHRONO
template <class Rep, class Period>
bool try_unlock_upgrade_and_lock_for(const chrono::duration<Rep, Period>& rel_time);
template <class Clock, class Duration>
bool try_unlock_upgrade_and_lock_until(const chrono::time_point<Clock, Duration>& abs_time);
#endif
void unlock_and_lock_upgrade();
};
The class `boost::null_mutex` provides a no-op implementation of a multiple-reader / single-writer mutex. It is a model of the
__UpgradeLockable concept.
[endsect]

554
doc/sync_queues_ref.qbk Normal file
View File

@@ -0,0 +1,554 @@
[/
/ Copyright (c) 2013 Vicente J. Botet Escriba
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:synchronized_queues Synchronized Queues -- EXPERIMENTAL]
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3533.html [*N3533 - C++ Concurrent Queues]] C++1y proposal from Lawrence Crowl and Chris Mysen and [@http://www.manning.com/williams/ [*C++ Concurrency in Action]] from Anthony Williams.]
[section:tutorial Tutorial]
Concurrent queues are a well know mechanism for communicating data between different threads.
Concurrent queues have inherently copy/move semantics for the data handling operation. Reference-returning interfaces are forbidden as multiple access to these references can not be thread-safe.
[endsect]
[section:ref Reference]
[section:sync_queue_req Synchronized Queue Model]
[section:bounded_unbounded Bounded-Unbounded Queues]
One of the major features of a concurrent queue is whether it has a bounded-unbounded capacity.
[endsect]
[section:locking Locking/Lock-free Queues]
Locking queues can by nature block waiting for the queue to be non-empty or non-full.
Lock-free queues will have some trouble waiting for the queue to be non-empty or non-full queues. These queues can not define operations such as push (and pull for bounded queues). That is, it could have blocking operations (presumably emulated with busy wait) but not waiting operations.
[endsect]
[section:closed Closed Queue]
Threads using a queue for communication need some mechanism to signal when the queue is no longer needed. The usual approach is add an additional out-of-band signal. However, this approach suffers from the flaw that threads waiting on either full or empty queues need to be woken up when the queue is no longer needed. Rather than require an out-of-band signal, we chose to directly support such a signal in the queue itself, which considerably simplifies coding.
To achieve this signal, a thread may close a queue. Once closed, no new elements may be pushed onto the queue. Push operations on a closed queue will either return queue_op_status::closed (when they have a queue_op_status return type), set the closed parameter if it has one or throw sync_queue::closed (when they do not). Elements already on the queue may be pulled off. When a queue is empty and closed, pull operations will either return queue_op_status::closed (when they have a status return), set the closed parameter if it has one or throw sync_queue::closed (when they do not).
[endsect]
[section:exception Concurrent Queues Throw specification]
[section:locking Locking]
All the functions are defined as if we had in addition to its specific Throw specification the following:
[variablelist
[[Throws:] [Any exception thrown by the internal locking.]]
]
[endsect]
[section:bad_alloc Allocation]
All the functions that allocate a resource are defined as if we had in addition to its specific Throw specification the following:
[variablelist
[[Throws:] [Any exception due to allocation errors.]]
]
[endsect]
[endsect]
[section:BasicConcurrentQueue Basic Concurrent Queue Operations]
The essential solution to the problem of concurrent queuing is to shift to value-based operations, rather than reference-based operations.
The BasicConcurrentQueue concept models the basic operations of a concurrent queue.
A type `Q` meets the BasicConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
* Q::value_type
* Q::size_type
* `q.push(e);`
* `q.push(rve);`
* `q.pull(lre);`
* `lre = q.pull();`
* `spe = q.ptr_pull();`
* `b = q.empty();`
* `u = q.size();`
where
* `q` denotes a value of type `Q`,
* `e` denotes a value of type Q::value_type,
* `u` denotes a value of type Q::size_type,
* `lve` denotes a lvalue referece of type Q::value_type,
* `rve` denotes a rvalue referece of type Q::value_type:
* `spe` denotes a shared_ptr<Q::value_type>
[section:push `q.push(e);`]
[variablelist
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue copying it (this could need an allocation for unbounded queues).]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Postcondition:] [`! q.empty()`.]]
[[Return type:] [`void`.]]
[[Throws:] [If the queue was closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[section:push_m `q.push(rve);`]
[variablelist
[[Effects:] [Waits until the queue is not full (for bounded queues) and then push `e` to the queue moving it (this could need an allocation for unbounded queues).]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Postcondition:] [`! q.empty()`.]]
[[Return type:] [`void`.]]
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[section:pull_lv `q.pull(lve)`]
[variablelist
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Postcondition:] [`! q.full()`.]]
[[Return type:] [`void`.]]
[[Throws:] [Any exception thrown by the move of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[section:pull `e = q.pull()`]
[variablelist
[[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety.]]
[[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element.]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Postcondition:] [`! q.full()`.]]
[[Return type:] [`Q::value_type`.]]
[[Return:] [The pulled element.]]
[[Throws:] [Any exception thrown by the copy of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[section:ptr_pull `spe = q.ptr_pull()`]
[variablelist
[/[Requires:] [Q::value_type is no throw copy movable. This is needed to ensure the exception safety. ]]
[[Effects:] [Waits until the queue is not empty and not closed. If the queue is empty and closed throws sync_queue_is_closed. Otherwise pull the element from the queue `q` and moves the pulled element into a shared_ptr.]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Postcondition:] [`! q.full()`.]]
[[Return type:] [`Q::value_type`.]]
[[Return:] [A shared_ptr containing the pulled element.]]
[[Throws:] [Any exception thrown by the move of `e`. Any exception throw when allocation resources are missing. ]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[endsect]
[section:non_waaiting Non-waiting Concurrent Queue Operations]
The ConcurrentQueue concept models a queue with .
A type `Q` meets the ConcurrentQueue requirements if the following expressions are well-formed and have the specified semantics
* `b = q.try_push(e);`
* `b = q.try_push(rve);`
* `b = q.try_pull(lre);`
where
* `q` denotes a value of type `Q`,
* `e` denotes a value of type Q::value_type,
* `u` denotes a value of type Q::size_type,
* `lve` denotes a lvalue referece of type Q::value_type,
* `rve` denotes a rvalue referece of type Q::value_type:
* `spe` denotes a shared_ptr<Q::value_type>
[section:try_push `q.try_push(e);`]
[variablelist
[[Effects:] [If the queue `q` is not full, push the `e` to the queue copying it.]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation when the operation succeeds. ]]
[[Return type:] [`bool`.]]
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[section:try_push_m `q.try_push(rve());`]
[variablelist
[[Effects:] [If the queue `q` is not full, push the `e` onto the queue moving it.]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Return type:] [`bool`.]]
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
[[Postcondition:] [If the call returns `true`, `! q.empty()`.]]
[[Throws:] [If the queue is closed, throws sync_queue_is_closed. Any exception thrown by the copy of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[section:pull_lv `b = q.try_pull(lve)`]
[variablelist
[[Effects:] [Waits until the queue is not empty and then pull the element from the queue `q` and moves the pulled element into `lve` (this could need an allocation for unbounded queues).]]
[[Synchronization:] [Prior pull-like operations on the same object synchronizes with this operation.]]
[[Postcondition:] [`! q.full()`.]]
[[Return type:] [`bool`.]]
[[Return:] [If the queue `q` is full return `false`, otherwise return `true`;]]
[[Throws:] [Any exception thrown by the move of `e`.]]
[[Exception safety:] [If an exception is thrown then the queue state is unmodified.]]
]
[endsect]
[endsect]
[section:non_blocking Non-blocking Concurrent Queue Operations]
For cases when blocking for mutual exclusion is undesirable, we have non-blocking operations. The interface is the same as the try operations but is allowed to also return queue_op_status::busy in case the operation is unable to complete without blocking.
Non-blocking operations are provided only for BlockingQueues
* `b = q.try_push(nb, e);`
* `b = q.try_push(nb, rve);`
* `b = q.try_pull(nb, lre);`
where
* `q` denotes a value of type `Q`,
* `e` denotes a value of type Q::value_type,
* `u` denotes a value of type Q::size_type,
* `lve` denotes a lvalue referece of type Q::value_type,
* `rve` denotes a rvalue referece of type Q::value_type:
* `spe` denotes a shared_ptr<Q::value_type>
[endsect]
[section:bounded Bounded Concurrent Queue Operations]
Bounded queues add the following valid expressions
* `Q q(u);`
* `b = q.full();`
* `u = q.capacity();`
[endsect]
[section:closed_op Closed Concurrent Queue Operations]
* `q.close();`
* `b = q.closed();`
Basic expressions
* `q.push(e,c);`
* `q.push(rve,c);`
* `q.pull(lre,c);`
* `spe = q.ptr_pull(c);`
Non-waiting operations
* `b = q.try_push(e, c);`
* `b = q.try_push(rve, c);`
* `b = q.try_pull(lre, c);`
Non-blocking operations are provided by BlockingQueues
* `b = q.try_push(nb, e, c);`
* `b = q.try_push(nb, rve, c);`
* `b = q.try_pull(nb, lre, c);`
[endsect]
[endsect]
[section:sync_bounded_queue_ref Synchronized Bounded Queue]
#include <boost/thread/sync_bounded_queue.hpp>
namespace boost
{
struct sync_queue_is_closed : std::exception {};
template <typename ValueType>
class sync_bounded_queue;
// Stream-like operators
template <typename ValueType>
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType&& elem);
template <typename ValueType>
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem);
template <typename ValueType>
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem);
}
[section:sync_queue_is_closed Class `sync_queue_is_closed`]
#include <boost/thread/sync_bounded_queue.hpp>
namespace boost
{
struct sync_queue_is_closed : std::exception {};
}
[endsect]
[section:sync_bounded_queue Class template `sync_bounded_queue<>`]
#include <boost/thread/sync_bounded_queue.hpp>
namespace boost
{
template <typename ValueType>
class sync_bounded_queue
{
public:
typedef ValueType value_type;
typedef std::size_t size_type;
sync_bounded_queue(sync_bounded_queue const&) = delete;
sync_bounded_queue& operator=(sync_bounded_queue const&) = delete;
explicit sync_bounded_queue(size_type max_elems);
template <typename Range>
sync_bounded_queue(size_type max_elems, Range range);
~sync_bounded_queue();
// Observers
bool empty() const;
bool full() const;
size_type capacity() const;
size_type size() const;
bool closed() const;
// Modifiers
void push(const value_type& x);
void push(value_type&& x);
bool try_push(const value_type& x);
bool try_push(value_type&& x);
bool try_push(no_block_tag, const value_type& x);
bool try_push(no_block_tag, value_type&& x);
void pull(value_type&);
// enable_if is_nothrow_movable<value_type>
value_type pull();
shared_ptr<ValueType> ptr_pull();
bool try_pull(value_type&);
bool try_pull(no_block_tag,value_type&);
shared_ptr<ValueType> try_pull();
void close();
};
}
[endsect]
[section:stream_out_operators Non-Member Function `operator<<()`]
#include <boost/thread/sync_bounded_queue.hpp>
namespace boost
{
template <typename ValueType>
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType&& elem);
template <typename ValueType>
sync_bounded_queue<ValueType>& operator<<(sync_bounded_queue<ValueType>& sbq, ValueType const&elem);
}
[endsect]
[section:stream_in_operators Non-Member Function `operator>>()`]
#include <boost/thread/sync_bounded_queue.hpp>
namespace boost
{
template <typename ValueType>
sync_bounded_queue<ValueType>& operator>>(sync_bounded_queue<ValueType>& sbq, ValueType &elem);
}
[endsect]
[endsect]
[section:sync_queue_ref Synchronized Unbounded Queue]
#include <boost/thread/sync_queue.hpp>
namespace boost
{
template <typename ValueType>
class sync_queue;
// Stream-like operators
template <typename ValueType>
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType&& elem);
template <typename ValueType>
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem);
template <typename ValueType>
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem);
}
[section:sync_queue Class template `sync_queue<>`]
#include <boost/thread/sync_queue.hpp>
namespace boost
{
template <typename ValueType>
class sync_queue
{
public:
typedef ValueType value_type;
typedef std::size_t size_type;
sync_queue(sync_queue const&) = delete;
sync_queue& operator=(sync_queue const&) = delete;
sync_queue();
explicit template <typename Range>
sync_queue(Range range);
~sync_queue();
// Observers
bool empty() const;
bool full() const;
size_type size() const;
bool closed() const;
// Modifiers
void push(const value_type& x);
void push(value_type&& x);
bool try_push(const value_type& x);
bool try_push(value_type&&) x);
bool try_push(no_block_tag, const value_type& x);
bool try_push(no_block_tag, value_type&& x);
void pull(value_type&);
// enable_if is_nothrow_movable<value_type>
value_type pull();
shared_ptr<ValueType> ptr_pull();
bool try_pull(value_type&);
bool try_pull(no_block_tag,value_type&);
shared_ptr<ValueType> try_pull();
void close();
};
}
[endsect]
[section:stream_out_operators Non-Member Function `operator<<()`]
#include <boost/thread/sync_queue.hpp>
namespace boost
{
template <typename ValueType>
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType&& elem);
template <typename ValueType>
sync_queue<ValueType>& operator<<(sync_queue<ValueType>& sbq, ValueType const&elem);
}
[endsect]
[section:stream_in_operators Non-Member Function `operator>>()`]
#include <boost/thread/sync_queue.hpp>
namespace boost
{
template <typename ValueType>
sync_queue<ValueType>& operator>>(sync_queue<ValueType>& sbq, ValueType &elem);
}
[endsect]
[endsect]
[endsect]
[endsect]

193
doc/sync_streams.qbk Normal file
View File

@@ -0,0 +1,193 @@
[/
/ Copyright (c) 2013 Vicente J. Botet Escriba
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:ext_locked_streams Externally Locked Streams - EXPERIMENTAL]
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
[note These features are based on the [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2013/n3535.html [*N3535 - C++ Streams Mutex]] C++1y proposal, even if the library proposes al alternative interface.]
[section:tutorial Tutorial]
[endsect] [/tutorial]
[/////////////////////]
[section:ref Reference]
#include <boost/thread/externally_locked_stream.hpp>
namespace boost
{
template <typename Stream, typename RecursiveMutex=recursive_mutex>
class externally_locked_stream;
template <class Stream, typename RecursiveMutex=recursive_mutex>
class stream_guard;
template <typename Stream, typename RecursiveMutex>
struct is_strict_lock_sur_parole<stream_guard<Stream, RecursiveMutex> > : true_type {};
// Stream-like operators
template <typename Stream, typename RecursiveMutex, typename T>
const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, T arg);
template <typename Stream, typename RecursiveMutex>
const stream_guard<Stream, RecursiveMutex>&
operator<<(const stream_guard<Stream, RecursiveMutex>& lck, Stream& (*arg)(Stream&));
template <typename Stream, typename RecursiveMutex, typename T>
const stream_guard<Stream, RecursiveMutex>&
operator>>(const stream_guard<Stream, RecursiveMutex>& lck, T& arg);
template <typename Stream, typename RecursiveMutex, typename T>
stream_guard<Stream, RecursiveMutex>
operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, T arg);
template <typename Stream, typename RecursiveMutex>
stream_guard<Stream, RecursiveMutex>
operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, Stream& (*arg)(Stream&));
template <typename Stream, typename RecursiveMutex, typename T>
stream_guard<Stream, RecursiveMutex>
operator>>(externally_locked_stream<Stream, RecursiveMutex>& mtx, T& arg);
}
[/////////////////////////////////////////]
[section:stream_guard Class `stream_guard`]
#include <boost/thread/externally_locked_stream.hpp>
namespace boost
{
template <class Stream, typename RecursiveMutex=recursive_mutex>
class stream_guard
{
public:
typedef typename externally_locked_stream<Stream, RecursiveMutex>::mutex_type mutex_type;
// Constructors, Assignment and Destructors
stream_guard(stream_guard const&) = delete;
stream_guard& operator=(stream_guard const&) = delete;
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx);
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx, adopt_lock_t);
stream_guard(stream_guard&& rhs);
~stream_guard();
// Observers
bool owns_lock(mutex_type const* l) const BOOST_NOEXCEPT;
Stream& get() const;
Stream& bypass() const;
};
}
`stream_guard` is a model of __StrictLock.
[//////////////////////////////////////////////////]
[section:constructor `stream_guard(mutex_type & 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:constructor_adopt `stream_guard(mutex_type & m,boost::adopt_lock_t)`]
[variablelist
[[Precondition:] [The current thread owns a lock on `m` equivalent to one
obtained by a call to [lock_ref_link `m.lock()`].]]
[[Effects:] [Stores a reference to `m`. Takes ownership of the lock state of
`m`.]]
[[Throws:] [Nothing.]]
]
[endsect]
[//////////////////////////////////////////////////////////]
[section:move_constructor `stream_guard(stream_guard && 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 `~stream_guard()`]
[variablelist
[[Effects:] [Invokes [unlock_ref_link `m.unlock()`] on the __lockable_concept_type__
object passed to the constructor.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[//////////////////////////////////////////////////////////////////]
[section:externally_locked_stream Class `externally_locked_stream `]
#include <boost/thread/externally_locked_stream.hpp>
namespace boost
{
template <typename Stream, typename RecursiveMutex>
class externally_locked_stream: public externally_locked<Stream&, RecursiveMutex>
{
public:
// Constructors, Assignment and Destructors
externally_locked_stream(externally_locked_stream const&) = delete;
externally_locked_stream& operator=(externally_locked_stream const&) = delete;
externally_locked_stream(Stream& stream, RecursiveMutex& mtx);
// Modifiers
stream_guard<Stream, RecursiveMutex> hold();
};
}
`externally_locked_stream` cloaks a reference to an stream of type `Stream`, and actually
provides full access to that object through the `get` member functions, provided you
pass a reference to a strict lock object.
[////////////////////////////////////////////////////////////////////////]
[section:constructor `externally_locked_stream(Stream&, RecursiveMutex&)`]
[variablelist
[[Effects:] [Constructs an externally locked object storing the cloaked reference object and its locking mutex.]]
]
[endsect]
[/////////////////////]
[section:hold `hold()`]
[variablelist
[[Returns:] [A stream_guard which will hold the mutex during it lifetime .]]
]
[endsect]
[endsect]
[endsect] [/ref]
[endsect] [/Externally Locked Streams]

View File

@@ -11,4 +11,34 @@
[@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]
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.
[include internal_locking.qbk]
[include external_locking.qbk]
[section:with Executing Around a Function]
In particular, the library provides some lock factories.
template <class Lockable, class Function>
auto with_lock_guard(Lockable& m, Function f) -> decltype(f())
{
auto&& _ = boost::make_lock_guard(m);
f();
}
that can be used as
int i = with_lock_guard(mtx, []()
{
// access the protected state
return true;
});
[endsect] [/ With]
[endsect] [/ Tutorial]

147
doc/synchronized_value.qbk Normal file
View File

@@ -0,0 +1,147 @@
[/
/ Copyright (c) 2013 Vicente J. Botet Escriba
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:synchronized_valuesxxx Synchronized Values - EXPERIMENTAL]
[warning These features are experimental and subject to change in future versions. There are not too much tests yet, so it is possible that you can find out some trivial bugs :(]
[section:tutorial Tutorial]
[note This tutorial is an adaptation of the paper of Anthony Williams "Enforcing Correct Mutex Usage with Synchronized Values" to the Boost library.]
[section The Problem with Mutexes]
The key problem with protecting shared data with a mutex is that there is no easy way to associate the mutex with the data. It is thus relatively easy to accidentally write code that fails to lock the right mutex - or even locks the wrong mutex - and the compiler will not help you.
std::mutex m1;
int value1;
std::mutex m2;
int value2;
int readValue1()
{
boost::lock_guard<boost::mutex> lk(m1);
return value1;
}
int readValue2()
{
boost::lock_guard<boost::mutex> lk(m1); // oops: wrong mutex
return value2;
}
Moreover, managing the mutex lock also clutters the source code, making it harder to see what is really going on.
The use of synchronized_value solves both these problems - the mutex is intimately tied to the value, so you cannot access it without a lock, and yet access semantics are still straightforward. For simple accesses, synchronized_value behaves like a pointer-to-T; for example:
boost::synchronized_value<std::string> value3;
std::string readValue3()
{
return *value3;
}
void setValue3(std::string const& newVal)
{
*value3=newVal;
}
void appendToValue3(std::string const& extra)
{
value3->append(extra);
}
Both forms of pointer dereference return a proxy object rather than a real reference, to ensure that the lock on the mutex is held across the assignment or method call, but this is transparent to the user.
[endsect] [/The Problem with Mutexes]
[section Beyond Simple Accesses]
The pointer-like semantics work very well for simple accesses such as assignment and calls to member functions. However, sometimes you need to perform an operation that requires multiple accesses under protection of the same lock, and that's what the synchronize() method provides.
By calling synchronize() you obtain an strict_lock_ptr object that holds a lock on the mutex protecting the data, and which can be used to access the protected data. The lock is held until the strict_lock_ptr object is destroyed, so you can safely perform multi-part operations. The strict_lock_ptr object also acts as a pointer-to-T, just like synchronized_value does, but this time the lock is already held. For example, the following function adds a trailing slash to a path held in a synchronized_value. The use of the strict_lock_ptr object ensures that the string hasn't changed in between the query and the update.
void addTrailingSlashIfMissing(boost::synchronized_value<std::string> & path)
{
boost::strict_lock_ptr<std::string> u=path.synchronize();
if(u->empty() || (*u->rbegin()!='/'))
{
*u+='/';
}
}
[endsect] [/Beyond Simple Accesses]
[section Operations Across Multiple Objects]
Though synchronized_value works very well for protecting a single object of type T, nothing that we've seen so far solves the problem of operations that require atomic access to multiple objects unless those objects can be combined within a single structure protected by a single mutex.
One way to protect access to two synchronized_value objects is to construct a strict_lock_ptr for each object and use those to access the respective protected values; for instance:
synchronized_value<std::queue<MessageType> > q1,q2;
void transferMessage()
{
strict_lock_ptr<std::queue<MessageType> > u1 = q1.synchronize();
strict_lock_ptr<std::queue<MessageType> > u2 = q2.synchronize();
if(!u1->empty())
{
u2->push_back(u1->front());
u1->pop_front();
}
}
This works well in some scenarios, but not all -- if the same two objects are updated together in different sections of code then you need to take care to ensure that the strict_lock_ptr objects are constructed in the same sequence in all cases, otherwise you have the potential for deadlock. This is just the same as when acquiring any two mutexes.
In order to be able to use the dead-lock free lock algorithms we need to use instead unique_lock_ptr, which is Lockable.
synchronized_value<std::queue<MessageType> > q1,q2;
void transferMessage()
{
unique_lock_ptr<std::queue<MessageType> > u1 = q1.unique_synchronize(boost::defer_lock);
unique_lock_ptr<std::queue<MessageType> > u2 = q2.unique_synchronize(boost::defer_lock);
boost::lock(u1,u2); // dead-lock free algorithm
if(!u1->empty())
{
u2->push_back(u1->front());
u1->pop_front();
}
}
While the preceding takes care of dead-lock, the access to the synchronized_value via unique_lock_ptr requires a lock that is not forced by the interface.
An alternative on compilers providing a standard library that supports movable std::tuple is to use the free synchronize function, which will lock all the mutexes associated to the synchronized values and return a tuple os strict_lock_ptr.
synchronized_value<std::queue<MessageType> > q1,q2;
void transferMessage()
{
auto lks = synchronize(u1,u2); // dead-lock free algorithm
if(!std::get<1>(lks)->empty())
{
std::get<2>(lks)->push_back(u1->front());
std::get<1>(lks)->pop_front();
}
}
[endsect] [/Operations Across Multiple Objects]
[section Value semantics]
synchronized_value has value semantics even if the syntax lets is close to a pointer (this is just because we are unable to define smart references).
[endsect] [/Value semantics]
[endsect] [/tutorial]
[include synchronized_value_ref.qbk]
[endsect] [/Synchronized values]

View File

@@ -0,0 +1,415 @@
[/
/ Copyright (c) 2013 Vicente J. Botet Escriba
/
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
/]
[section:synchronized_value_ref Reference ]
#include <boost/thread/synchronized_value.hpp>
namespace boost
{
template<typename T, typename Lockable = mutex>
class synchronized_value;
// Specialized swap algorithm
template <typename T, typename L>
void swap(synchronized_value<T,L> & lhs, synchronized_value<T,L> & rhs);
template <typename T, typename L>
void swap(synchronized_value<T,L> & lhs, T & rhs);
template <typename T, typename L>
void swap(T & lhs, synchronized_value<T,L> & rhs);
// Hash support
template<typename T, typename L>
struct hash<synchronized_value<T,L> >;
// Comparison
template <typename T, typename L>
bool operator==(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
template <typename T, typename L>
bool operator!=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
template <typename T, typename L>
bool operator<(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
template <typename T, typename L>
bool operator<=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
template <typename T, typename L>
bool operator>(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
template <typename T, typename L>
bool operator>=(synchronized_value<T,L> const&lhs, synchronized_value<T,L> const& rhs)
// Comparison with T
template <typename T, typename L>
bool operator==(T const& lhs, synchronized_value<T,L> const&rhs);
template <typename T, typename L>
bool operator!=(T const& lhs, synchronized_value<T,L> const&rhs);
template <typename T, typename L>
bool operator<(T const& lhs, synchronized_value<T,L> const&rhs);
template <typename T, typename L>
bool operator<=(T const& lhs, synchronized_value<T,L> const&rhs);
template <typename T, typename L>
bool operator>(T const& lhs, synchronized_value<T,L> const&rhs);
template <typename T, typename L>
bool operator>=(T const& lhs, synchronized_value<T,L> const&rhs);
template <typename T, typename L>
bool operator==(synchronized_value<T,L> const& lhs, T const& rhs);
template <typename T, typename L>
bool operator!=(synchronized_value<T,L> const& lhs, T const& rhs);
template <typename T, typename L>
bool operator<(synchronized_value<T,L> const& lhs, T const& rhs);
template <typename T, typename L>
bool operator<=(synchronized_value<T,L> const& lhs, T const& rhs);
template <typename T, typename L>
bool operator>(synchronized_value<T,L> const& lhs, T const& rhs);
template <typename T, typename L>
bool operator>=(synchronized_value<T,L> const& lhs, T const& rhs);
#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
template <typename ...SV>
std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
#endif
}
[section:synchronized_value Class `synchronized_value`]
#include <boost/thread/synchronized_value.hpp>
namespace boost
{
template<typename T, typename Lockable = mutex>
class synchronized_value
{
public:
typedef T value_type;
typedef Lockable mutex_type;
synchronized_value() noexept(is_nothrow_default_constructible<T>::value);
synchronized_value(T const& other) noexept(is_nothrow_copy_constructible<T>::value);
synchronized_value(T&& other) noexept(is_nothrow_move_constructible<T>::value);
synchronized_value(synchronized_value const& rhs);
synchronized_value(synchronized_value&& other);
// mutation
synchronized_value& operator=(synchronized_value const& rhs);
synchronized_value& operator=(value_type const& val);
void swap(synchronized_value & rhs);
void swap(value_type & rhs);
//observers
T get() const;
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
explicit operator T() const;
#endif
strict_lock_ptr<T,Lockable> operator->();
const_strict_lock_ptr<T,Lockable> operator->() const;
strict_lock_ptr<T,Lockable> synchronize();
const_strict_lock_ptr<T,Lockable> synchronize() const;
deref_value operator*();;
const_deref_value operator*() const;
private:
T value_; // for exposition only
mutable mutex_type mtx_; // for exposition only
};
}
[variablelist
[[Requires:] [`Lockable` is `Lockable`.]]
]
[section:constructor `synchronized_value()`]
synchronized_value() noexept(is_nothrow_default_constructible<T>::value);
[variablelist
[[Requires:] [`T` is `DefaultConstructible`.]]
[[Effects:] [Default constructs the cloaked value_type]]
[[Throws:] [Any exception thrown by `value_type()`.]]
]
[endsect]
[section:constructor_vt `synchronized_value(T const&)`]
synchronized_value(T const& other) noexept(is_nothrow_copy_constructible<T>::value);
[variablelist
[[Requires:] [`T` is `CopyConstructible`.]]
[[Effects:] [Copy constructs the cloaked value_type using the parameter `other`]]
[[Throws:] [Any exception thrown by `value_type(other)`.]]
]
[endsect]
[section:copy_cons `synchronized_value(synchronized_value const&)`]
synchronized_value(synchronized_value const& rhs);
[variablelist
[[Requires:] [`T` is `DefaultConstructible` and `Assignable`.]]
[[Effects:] [Assigns the value on a scope protected by the mutex of the rhs. The mutex is not copied.]]
[[Throws:] [Any exception thrown by `value_type()` or `value_type& operator=(value_type&)` or `mtx_.lock()`.]]
]
[endsect]
[section:move_vt `synchronized_value(T&&)`]
synchronized_value(T&& other) noexept(is_nothrow_move_constructible<T>::value);
[variablelist
[[Requires:] [`T` is `CopyMovable `.]]
[[Effects:] [Move constructs the cloaked value_type]]
[[Throws:] [Any exception thrown by `value_type(value_type&&)`.]]
]
[endsect]
[section:move `synchronized_value(synchronized_value&&)`]
synchronized_value(synchronized_value&& other);
[variablelist
[[Requires:] [`T` is `CopyMovable `.]]
[[Effects:] [Move constructs the cloaked value_type]]
[[Throws:] [Any exception thrown by `value_type(value_type&&)` or `mtx_.lock()`.]]
]
[endsect]
[section:assign `operator=(synchronized_value const&)`]
synchronized_value& operator=(synchronized_value const& rhs);
[variablelist
[[Requires:] [`T` is `Assignale`.]]
[[Effects:] [Copies the underlying value on a scope protected by the two mutexes. The mutex is not copied. The locks are acquired avoiding deadlock. For example, there is no problem if one thread assigns `a = b` and the other assigns `b = a`.]]
[[Return:] [`*this`]]
[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]]
]
[endsect]
[section:assign_vt `operator=(T const&)`]
synchronized_value& operator=(value_type const& val);
[variablelist
[[Requires:] [`T` is `Assignale`.]]
[[Effects:] [Copies the value on a scope protected by the mutex.]]
[[Return:] [`*this`]]
[[Throws:] [Any exception thrown by `value_type& operator(value_type const&)` or `mtx_.lock()`.]]
]
[endsect]
[section:get `get() const`]
T get() const;
[variablelist
[[Requires:] [`T` is `CopyConstructible`.]]
[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]]
[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]]
]
[endsect]
[section:T `operator T() const`]
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
explicit operator T() const;
#endif
[variablelist
[[Requires:] [`T` is `CopyConstructible`.]]
[[Return:] [`A copy of the protected value obtained on a scope protected by the mutex.`]]
[[Throws:] [Any exception thrown by `value_type(value_type const&)` or `mtx_.lock()`.]]
]
[endsect]
[section:swap `swap(synchronized_value&)`]
void swap(synchronized_value & rhs);
[variablelist
[[Requires:] [`T` is `Assignale`.]]
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]
[[Throws:] [Any exception thrown by `swap(value_, rhs.value)` or `mtx_.lock()` or `rhs_.mtx_.lock()`.]]
]
[endsect]
[section:swap_vt `swap(synchronized_value&)`]
void swap(value_type & rhs);
[variablelist
[[Requires:] [`T` is `Swapable`.]]
[[Effects:] [Swaps the data on a scope protected by both mutex. Both mutex are acquired to avoid dead-lock. The mutexes are not swapped.]]
[[Throws:] [Any exception thrown by `swap(value_, rhs)` or `mtx_.lock()`.]]
]
[endsect]
[section:indir `operator->()`]
strict_lock_ptr<T,Lockable> operator->();
Essentially calling a method `obj->foo(x, y, z)` calls the method `foo(x, y, z)` inside a critical section as long-lived as the call itself.
[variablelist
[[Return:] [`A strict_lock_ptr<>.`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:indir_const `operator->() const`]
const_strict_lock_ptr<T,Lockable> operator->() const;
If the `synchronized_value` object involved is const-qualified, then you'll only be able to call const methods
through `operator->`. So, for example, `vec->push_back("xyz")` won't work if `vec` were const-qualified.
The locking mechanism capitalizes on the assumption that const methods don't modify their underlying data.
[variablelist
[[Return:] [`A const_strict_lock_ptr <>.`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:synchronize `synchronize()`]
strict_lock_ptr<T,Lockable> synchronize();
The synchronize() factory make easier to lock on a scope. As discussed, `operator->` can only lock over the duration of a call, so it is insufficient for complex operations. With `synchronize()` you get to lock the object in a scoped and to directly access the object inside that scope.
[*Example:]
void fun(synchronized_value<vector<int>> & vec) {
auto vec2=vec.synchronize();
vec2.push_back(42);
assert(vec2.back() == 42);
}
[variablelist
[[Return:] [`A strict_lock_ptr <>.`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:synchronize_const `synchronize() const`]
const_strict_lock_ptr<T,Lockable> synchronize() const;
[variablelist
[[Return:] [`A const_strict_lock_ptr <>.`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:deref `operator*()`]
deref_value operator*();;
[variablelist
[[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a reference to the protected value.`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:deref_const `operator*() const`]
const_deref_value operator*() const;
[variablelist
[[Return:] [`A an instance of a class that locks the mutex on construction and unlocks it on destruction and provides implicit conversion to a constant reference to the protected value.`]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:synchronize Non-Member Function `synchronize`]
#include <boost/thread/synchronized_value.hpp>
namespace boost
{
#if ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
template <typename ...SV>
std::tuple<typename synchronized_value_strict_lock_ptr<SV>::type ...> synchronize(SV& ...sv);
#endif
}
[endsect]
[endsect]

View File

@@ -8,10 +8,10 @@
[library Thread
[quickbook 1.5]
[version 3.0.0]
[version 4.2.0]
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
[copyright 2007-11 Anthony Williams]
[copyright 2011-12 Vicente J. Botet Escriba]
[copyright 2011-13 Vicente J. Botet Escriba]
[purpose C++ Library for launching threads and synchronizing data between them]
[category text]
[license
@@ -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]]
@@ -135,6 +135,7 @@
[template owns_lock_ref_link[link_text] [link thread.synchronization.locks.unique_lock.owns_lock [link_text]]]
[def __owns_lock_ref__ [owns_lock_ref_link `owns_lock()`]]
[def __owns_lock [owns_lock_ref_link `owns_lock()`]]
[template owns_lock_shared_ref_link[link_text] [link thread.synchronization.locks.shared_lock.owns_lock [link_text]]]
[def __owns_lock_shared_ref__ [owns_lock_shared_ref_link `owns_lock()`]]
@@ -145,6 +146,7 @@
[def __boost_thread__ [*Boost.Thread]]
[def __not_a_thread__ ['Not-a-Thread]]
[def __interruption_points__ [link interruption_points ['interruption points]]]
[def __lock_error__ `lock_error`]
[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]]
[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]]
@@ -154,19 +156,27 @@
[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`]]
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
[def __reverse_lock [link thread.synchronization.other_locks.reverse_lock `reverse_lock`]]
[def __shared_lock_guard [link thread.synchronization.other_locks.shared_lock_guard `shared_lock_guard`]]
[def __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_locks.strict_lock `strict_lock`]]
[def __nested_strict_lock [link thread.synchronization.other_locks.strict_locks.nested_strict_lock `nested_strict_lock`]]
[def __thread__ [link thread.thread_management.thread `boost::thread`]]
[def __thread [link thread.thread_management.thread `boost::thread`]]
[def __thread [link thread.thread_management.thread `thread`]]
[def __thread_id__ [link thread.thread_management.thread.id `boost::thread::id`]]
[template join_link[link_text] [link thread.thread_management.thread.join [link_text]]]
[def __join__ [join_link `join()`]]
@@ -174,7 +184,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()`]]
@@ -194,6 +203,7 @@
[def __thread_resource_error__ `boost::thread_resource_error`]
[def __thread_interrupted__ `boost::thread_interrupted`]
[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]]
[def __latch__ [link thread.synchronization.latches.latch `latch`]]
[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]]
[def __cond_wait__ [cond_wait_link `wait()`]]
@@ -220,6 +230,7 @@
[include changes.qbk]
[include thread_ref.qbk]
[include scoped_thread.qbk]
[section:synchronization Synchronization]
[include sync_tutorial.qbk]
@@ -228,11 +239,20 @@
[include condition_variables.qbk]
[include once.qbk]
[include barrier.qbk]
[/include latch.qbk]
[include futures.qbk]
[/include async_executors.qbk]
[endsect]
[include tss.qbk]
[section:sds Synchronized Data Structures]
[include synchronized_value.qbk]
[include sync_queues_ref.qbk]
[/include sync_streams.qbk]
[endsect]
[include time.qbk]
[include emulations.qbk]

View File

@@ -21,7 +21,7 @@
{
thread::id get_id() noexcept;
template<typename TimeDuration>
void yield() noexcept;
void yield() noexcept; // DEPRECATED
template <class Clock, class Duration>
void sleep_until(const chrono::time_point<Clock, Duration>& abs_time);
template <class Rep, class Period>
@@ -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 <TimeDuration>
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:detach 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]
@@ -338,7 +402,7 @@ The user can access to some synchronization functions related to the native curr
Of course all the synchronization facilities provided by Boost.Thread are also available on native threads.
The `boost::this_thread` interrupt related functions behave in a degraded mode when called from a thread created using the native interface, i.e. `boost::this_thread::interruption_enabled()` returns false. As consequence the use of `boost::this_thread::disable_interruption` and `boost::this_thread::restore_interruption` will do nothing and calls to `boost::this_thread::interrupt_point()` will be just ignored.
The `boost::this_thread` interrupt related functions behave in a degraded mode when called from a thread created using the native interface, i.e. `boost::this_thread::interruption_enabled()` returns false. As consequence the use of `boost::this_thread::disable_interruption` and `boost::this_thread::restore_interruption` will do nothing and calls to `boost::this_thread::interruption_point()` will be just ignored.
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` wiil returns false for the native threads.
@@ -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 <class F,class A1,class A2,...>
thread(F f,A1 a1,A2 a2,...);
// template <class F, class ...Args>
// explicit thread(F&& f, Args&&... args); // NOT YET IMPLEMENTED
template <class F, class ...Args>
explicit thread(F&& f, Args&&... args);
template <class F>
explicit thread(attributes& attrs, F f); // EXTENSION
template <class F>
thread(attributes& attrs, F &&f); // EXTENSION
// template <class F, class ...Args>
// explicit thread(attributes& attrs, F&& f, Args&&... args); // NOT YET IMPLEMENTED
template <class F, class ...Args>
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;
id get_id() const noexcept;
@@ -405,6 +470,7 @@ This behavior is incompatible with the current Boost.Thread design, so the use o
void detach();
static unsigned hardware_concurrency() noexcept;
static unsigned physical_concurrency() noexcept;
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
@@ -413,19 +479,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<typename TimeDuration>
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 +533,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 1: If there was a thread previously associated with
`*this` then that thread is detached, version 2: 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 +559,7 @@ any) to `*this`. Version 1: If there was a thread previously associated with
]
[endsect]
[section:callable_constructor Thread Constructor]
@@ -488,7 +569,7 @@ any) to `*this`. Version 1: If there was a thread previously associated with
[variablelist
[[Requires:] [`Callable` must by Copyable and `func()` must be a valid expression.]]
[[Requires:] [`Callable` must be Copyable and `func()` must be a valid expression.]]
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
@@ -515,7 +596,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any
[variablelist
[[Preconditions:] [`Callable` must by copyable.]]
[[Preconditions:] [`Callable` must be copyable.]]
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
@@ -543,7 +624,7 @@ If the attributes declare the native thread as detached, the boost::thread will
[variablelist
[[Preconditions:] [`Callable` must by Movable.]]
[[Preconditions:] [`Callable` must be Movable.]]
[[Effects:] [`func` is moved into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution. If this invocation results in an exception being propagated into the internals of the thread library that is
@@ -570,7 +651,7 @@ not of type __thread_interrupted__, then `std::terminate()` will be called. Any
[variablelist
[[Preconditions:] [`Callable` must by copyable.]]
[[Preconditions:] [`Callable` must be copyable.]]
[[Effects:] [`func` is copied into storage managed internally by the thread library, and that copy is invoked on a newly-created
thread of execution with the specified attributes. If this invocation results in an exception being propagated into the internals of the thread library that is
@@ -599,7 +680,7 @@ If the attributes declare the native thread as detached, the boost::thread will
[variablelist
[[Preconditions:] [`F` and each `A`n must by copyable or movable.]]
[[Preconditions:] [`F` and each `A`n must be copyable or movable.]]
[[Effects:] [As if [link
thread.thread_management.thread.callable_constructor
@@ -626,34 +707,29 @@ are copied into internal storage for access by the new thread.]]]
~thread();
[variablelist
[[Effects:] [Version 1: If `*this` has an associated thread of execution, calls __detach__, Version 2: 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()`]
@@ -680,18 +756,25 @@ are copied into internal storage for access by the new thread.]]]
[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete.]]
[[Synchronization:] [The completion of the thread represented by `*this` synchronizes with the
corresponding successful `join()` return. ]]
[[Note:] [Operations on *this are not synchronized.
]]
[[Postconditions:] [If `*this` refers to a thread of execution on entry, that thread of execution has completed. `*this` no longer refers to any thread of execution.]]
[[Throws:] [__thread_interrupted__ if the current thread of execution is interrupted or `system_error`]]
[[Error Conditions:] [
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
[*resource_deadlock_would_occur]: if deadlock is detected or `this->get_id() == boost::this_thread::get_id()`.
[*invalid_argument]: if the thread is not joinable and `BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED` is defined.
[/
[*no_such_process]: if the thread is not valid.
[*invalid_argument]: if the thread is not joinable.
]
]]
@@ -702,16 +785,24 @@ 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<typename TimeDuration>
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:] [`this->get_id()!=boost::this_thread::get_id()`]]
[[Preconditions:] [the thread is joinable.]]
[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `wait_until` has
been reach or the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]]
@@ -727,12 +818,13 @@ unchanged.]]
[[Error Conditions:] [
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
[/
[*no_such_process]: if the thread is not valid.
[*invalid_argument]: if the thread is not joinable.
]
]]
@@ -750,7 +842,7 @@ unchanged.]]
[variablelist
[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]]
[[Preconditions:] [the thread is joinable.]]
[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete,
the specified duration `rel_time` has elapsed. If `*this` doesn't refer to a thread of execution, returns immediately.]]
@@ -766,12 +858,13 @@ unchanged.]]
[[Error Conditions:] [
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
[/
[*no_such_process]: if the thread is not valid.
[*invalid_argument]: if the thread is not joinable.
]
]]
@@ -789,7 +882,7 @@ unchanged.]]
[variablelist
[[Preconditions:] [`this->get_id()!=boost::this_thread::get_id()`]]
[[Preconditions:] [the thread is joinable.]]
[[Effects:] [If `*this` refers to a thread of execution, waits for that thread of execution to complete, the time `abs_time` has
been reach. If `*this` doesn't refer to a thread of execution, returns immediately.]]
@@ -805,12 +898,14 @@ unchanged.]]
[[Error Conditions:] [
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == std::this_thread::get_id().
[*resource_deadlock_would_occur]: if deadlock is detected or this->get_id() == boost::this_thread::get_id().
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
[/
[*no_such_process]: if the thread is not valid.
[*invalid_argument]: if the thread is not joinable.
]
]]
@@ -825,7 +920,7 @@ unchanged.]]
[section:detach Member function `detach()`]
void detach() noexcept;
void detach();
[variablelist
@@ -835,7 +930,15 @@ unchanged.]]
[[Postconditions:] [`*this` no longer refers to any thread of execution.]]
[[Throws:] [Nothing]]
[[Throws:] [`system_error`]]
[[Error Conditions:] [
[*no_such_process]: if the thread is not valid.
[*invalid_argument]: if the thread is not joinable and BOOST_THREAD_TRHOW_IF_PRECONDITION_NOT_SATISFIED is defined.
]]
]
@@ -857,7 +960,7 @@ a default-constructed __thread_id__.]]
[endsect]
[section:interrupt Member function `interrupt()`]
[section:interrupt Member function `interrupt()` EXTENSION]
void interrupt();
@@ -889,6 +992,21 @@ or 0 if this information is not available.]]
[endsect]
[section:physical_concurrency Static member function `physical_concurrency()`]
unsigned physical_concurrency() noexecpt;
[variablelist
[[Returns:] [The number of physical cores available on the current system. In contrast to `hardware_concurrency()` it does not return
the number of virtual cores, but it counts only physical cores.]]
[[Throws:] [Nothing]]
]
[endsect]
[section:nativehandle Member function `native_handle()`]
typedef platform-specific-type native_handle_type;
@@ -905,38 +1023,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.]]
@@ -945,22 +1086,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]
@@ -1248,9 +1393,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
}
}
@@ -1331,7 +1476,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 <boost/thread/thread.hpp>
@@ -1342,6 +1487,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
@@ -1352,8 +1506,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]
@@ -1370,8 +1522,7 @@ specified by `rel_time` has elapsed or the time point specified by
[variablelist
[[Effects:] [Suspends the current thread until the time period
specified by `rel_time` has elapsed or the time point specified by
[[Effects:] [Suspends the current thread until the time point specified by
`abs_time` has been reached.]]
[[Throws:] [Nothing if Clock satisfies the TrivialClock requirements and operations of Duration
@@ -1395,8 +1546,8 @@ do not throw exceptions. __thread_interrupted__ if the current thread of executi
[variablelist
[[Effects:] [Suspends the current thread until the time point specified by
`abs_time` has been reached.]]
[[Effects:] [Suspends the current thread until the duration specified by
by `rel_time` has elapsed.]]
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted.]]
@@ -1570,14 +1721,16 @@ registered with `at_thread_exit()`]]
[endsect]
[section:threadgroup Class `thread_group`]
[section:threadgroup Class `thread_group` EXTENSION]
#include <boost/thread/thread.hpp>
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();
@@ -1585,6 +1738,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;
@@ -1640,7 +1795,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.]]
@@ -1670,12 +1825,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]

View File

@@ -10,14 +10,16 @@
As of Boost 1.50.0, the __boost_thread__ library uses Boost.Chrono library for all operations that require a
time out as defined in the standard c++11. These include (but are not limited to):
* __sleep_for
* __sleep_until
* __try_join_for
* __try_join_until
* __wait_for
* __wait_until
* __try_lock_for
* __try_lock_until
* `boost::this_thread::__sleep_for`
* `boost::this_thread::__sleep_until`
* `boost::__thread::__try_join_for`
* `boost::__thread::__try_join_until`
* `boost::__condition_variable::__wait_for`
* `boost::__condition_variable::__wait_until`
* `boost::__condition_variable_any::__cvany_wait_for`
* `boost::__condition_variable_any::__cvany_wait_until`
* `__TimedLockable::__try_lock_for`
* `__TimedLockable::__try_lock_until`
[section:deprecated Deprecated]
The time related functions introduced in Boost 1.35.0, using the [link date_time Boost.Date_Time] library are deprecated. These include (but are not limited to):

View File

@@ -47,10 +47,16 @@ platforms such cleanup is only done for threads that are started with
`boost::thread` unless `boost::on_thread_exit()` is called manually
from that thread.
[heading Rationale about the nature of the key]
Boost.Thread uses the address of the `thread_specific_ptr` instance as key of the thread specific pointers. This avoids to create/destroy a key which will need a lock to protect from race conditions. This has a little performance liability, as the access must be done using an associative container.
[section:thread_specific_ptr Class `thread_specific_ptr`]
#include <boost/thread/tss.hpp>
// #include <boost/thread/tss.hpp>
namespace boost
{
template <typename T>
class thread_specific_ptr
{
@@ -66,6 +72,7 @@ from that thread.
T* release();
void reset(T* new_value=0);
};
}
[section:default_constructor `thread_specific_ptr();`]
@@ -102,10 +109,14 @@ supplied `cleanup_function` will be used to destroy any thread-local objects whe
[variablelist
[[Requires:] [All the thread specific instances associated to this thread_specific_ptr (except maybe the one associated to this thread) must be null.]]
[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]]
[[Throws:] [Nothing.]]
[[Remarks:] [The requirement is due to the fact that in order to delete all these instances, the implementation should be forced to maintain a list of all the threads having an associated specific ptr, which is against the goal of thread specific data.]]
]
[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been

View File

@@ -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 <boost/thread/mutex.hpp>
#include <boost/thread/lockable_adapter.hpp>
#include <boost/thread/externally_locked.hpp>
#include <boost/thread/strict_lock.hpp>
#include <boost/thread/lock_types.hpp>
#include <iostream>
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<mutex>
{
public:
typedef basic_lockable_adapter<mutex> 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<BankAccount, AccountManager > checkingAcct_;
externally_locked<BankAccount, AccountManager > savingsAcct_;
};
//]
//[Checking2Savings
void AccountManager::Checking2Savings(int amount)
{
strict_lock<AccountManager> 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<AccountManager> 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<AccountManager> guard1(*this);
// if (some_condition()) {
// guard1.lock();
// }
// {
// strict_lock<AccountManager> guard(guard1);
// checkingAcct_.get(guard).Withdraw(amount);
// savingsAcct_.get(guard).Deposit(amount);
// }
// guard1.unlock();
//}
////]
//#else
////[AMoreComplicatedChecking2Savings
void AccountManager::AMoreComplicatedChecking2Savings(int amount) {
unique_lock<AccountManager> guard1(*this);
if (some_condition()) {
guard1.lock();
}
{
nested_strict_lock<unique_lock<AccountManager> > guard(guard1);
checkingAcct_.get(guard).Withdraw(amount);
savingsAcct_.get(guard).Deposit(amount);
}
guard1.unlock();
}
////]
//#endif
int main()
{
AccountManager mgr;
mgr.Checking2Savings(100);
return 0;
}

View File

@@ -7,15 +7,16 @@
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/thread_only.hpp>
#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<boost::mutex> lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
bounded_buffer(int n) : boost::noncopyable(), begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
@@ -38,9 +39,10 @@ public:
}
private:
int begin, end, buffered;
int begin, end;
std::vector<int>::size_type buffered;
std::vector<int> 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<boost::mutex> 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<boost::mutex> io_lock(io_mutex);
std::cout << "received: " << n << std::endl;
}
} while (n != -1); // -1 indicates end of buffer

View File

@@ -0,0 +1,78 @@
// Copyright (C) 2012-2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/detail/log.hpp>
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <exception>
#include <string>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
int p1_ex()
{
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
throw std::logic_error("kk");
}
int p1()
{
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
return 1;;
}
int main()
{
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
{
try
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
boost::future<int> f2 = f1.fallback_to(-1);
assert(f2.get()==1);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
{
try
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1_ex);
boost::future<int> f2 = f1.fallback_to(-1);
assert(f2.get()==-1);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
}
#else
int main()
{
return 0;
}
#endif

109
example/future_then.cpp Normal file
View File

@@ -0,0 +1,109 @@
// Copyright (C) 2012-2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/detail/log.hpp>
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <string>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
int p1()
{
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
return 123;
}
int p2(boost::future<int> f)
{
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
try
{
return 2 * f.get();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_ASSERT(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_ASSERT(false);
}
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
}
int p2s(boost::shared_future<int> f)
{
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
try
{
return 2 * f.get();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
BOOST_ASSERT(false);
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
BOOST_ASSERT(false);
}
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
}
int main()
{
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
{
try
{
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
boost::future<int> f2 = f1.then(&p2);
(void)f2.get();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
{
try
{
boost::shared_future<int> f1 = boost::async(boost::launch::async, &p1).share();
boost::future<int> f2 = f1.then(&p2s);
(void)f2.get();
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
}
#else
int main()
{
return 0;
}
#endif

59
example/future_unwrap.cpp Normal file
View File

@@ -0,0 +1,59 @@
// Copyright (C) 2012-2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/detail/log.hpp>
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <string>
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
int p1()
{
BOOST_THREAD_LOG << "P1" << BOOST_THREAD_END_LOG;
return 123;
}
boost::future<int> p2()
{
BOOST_THREAD_LOG << "<P2" << BOOST_THREAD_END_LOG;
boost::future<int> f1 = boost::async(boost::launch::async, &p1);
BOOST_THREAD_LOG << "P2>" << BOOST_THREAD_END_LOG;
return boost::move(f1);
}
int main()
{
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
try
{
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
boost::future<int> inner_future = outer_future.unwrap();
int i = inner_future.get();
BOOST_THREAD_LOG << "i= "<< i << "" << BOOST_THREAD_END_LOG;
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
}
#else
int main()
{
return 0;
}
#endif

60
example/lambda_future.cpp Normal file
View File

@@ -0,0 +1,60 @@
// Copyright (C) 2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/detail/log.hpp>
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <string>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
&& ! defined BOOST_NO_CXX11_LAMBDAS
int main()
{
BOOST_THREAD_LOG << "<MAIN" << BOOST_THREAD_END_LOG;
try
{
{
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
int result = f1.get();
BOOST_THREAD_LOG << "f1 " << result << BOOST_THREAD_END_LOG;
}
{
boost::future<int> f1 = boost::async(boost::launch::async, []() {return 123;});
boost::future<int> f2 = f1.then([](boost::future<int> f) {return 2*f.get(); });
int result = f2.get();
BOOST_THREAD_LOG << "f2 " << result << BOOST_THREAD_END_LOG;
}
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG << "ERRORRRRR "<<ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG << " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
BOOST_THREAD_LOG << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
}
#else
int main()
{
return 0;
}
#endif

72
example/make_future.cpp Normal file
View File

@@ -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
#include <boost/thread/future.hpp>
#include <iostream>
namespace boost
{
template <typename T>
exception_ptr make_exception_ptr(T v)
{
return copy_exception(v);
}
}
int p1() { return 5; }
void p() { }
#if defined BOOST_THREAD_USES_MOVE
boost::future<void> void_compute()
{
return BOOST_THREAD_MAKE_RV_REF(boost::make_ready_future());
}
#endif
boost::future<int> compute(int x)
{
if (x == 0) return boost::make_ready_future(0);
//if (x < 0) return boost::make_ready_future<int>(boost::make_exception_ptr(std::logic_error("Error")));
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error"));
//boost::future<int> f1 = boost::async([]() { return x+1; });
boost::future<int> f1 = boost::async(boost::launch::async, p1);
return boost::move(f1);
}
boost::shared_future<int> shared_compute(int x)
{
if (x == 0) return boost::make_ready_future(0).share();
if (x < 0) return boost::make_ready_future<int>(std::logic_error("Error")).share();
//boost::future<int> f1 = boost::async([]() { return x+1; });
boost::shared_future<int> f1 = boost::async(p1).share();
return boost::move(f1);
}
int main()
{
#if defined BOOST_THREAD_USES_MOVE
{
boost::future<void> f = void_compute();
f.get();
}
#endif
{
boost::future<int> f = compute(2);
std::cout << f.get() << std::endl;
}
{
boost::future<int> f = compute(0);
std::cout << f.get() << std::endl;
}
{
boost::shared_future<int> f = shared_compute(2);
std::cout << f.get() << std::endl;
}
return 0;
}

View File

@@ -6,10 +6,10 @@
#include <vector>
#include <iostream>
#include <boost/thread/condition.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_only.hpp>
namespace {
const int ITERS = 100;
@@ -20,7 +20,7 @@ template <typename M>
class buffer_t
{
public:
typedef typename M::scoped_lock scoped_lock;
typedef boost::unique_lock<M> 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<boost::mutex> 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<boost::mutex> 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<int> buf;
};

View File

@@ -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 <boost/thread/mutex.hpp>
@@ -16,7 +16,7 @@ public:
counter() : count(0) { }
int increment() {
boost::mutex::scoped_lock scoped_lock(mutex);
boost::unique_lock<boost::mutex> 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<boost::mutex> scoped_lock(io_mutex);
std::cout << "count == " << i << std::endl;
}

View File

@@ -0,0 +1,63 @@
// (C) Copyright 2012 Howard Hinnant
// (C) Copyright 2012 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// adapted from the example given by Howard Hinnant in
#define BOOST_THREAD_VERSION 4
#include <iostream>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/externally_locked_stream.hpp>
void use_cerr(boost::externally_locked_stream<std::ostream> &mcerr)
{
using namespace boost;
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(10);
while (chrono::steady_clock::now() < tf)
{
mcerr << "logging data to cerr\n";
this_thread::sleep_for(chrono::milliseconds(500));
}
}
void use_cout(boost::externally_locked_stream<std::ostream> &mcout)
{
using namespace boost;
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
while (chrono::steady_clock::now() < tf)
{
mcout << "logging data to cout\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
int main()
{
using namespace boost;
recursive_mutex terminal_mutex;
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
scoped_thread<> t1(boost::thread(use_cerr, boost::ref(mcerr)));
scoped_thread<> t2(boost::thread(use_cout, boost::ref(mcout)));
this_thread::sleep_for(chrono::seconds(2));
std::string nm;
{
strict_lock<recursive_mutex> lk(terminal_mutex);
std::ostream & gcout = mcout.get(lk);
//std::istream & gcin = mcin.get(lk);
gcout << "Enter name: ";
//gcin >> nm;
}
t1.join();
t2.join();
mcout << nm << '\n';
return 0;
}

View File

@@ -0,0 +1,61 @@
// (C) Copyright 2012 Howard Hinnant
// (C) Copyright 2012 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// adapted from the example given by Howard Hinnant in
#define BOOST_THREAD_VERSION 4
#include <iostream>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/ostream_buffer.hpp>
void use_cerr()
{
using namespace boost;
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
int i = 0;
while (chrono::steady_clock::now() < tf)
{
ostream_buffer<std::ostream> mcerr(std::cerr);
mcerr.stream() << "logging data to cerr " << i++ << "\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
void use_cout()
{
using namespace boost;
chrono::steady_clock::time_point tf = chrono::steady_clock::now() + chrono::seconds(5);
int i = 0;
while (chrono::steady_clock::now() < tf)
{
ostream_buffer<std::ostream> mcout(std::cout);
mcout.stream() << "logging data to cout " << i++ << "\n";
this_thread::sleep_for(chrono::milliseconds(500));
}
}
int main()
{
using namespace boost;
scoped_thread<> t1(&use_cerr);
scoped_thread<> t2(&use_cout);
this_thread::sleep_for(chrono::seconds(2));
std::string nm = "he, he\n";
{
ostream_buffer<std::ostream> mcout(std::cout);
mcout.stream() << "Enter name: \n";
}
t1.join();
t2.join();
{
ostream_buffer<std::ostream> mcout(std::cout);
mcout.stream() << nm;
}
return 0;
}

View File

@@ -12,10 +12,11 @@
int value=0;
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
boost::once_flag once;
static boost::once_flag once;
//static boost::once_flag once2 = BOOST_ONCE_INIT;
#else
boost::once_flag once = BOOST_ONCE_INIT;
boost::once_flag once2 = once;
static boost::once_flag once = BOOST_ONCE_INIT;
//static boost::once_flag once2 = once;
#endif
void init()

View File

@@ -0,0 +1,237 @@
// (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)
//
// This performance test is based on the performance test provided by maxim.yegorushkin
// at https://svn.boost.org/trac/boost/ticket/7422
#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/chrono/stopwatches/simple_stopwatch.hpp>
#include <condition_variable>
#include <future>
#include <limits>
#include <cstdio>
#include <thread>
#include <mutex>
#include <vector>
////////////////////////////////////////////////////////////////////////////////////////////////
namespace
{
////////////////////////////////////////////////////////////////////////////////////////////////
// class Stopwatch
// {
// public:
// typedef long long rep;
//
// static rep now()
// {
// timespec ts;
// if (clock_gettime(CLOCK_MONOTONIC, &ts)) abort();
// return ts.tv_sec * rep(1000000000) + ts.tv_nsec;
// }
//
// Stopwatch() :
// start_(now())
// {
// }
//
// rep elapsed() const
// {
// return now() - start_;
// }
//
// private:
// rep start_;
// };
typedef boost::chrono::simple_stopwatch<> Stopwatch;
////////////////////////////////////////////////////////////////////////////////////////////////
struct BoostTypes
{
typedef boost::condition_variable condition_variable;
typedef boost::mutex mutex;
typedef boost::mutex::scoped_lock scoped_lock;
};
struct StdTypes
{
typedef std::condition_variable condition_variable;
typedef std::mutex mutex;
typedef std::unique_lock<std::mutex> scoped_lock;
};
template <class Types>
struct SharedData: Types
{
unsigned const iterations;
unsigned counter;
unsigned semaphore;
typename Types::condition_variable cnd;
typename Types::mutex mtx;
Stopwatch::rep producer_time;
SharedData(unsigned iterations, unsigned consumers) :
iterations(iterations), counter(), semaphore(consumers) // Initialize to the number of consumers. (*)
, producer_time()
{
}
};
////////////////////////////////////////////////////////////////////////////////////////////////
template <class S>
void producer_thread(S* shared_data)
{
Stopwatch sw;
unsigned const consumers = shared_data->semaphore; // (*)
for (unsigned i = shared_data->iterations; i--;)
{
{
typename S::scoped_lock lock(shared_data->mtx);
// Wait till all consumers signal.
while (consumers != shared_data->semaphore)
{
shared_data->cnd.wait(lock);
}
shared_data->semaphore = 0;
// Signal consumers.
++shared_data->counter;
}
shared_data->cnd.notify_all();
}
shared_data->producer_time = sw.elapsed().count();
}
template <class S>
void consumer_thread(S* shared_data)
{
unsigned counter = 0;
while (counter != shared_data->iterations)
{
{
typename S::scoped_lock lock(shared_data->mtx);
// Wait till the producer signals.
while (counter == shared_data->counter)
{
shared_data->cnd.wait(lock);
}
counter = shared_data->counter;
// Signal the producer.
++shared_data->semaphore;
}
shared_data->cnd.notify_all();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////
template <class Types>
Stopwatch::rep benchmark_ping_pong(unsigned consumer_count)
{
typedef SharedData<Types> S;
auto best_producer_time = std::numeric_limits<Stopwatch::rep>::max BOOST_PREVENT_MACRO_SUBSTITUTION ();
std::vector<std::thread> consumers
{ consumer_count };
// Run the benchmark 10 times and report the best time.
for (int times = 10; times--;)
{
S shared_data
{ 100000, consumer_count };
// Start the consumers.
for (unsigned i = 0; i < consumer_count; ++i)
consumers[i] = std::thread
{ consumer_thread<S> , &shared_data };
// Start the producer and wait till it finishes.
std::thread
{ producer_thread<S> , &shared_data }.join();
// Wait till consumers finish.
for (unsigned i = 0; i < consumer_count; ++i)
consumers[i].join();
best_producer_time = std::min BOOST_PREVENT_MACRO_SUBSTITUTION (best_producer_time, shared_data.producer_time);
}
return best_producer_time;
}
////////////////////////////////////////////////////////////////////////////////////////////////
} // namespace
////////////////////////////////////////////////////////////////////////////////////////////////
// sudo chrt -f 99 /usr/bin/time -f "\n***\ntime: %E\ncontext switches: %c\nwaits: %w" /home/max/otsquant/build/Linux-x86_64-64.g++-release/test/test
/*
Producer-consumer ping-pong tests. It aims to benchmark condition variables with and without
thread cancellation support by comparing the time it took to complete the benchmark.
Condition variable with thread cancellation support is boost::condition_variable from
boost-1.51. Without - std::condition_variable that comes with gcc-4.7.2.
One producer, one to CONSUMER_MAX consumers. The benchmark calls
condition_variable::notify_all() without holding a mutex to maximize contention within this
function. Each benchmark for a number of consumers is run three times and the best time is
picked to get rid of outliers.
The results are reported for each benchmark for a number of consumers. The most important number
is (std - boost) / std * 100. Positive numbers are when boost::condition_variable is faster,
negative it is slower.
*/
int main()
{
std::printf("MAIN\n");
enum
{
CONSUMER_MAX = 2
};
struct
{
Stopwatch::rep boost, std;
} best_times[CONSUMER_MAX] = {};
for (unsigned i = 1; i <= CONSUMER_MAX; ++i)
{
auto& b = best_times[i - 1];
std::printf("STD: %d\n", i);
b.std = benchmark_ping_pong<StdTypes> (i);
std::printf("BOOST: %d\n", i);
b.boost = benchmark_ping_pong<BoostTypes> (i);
std::printf("consumers: %4d\n", i);
std::printf("best std producer time: %15.9fsec\n", b.std * 1e-9);
std::printf("best boost producer time: %15.9fsec\n", b.boost * 1e-9);
std::printf("(std - boost) / std: %7.2f%%\n", (b.std - b.boost) * 100. / b.std);
}
printf("\ncsv:\n\n");
printf("consumers,(std-boost)/std,std,boost\n");
for (unsigned i = 1; i <= CONSUMER_MAX; ++i)
{
auto& b = best_times[i - 1];
printf("%d,%f,%lld,%lld\n", i, (b.std - b.boost) * 100. / b.std, b.std, b.boost);
}
return 1;
}

View File

@@ -0,0 +1,72 @@
// (C) Copyright 2013 Andrey
// (C) Copyright 2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This performance test is based on the performance test provided by maxim.yegorushkin
// at https://svn.boost.org/trac/boost/ticket/7422
#define BOOST_THREAD_USES_CHRONO
#include <iostream>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/chrono/chrono_io.hpp>
#include <boost/thread/shared_mutex.hpp>
using namespace boost;
shared_mutex mtx;
const int cycles = 10000;
void shared()
{
int cycle(0);
while (++cycle < cycles)
{
shared_lock<shared_mutex> lock(mtx);
}
}
void unique()
{
int cycle(0);
while (++cycle < cycles)
{
unique_lock<shared_mutex> lock(mtx);
}
}
int main()
{
boost::chrono::high_resolution_clock::duration best_time(std::numeric_limits<boost::chrono::high_resolution_clock::duration::rep>::max BOOST_PREVENT_MACRO_SUBSTITUTION ());
for (int i =100; i>0; --i) {
boost::chrono::high_resolution_clock clock;
boost::chrono::high_resolution_clock::time_point s1 = clock.now();
thread t0(shared);
thread t1(shared);
thread t2(unique);
//thread t11(shared);
//thread t12(shared);
//thread t13(shared);
t0.join();
t1.join();
t2.join();
//t11.join();
// t12.join();
// t13.join();
boost::chrono::high_resolution_clock::time_point f1 = clock.now();
//std::cout << " Time spent:" << (f1 - s1) << std::endl;
best_time = std::min BOOST_PREVENT_MACRO_SUBSTITUTION (best_time, f1 - s1);
}
std::cout << "Best Time spent:" << best_time << std::endl;
std::cout << "Time spent/cycle:" << best_time/cycles/3 << std::endl;
return 1;
}

View File

@@ -0,0 +1,127 @@
// (C) Copyright 2012 Howard Hinnant
// (C) Copyright 2012 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// adapted from the example given by Howard Hinnant in
#define BOOST_THREAD_VERSION 4
#include <iostream>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/externally_locked_stream.hpp>
#include <boost/thread/sync_queue.hpp>
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
{
using namespace boost;
try {
for(int i=0; ;++i)
{
//sbq.push(i);
sbq << i;
mos << "push(" << i << ") "<< sbq.size()<<"\n";
this_thread::sleep_for(chrono::milliseconds(200));
}
}
catch(sync_queue_is_closed&)
{
mos << "closed !!!\n";
}
catch(...)
{
mos << "exception !!!\n";
}
}
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
{
using namespace boost;
try {
for(int i=0; ;++i)
{
int r;
//sbq.pull(r);
sbq >> r;
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
catch(sync_queue_is_closed&)
{
mos << "closed !!!\n";
}
catch(...)
{
mos << "exception !!!\n";
}
}
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
{
using namespace boost;
try {
bool closed=false;
for(int i=0; ;++i)
{
int r;
sbq.pull(r, closed);
if (closed) break;
mos << i << " pull(" << r << ")\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
catch(...)
{
mos << "exception !!!\n";
}
}
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_queue<int> & sbq)
//{
// using namespace boost;
// bool closed=false;
// try {
// for(int i=0; ;++i)
// {
// int r;
// queue_op_status res = sbq.wait_and_pull(r);
// if (res==queue_op_status::closed) break;
// mos << i << " wait_and_pull(" << r << ")\n";
// this_thread::sleep_for(chrono::milliseconds(250));
// }
// }
// catch(...)
// {
// mos << "exception !!!\n";
// }
//}
int main()
{
using namespace boost;
recursive_mutex terminal_mutex;
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
sync_queue<int> sbq;
{
mcout << "begin of main" << std::endl;
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));
this_thread::sleep_for(chrono::seconds(1));
mcout << "closed()" << std::endl;
sbq.close();
mcout << "closed()" << std::endl;
} // all threads joined here.
mcout << "end of main" << std::endl;
return 0;
}

View File

@@ -0,0 +1,126 @@
// (C) Copyright 2012 Howard Hinnant
// (C) Copyright 2012 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// adapted from the example given by Howard Hinnant in
#define BOOST_THREAD_VERSION 4
#include <iostream>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/externally_locked_stream.hpp>
#include <boost/thread/sync_bounded_queue.hpp>
void producer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
{
using namespace boost;
try {
for(int i=0; ;++i)
{
//sbq.push(i);
sbq << i;
mos << "push(" << i << ") "<< sbq.size()<<"\n";
this_thread::sleep_for(chrono::milliseconds(200));
}
}
catch(sync_queue_is_closed&)
{
mos << "closed !!!\n";
}
catch(...)
{
mos << "exception !!!\n";
}
}
void consumer(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
{
using namespace boost;
try {
for(int i=0; ;++i)
{
int r;
//sbq.pull(r);
sbq >> r;
mos << i << " pull(" << r << ") "<< sbq.size()<<"\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
catch(sync_queue_is_closed&)
{
mos << "closed !!!\n";
}
catch(...)
{
mos << "exception !!!\n";
}
}
void consumer2(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
{
using namespace boost;
try {
bool closed=false;
for(int i=0; ;++i)
{
int r;
sbq.pull(r, closed);
if (closed) break;
mos << i << " pull(" << r << ")\n";
this_thread::sleep_for(chrono::milliseconds(250));
}
}
catch(...)
{
mos << "exception !!!\n";
}
}
//void consumer3(boost::externally_locked_stream<std::ostream> &mos, boost::sync_bounded_queue<int> & sbq)
//{
// using namespace boost;
// bool closed=false;
// try {
// for(int i=0; ;++i)
// {
// int r;
// queue_op_status res = sbq.wait_and_pull(r);
// if (res==queue_op_status::closed) break;
// mos << i << " wait_and_pull(" << r << ")\n";
// this_thread::sleep_for(chrono::milliseconds(250));
// }
// }
// catch(...)
// {
// mos << "exception !!!\n";
// }
//}
int main()
{
using namespace boost;
recursive_mutex terminal_mutex;
externally_locked_stream<std::ostream> mcerr(std::cerr, terminal_mutex);
externally_locked_stream<std::ostream> mcout(std::cout, terminal_mutex);
externally_locked_stream<std::istream> mcin(std::cin, terminal_mutex);
sync_bounded_queue<int> sbq(10);
{
mcout << "begin of main" << std::endl;
scoped_thread<> t11(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(boost::thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(boost::thread(consumer, boost::ref(mcout), boost::ref(sbq)));
this_thread::sleep_for(chrono::seconds(1));
sbq.close();
mcout << "closed()" << std::endl;
} // all threads joined here.
mcout << "end of main" << std::endl;
return 0;
}

View File

@@ -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 <boost/thread/recursive_mutex.hpp>
@@ -14,12 +14,12 @@ public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
boost::unique_lock<boost::recursive_mutex> scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
boost::unique_lock<boost::recursive_mutex> scoped_lock(mutex);
return add(1);
}

93
example/scoped_thread.cpp Normal file
View File

@@ -0,0 +1,93 @@
// (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 <iostream>
#include <boost/thread/scoped_thread.hpp>
void do_something(int& i)
{
++i;
}
void f(int, int)
{
}
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));
// }
{
int some_local_state;
boost::scoped_thread<> t( (boost::thread(func(some_local_state))));
if (t.joinable())
t.join();
else
do_something_in_current_thread();
}
{
int some_local_state;
boost::thread t(( func(some_local_state) ));
boost::scoped_thread<> g( (boost::move(t)) );
t.detach();
do_something_in_current_thread();
}
{
boost::scoped_thread<> g( &f, 1, 2 );
do_something_in_current_thread();
}
return 0;
}

View File

@@ -6,7 +6,8 @@
#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/lock_algorithms.hpp>
#include <boost/thread/thread_only.hpp>
#if defined BOOST_THREAD_DONT_USE_CHRONO
#include <boost/chrono/chrono_io.hpp>
#endif

View File

@@ -10,7 +10,9 @@
#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/lock_algorithms.hpp>
#include <boost/thread/thread_only.hpp>
#include <vector>
#if defined BOOST_THREAD_USES_CHRONO
#include <boost/chrono/chrono_io.hpp>

View File

@@ -4,9 +4,11 @@
// Distributed under the 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 <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#include <time.h>
@@ -23,18 +25,18 @@ public:
void get(int id)
{
boost::mutex::scoped_lock lock(m_mutex);
boost::unique_lock<boost::mutex> lock(m_mutex);
while (m_chickens == 0)
{
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> 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<boost::mutex> lk(iomx);
std::cout << "(" << clock() << ") Phil" << id <<
": those chickens look good ... one please ..." << std::endl;
}
@@ -42,20 +44,20 @@ public:
}
void put(int value)
{
boost::mutex::scoped_lock lock(m_mutex);
boost::unique_lock<boost::mutex> lock(m_mutex);
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> lk(iomx);
std::cout << "(" << clock()
<< ") Chef: ouch ... make room ... this dish is "
<< "very hot ..." << std::endl;
}
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.sec += 3;
boost::thread::sleep(xt);
m_chickens += value;
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> lk(iomx);
std::cout << "(" << clock() <<
") Chef: more chickens ... " << m_chickens <<
" now available ... NOTIFYING ..." << std::endl;
@@ -75,21 +77,21 @@ void chef()
{
const int chickens = 4;
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> lock(iomx);
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
}
for (;;)
{
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> lock(iomx);
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
}
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.sec += 2;
boost::thread::sleep(xt);
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> 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<boost::mutex> lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": starting ..." << std::endl;
}
@@ -111,18 +113,18 @@ struct phil
if (m_id > 0)
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.sec += 3;
boost::thread::sleep(xt);
}
{
boost::mutex::scoped_lock lock(iomx);
boost::unique_lock<boost::mutex> 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<boost::mutex> lk(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": mmm ... that's good ..." << std::endl;
}

40
example/strict_lock.cpp Normal file
View File

@@ -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 <boost/thread/mutex.hpp>
#include <boost/thread/lock_traits.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/strict_lock.hpp>
#include <boost/thread/lock_types.hpp>
#include <iostream>
BOOST_STATIC_ASSERT(boost::is_strict_lock<boost::strict_lock<boost::mutex> >::value);
BOOST_CONCEPT_ASSERT(( boost::BasicLockable<boost::mutex> ));
BOOST_CONCEPT_ASSERT(( boost::StrictLock<boost::strict_lock<boost::mutex> > ));
int main()
{
{
boost::mutex mtx;
boost::strict_lock<boost::mutex> lk(mtx);
std::cout << __FILE__ << std::endl;
}
{
boost::timed_mutex mtx;
boost::unique_lock<boost::timed_mutex> lk(mtx);
boost::nested_strict_lock<boost::unique_lock<boost::timed_mutex> > nlk(lk);
std::cout << __FILE__ << std::endl;
}
{
boost::mutex mtx;
boost::unique_lock<boost::mutex> lk(mtx, boost::defer_lock);
boost::nested_strict_lock<boost::unique_lock<boost::mutex> > nlk(lk);
std::cout << __FILE__ << std::endl;
}
return 0;
}

View File

@@ -0,0 +1,282 @@
// (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
#include <iostream>
#include <string>
#include <boost/thread/synchronized_value.hpp>
//class SafePerson {
//public:
// std::string GetName() const {
// const_unique_access<std::string> name(nameGuard);
// return *name;
// }
// void SetName(const std::string& newName) {
// unique_access<std::string> name(nameGuard);
// *name = newName;
// }
//private:
// unique_access_guard<std::string> nameGuard;
//};
class SafePerson {
public:
std::string GetName() const {
return *name;
}
void SetName(const std::string& newName) {
*name = newName;
}
private:
boost::synchronized_value<std::string> 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> Person_ts;
//class SafeMemberPerson {
//public:
// SafeMemberPerson(unsigned int age) :
// memberGuard(age)
// { }
// std::string GetName() const {
// const_unique_access<Member> member(memberGuard);
// return member->name;
// }
// void SetName(const std::string& newName) {
// unique_access<Member> member(memberGuard);
// member->name = newName;
// }
//private:
// struct Member
// {
// Member(unsigned int age) :
// age(age)
// { }
// std::string name;
// unsigned int age;
// };
// unique_access_guard<Member> 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> 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> Person2_ts;
//===================
//class HelperPerson {
//public:
// HelperPerson(unsigned int age) :
// memberGuard(age)
// { }
// std::string GetName() const {
// const_unique_access<Member> member(memberGuard);
// Invariant(member);
// return member->name;
// }
// void SetName(const std::string& newName) {
// unique_access<Member> member(memberGuard);
// Invariant(member);
// member->name = newName;
// }
//private:
// void Invariant(const_unique_access<Member>& 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<Member> memberGuard;
//};
class HelperPerson {
public:
HelperPerson(unsigned int age) :
member(age)
{ }
std::string GetName() const {
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
auto memberSync = member.synchronize();
#else
boost::const_strict_lock_ptr<Member> memberSync = member.synchronize();
#endif
Invariant(memberSync);
return memberSync->name;
}
void SetName(const std::string& newName) {
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
auto memberSync = member.synchronize();
#else
boost::strict_lock_ptr<Member> memberSync = member.synchronize();
#endif
Invariant(memberSync);
memberSync->name = newName;
}
private:
struct Member {
Member(unsigned int age) :
age(age)
{ }
std::string name;
unsigned int age;
};
void Invariant(boost::const_strict_lock_ptr<Member> & mbr) const
{
if (mbr->age < 1) throw std::runtime_error("Age cannot be negative");
}
boost::synchronized_value<Member> 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> 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");
}
{
Person3_ts p1(1);
Person3_ts p2(2);
Person3_ts p3(3);
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS
auto lk1 = p1.unique_synchronize(boost::defer_lock);
auto lk2 = p2.unique_synchronize(boost::defer_lock);
auto lk3 = p3.unique_synchronize(boost::defer_lock);
#else
boost::unique_lock_ptr<Person3> lk1 = p1.unique_synchronize(boost::defer_lock);
boost::unique_lock_ptr<Person3> lk2 = p2.unique_synchronize(boost::defer_lock);
boost::unique_lock_ptr<Person3> lk3 = p3.unique_synchronize(boost::defer_lock);
#endif
boost::lock(lk1,lk2,lk3);
lk1->SetName("Carmen");
lk2->SetName("Javier");
lk3->SetName("Matias");
}
#if ! defined BOOST_NO_CXX11_AUTO_DECLARATIONS \
&& ! defined(BOOST_THREAD_NO_SYNCHRONIZE)
{
Person3_ts p1(1);
Person3_ts p2(2);
Person3_ts p3(3);
auto t = boost::synchronize(p1,p2,p3);
std::get<0>(t)->SetName("Carmen");
std::get<1>(t)->SetName("Javier");
std::get<2>(t)->SetName("Matias");
}
{
const Person3_ts p1(1);
Person3_ts p2(2);
const Person3_ts p3(3);
auto t = boost::synchronize(p1,p2,p3);
//std::get<0>(t)->SetName("Carmen");
std::get<1>(t)->SetName("Javier");
//std::get<2>(t)->SetName("Matias");
}
#endif
return 0;
}

View File

@@ -0,0 +1,147 @@
// (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
#include <iostream>
#include <string>
#include <boost/thread/synchronized_value.hpp>
void addTrailingSlashIfMissing(boost::synchronized_value<std::string> & path)
{
boost::strict_lock_ptr<std::string> u=path.synchronize();
if(u->empty() || (*u->rbegin()!='/'))
{
*u+='/';
}
}
void f(const boost::synchronized_value<int> &v) {
std::cout<<"v="<<*v<<std::endl;
}
void g(const boost::const_strict_lock_ptr<int> &v) {
std::cout<<"v="<<*v<<std::endl;
}
bool checkIfMissingTrailingSlash(boost::synchronized_value<std::string> & path)
{
boost::strict_lock_ptr<std::string> u=path.synchronize();
return (u->empty() || (*u->rbegin()!='/'));
}
int main()
{
{
boost::synchronized_value<int> v1;
*v1=42;
std::cout<<"v1="<<*v1<<std::endl;
f(v1);
int i=*v1;
std::cout<<"i="<<i<<std::endl;
{
boost::strict_lock_ptr<int> u=v1.synchronize();
*u+=43;
std::cout<<"v1="<<*u<<std::endl;
g(u);
}
boost::synchronized_value<int> v2(2);
std::cout<<"v2="<<*v2<<std::endl;
v2 = 3;
std::cout<<"v2="<<*v2<<std::endl;
boost::synchronized_value<int> v3(v2);
std::cout<<"v3="<<*v3<<std::endl;
v3 = v1;
std::cout<<"v3="<<*v3<<std::endl;
std::cout<<"v2="<<*v3<<std::endl;
std::cout<<"v3="<<*v3<<std::endl;
swap(v3,v2);
v1.swap(v2);
std::cout<<"v3="<<*v3<<std::endl;
}
{
boost::synchronized_value<std::string> s;
addTrailingSlashIfMissing(s);
std::cout<<"s="<<std::string(*s)<<std::endl;
}
{
boost::synchronized_value<std::string> s;
s->append("foo/");
s.synchronize()->append("foo");
addTrailingSlashIfMissing(s);
std::cout<<"s="<<std::string(*s)<<std::endl;
}
{
boost::synchronized_value<std::string> s;
s = std::string("foo/");
std::cout<<"ss="<< s << std::endl;
}
{
boost::synchronized_value<std::string> s;
s = "foo/";
std::cout<<"ss="<< s << std::endl;
}
{
boost::synchronized_value<std::string> s1("a");
boost::synchronized_value<std::string> s2;
s2=s1;
std::cout<<"s1="<< s1 << std::endl;
std::cout<<"s2="<< s2 << std::endl;
}
{
boost::synchronized_value<std::string> s1("a");
boost::synchronized_value<std::string> s2("b");
std::cout<<"s1="<< s1 << std::endl;
std::cout<<"s2="<< s2 << std::endl;
swap(s1,s2);
std::cout<<"s1="<< s1 << std::endl;
std::cout<<"s2="<< s2 << std::endl;
}
#if ! defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
{
boost::synchronized_value<std::string> sts("a");
std::string s(sts);
std::cout<<"ssts="<< s << std::endl;
}
#endif
{
boost::synchronized_value<int> s1(1);
boost::synchronized_value<int> s2(1);
BOOST_ASSERT(s1==s2);
BOOST_ASSERT(s1<=s2);
BOOST_ASSERT(s1>=s2);
BOOST_ASSERT(s1==1);
BOOST_ASSERT(s1<=1);
BOOST_ASSERT(s1>=1);
}
{
boost::synchronized_value<int> s1(1);
boost::synchronized_value<int> s2(2);
BOOST_ASSERT(s1!=s2);
BOOST_ASSERT(s1!=2);
BOOST_ASSERT(2!=s1);
}
{
boost::synchronized_value<int> s1(1);
boost::synchronized_value<int> s2(2);
BOOST_ASSERT(s1<s2);
BOOST_ASSERT(s1<=s2);
BOOST_ASSERT(s2>s1);
BOOST_ASSERT(s2>=s1);
BOOST_ASSERT(s1<2);
BOOST_ASSERT(s1<=2);
BOOST_ASSERT(s2>1);
BOOST_ASSERT(s2>=1);
}
return 0;
}

View File

@@ -1,12 +1,15 @@
// 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)
#undef BOOST_THREAD_VERSION
#define BOOST_THREAD_VERSION 2
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
@@ -29,7 +32,7 @@ int state;
boost::mutex mutex;
boost::condition cond;
char* player_name(int state)
const char* player_name(int state)
{
if (state == PLAYER_A)
return "PLAYER-A";
@@ -39,11 +42,10 @@ char* player_name(int state)
return 0;
}
void player(void* param)
void player(int active)
{
boost::mutex::scoped_lock lock(mutex);
boost::unique_lock<boost::mutex> lock(mutex);
int active = (int)param;
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
while (state < GAME_OVER)
@@ -96,27 +98,27 @@ private:
void* _param;
};
int main(int argc, char* argv[])
int main()
{
state = START;
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
boost::thread thrda(&player, PLAYER_A);
boost::thread thrdb(&player, PLAYER_B);
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.sec += 1;
boost::thread::sleep(xt);
{
boost::mutex::scoped_lock lock(mutex);
boost::unique_lock<boost::mutex> lock(mutex);
std::cout << "---Noise ON..." << std::endl;
}
for (int i = 0; i < 1000000000; ++i)
for (int i = 0; i < 10; ++i)
cond.notify_all();
{
boost::mutex::scoped_lock lock(mutex);
boost::unique_lock<boost::mutex> lock(mutex);
std::cout << "---Noise OFF..." << std::endl;
state = GAME_OVER;
cond.notify_all();

View File

@@ -4,7 +4,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/thread.hpp>
#define BOOST_THREAD_VERSION 2
#include <boost/thread/thread_only.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
@@ -14,7 +16,7 @@ struct thread_alarm
void operator()()
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.sec += m_secs;
boost::thread::sleep(xt);

View File

@@ -6,20 +6,67 @@
#include <boost/thread/thread.hpp>
#include <iostream>
#include <boost/detail/lightweight_test.hpp>
int count = 0;
boost::mutex mutex;
void increment_count()
{
boost::mutex::scoped_lock lock(mutex);
boost::unique_lock<boost::mutex> lock(mutex);
std::cout << "count = " << ++count << std::endl;
}
boost::thread_group threads2;
boost::thread* th2 = 0;
void increment_count_2()
{
boost::unique_lock<boost::mutex> 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();
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
{
boost::thread_group threads;
for (int i = 0; i < 3; ++i)
threads.create_thread(&increment_count);
threads.interrupt_all();
threads.join_all();
}
#endif
{
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<boost::mutex> lock(mutex);
boost::thread* th2 = new boost::thread(&increment_count_2);
threads2.add_thread(th2);
}
threads2.join_all();
}
return boost::report_errors();
}

57
example/thread_guard.cpp Normal file
View File

@@ -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 <iostream>
#include <string>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/thread_guard.hpp>
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;
}

147
example/thread_pool.cpp Normal file
View File

@@ -0,0 +1,147 @@
// Copyright (C) 2012-2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_USES_LOG
#define BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/detail/log.hpp>
#include <boost/thread/thread_pool.hpp>
#include <boost/assert.hpp>
#include <string>
void p1()
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " P1" << BOOST_THREAD_END_LOG;
}
void p2()
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " P2" << BOOST_THREAD_END_LOG;
}
void push(boost::container::deque<boost::detail::function_wrapper> &data_, BOOST_THREAD_RV_REF(boost::detail::function_wrapper) closure)
{
try
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
boost::detail::function_wrapper v;
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
//v = boost::move(closure);
//v = boost::forward<boost::detail::function_wrapper>(closure);
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
data_.push_back(boost::move(closure));
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
//data_.push_back(boost::forward<boost::detail::function_wrapper>(closure));
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
}
catch (...)
{
BOOST_THREAD_LOG
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
}
}
template <typename Closure>
void submit(boost::container::deque<boost::detail::function_wrapper> &data_, BOOST_THREAD_FWD_REF(Closure) closure)
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
//work w =boost::move(closure);
//work_queue.push(boost::move(w));
//push(data_, boost::detail::function_wrapper(boost::forward<Closure>(closure)));
boost::detail::function_wrapper v =boost::forward<Closure>(closure);
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
push(data_, boost::move(v));
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
}
int main()
{
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
#if 0
{
try
{
boost::detail::function_wrapper f(&p1);
boost::container::deque<boost::detail::function_wrapper> data_;
data_.push_back(boost::move(f));
data_.push_back(boost::detail::function_wrapper(&p1));
submit(data_, &p1);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
}
catch (...)
{
BOOST_THREAD_LOG
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
}
typedef boost::container::vector<boost::thread> thread_vector;
thread_vector threads;
}
#endif
#if 1
{
try
{
boost::thread_pool tp;
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
tp.submit(&p1);
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << " <MAIN" << BOOST_THREAD_END_LOG;
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
tp.submit(&p1);
tp.submit(&p2);
}
catch (std::exception& ex)
{
BOOST_THREAD_LOG
<< "ERRORRRRR " << ex.what() << "" << BOOST_THREAD_END_LOG;
return 1;
}
catch (...)
{
BOOST_THREAD_LOG
<< " ERRORRRRR exception thrown" << BOOST_THREAD_END_LOG;
return 2;
}
}
#endif
BOOST_THREAD_LOG
<< boost::this_thread::get_id() << "MAIN>" << BOOST_THREAD_END_LOG;
return 0;
}

View File

@@ -4,13 +4,15 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/thread.hpp>
#define BOOST_THREAD_VERSION 2
#include <boost/thread/thread_only.hpp>
#include <boost/thread/xtime.hpp>
int main()
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
boost::xtime_get(&xt, boost::TIME_UTC_);
xt.sec += 1;
boost::thread::sleep(xt); // Sleep for 1 second
}

View File

@@ -0,0 +1,19 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if defined(BOOST_INTEL)
#pragma pop_macro("atomic_compare_exchange")
#pragma pop_macro("atomic_compare_exchange_explicit")
#pragma pop_macro("atomic_exchange")
#pragma pop_macro("atomic_exchange_explicit")
#pragma pop_macro("atomic_is_lock_free")
#pragma pop_macro("atomic_load")
#pragma pop_macro("atomic_load_explicit")
#pragma pop_macro("atomic_store")
#pragma pop_macro("atomic_store_explicit")
#endif // #if defined(BOOST_INTEL)

View File

@@ -0,0 +1,39 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if defined(BOOST_INTEL)
#pragma push_macro("atomic_compare_exchange")
#undef atomic_compare_exchange
#pragma push_macro("atomic_compare_exchange_explicit")
#undef atomic_compare_exchange_explicit
#pragma push_macro("atomic_exchange")
#undef atomic_exchange
#pragma push_macro("atomic_exchange_explicit")
#undef atomic_exchange_explicit
#pragma push_macro("atomic_is_lock_free")
#undef atomic_is_lock_free
#pragma push_macro("atomic_load")
#undef atomic_load
#pragma push_macro("atomic_load_explicit")
#undef atomic_load_explicit
#pragma push_macro("atomic_store")
#undef atomic_store
#pragma push_macro("atomic_store_explicit")
#undef atomic_store_explicit
#endif // #if defined(BOOST_INTEL)

View File

@@ -9,55 +9,205 @@
#define BOOST_BARRIER_JDM030602_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/throw_exception.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/condition_variable.hpp>
#include <string>
#include <stdexcept>
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
#include <boost/function.hpp>
#else
#include <functional>
#endif
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_void.hpp>
#include <boost/utility/enable_if.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace thread_detail
{
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
typedef function<void()> void_completion_function;
typedef function<size_t()> size_completion_function;
#else
typedef std::function<void()> void_completion_function;
typedef std::function<size_t()> size_completion_function;
#endif
class barrier
struct default_barrier_reseter
{
public:
barrier(unsigned int count)
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
boost::throw_exception(thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
}
bool wait()
{
boost::mutex::scoped_lock lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
while (gen == m_generation)
m_cond.wait(lock);
return false;
}
private:
mutex m_mutex;
condition_variable m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
unsigned int size_;
default_barrier_reseter(unsigned int size) :
size_(size)
{
}
unsigned int operator()()
{
return size_;
}
};
} // namespace boost
struct void_functor_barrier_reseter
{
unsigned int size_;
void_completion_function fct_;
template <typename F>
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
void_functor_barrier_reseter(unsigned int size, BOOST_THREAD_RV_REF(F) funct)
: size_(size), fct_(boost::move(funct))
{}
#else
void_functor_barrier_reseter(unsigned int size, F funct)
: size_(size), fct_(funct)
{}
#endif
unsigned int operator()()
{
fct_();
return size_;
}
};
struct void_fct_ptr_barrier_reseter
{
unsigned int size_;
void(*fct_)();
void_fct_ptr_barrier_reseter(unsigned int size, void(*funct)()) :
size_(size), fct_(funct)
{
}
unsigned int operator()()
{
fct_();
return size_;
}
};
}
class barrier
{
static inline unsigned int check_counter(unsigned int count)
{
if (count == 0) boost::throw_exception(
thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
return count;
}
struct dummy
{
};
public:
BOOST_THREAD_NO_COPYABLE( barrier)
explicit barrier(unsigned int count) :
m_count(check_counter(count)), m_generation(0), fct_(thread_detail::default_barrier_reseter(count))
{
}
template <typename F>
barrier(
unsigned int count,
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
BOOST_THREAD_RV_REF(F) funct,
#else
F funct,
#endif
typename enable_if<
typename is_void<typename result_of<F>::type>::type, dummy*
>::type=0
)
: m_count(check_counter(count)),
m_generation(0),
fct_(thread_detail::void_functor_barrier_reseter(count,
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
boost::move(funct)
#else
funct
#endif
)
)
{
}
template <typename F>
barrier(
unsigned int count,
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
BOOST_THREAD_RV_REF(F) funct,
#else
F funct,
#endif
typename enable_if<
typename is_same<typename result_of<F>::type, unsigned int>::type, dummy*
>::type=0
)
: m_count(check_counter(count)),
m_generation(0),
fct_(
#ifndef BOOST_NO_CXX11_HDR_FUNCTIONAL
boost::move(funct)
#else
funct
#endif
)
{
}
barrier(unsigned int count, void(*funct)()) :
m_count(check_counter(count)), m_generation(0),
fct_(funct
? thread_detail::size_completion_function(thread_detail::void_fct_ptr_barrier_reseter(count, funct))
: thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
)
{
}
barrier(unsigned int count, unsigned int(*funct)()) :
m_count(check_counter(count)), m_generation(0),
fct_(funct
? thread_detail::size_completion_function(funct)
: thread_detail::size_completion_function(thread_detail::default_barrier_reseter(count))
)
{
}
bool wait()
{
boost::unique_lock < boost::mutex > lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;
m_count = static_cast<unsigned int>(fct_());
BOOST_ASSERT(m_count != 0);
m_cond.notify_all();
return true;
}
while (gen == m_generation)
m_cond.wait(lock);
return false;
}
void count_down_and_wait()
{
wait();
}
private:
mutex m_mutex;
condition_variable m_cond;
unsigned int m_count;
unsigned int m_generation;
thread_detail::size_completion_function fct_;
};
} // namespace boost
#include <boost/config/abi_suffix.hpp>

View File

@@ -0,0 +1,233 @@
// Distributed under the 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 2013 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_COMPLETION_LATCH_HPP
#define BOOST_THREAD_COMPLETION_LATCH_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/counter.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/chrono/duration.hpp>
#include <boost/chrono/time_point.hpp>
#include <boost/assert.hpp>
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
#include <boost/function.hpp>
#else
#include <functional>
#endif
//#include <boost/thread/latch.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace thread_detail
{
void noop()
{
}
}
class completion_latch
{
public:
/// the implementation defined completion function type
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
typedef function<void()> completion_function;
#else
typedef std::function<void()> completion_function;
#endif
/// noop completion function factory
static completion_function noop()
{
return completion_function(&thread_detail::noop);
}
private:
struct around_wait;
friend struct around_wait;
struct around_wait
{
completion_latch &that_;
boost::unique_lock<boost::mutex> &lk_;
around_wait(completion_latch &that, boost::unique_lock<boost::mutex> &lk)
: that_(that), lk_(lk)
{
that_.leavers_.cond_.wait(lk, detail::counter_is_zero(that_.leavers_));
that_.waiters_.inc_and_notify_all();
that_.leavers_.cond_.wait(lk, detail::counter_is_not_zero(that_.leavers_));
}
~around_wait()
{
that_.waiters_.dec_and_notify_all();
}
};
bool count_down(unique_lock<mutex> &lk)
{
BOOST_ASSERT(count_ > 0);
if (--count_ == 0)
{
waiters_.cond_.wait(lk, detail::counter_is_not_zero(waiters_));
leavers_.assign_and_notify_all(waiters_);
count_.cond_.notify_all();
waiters_.cond_.wait(lk, detail::counter_is_zero(waiters_));
leavers_.assign_and_notify_all(0);
lk.unlock();
funct_();
return true;
}
return false;
}
public:
BOOST_THREAD_NO_COPYABLE( completion_latch )
/// Constructs a latch with a given count.
completion_latch(std::size_t count) :
count_(count), funct_(noop()), waiters_(0), leavers_(0)
{
}
/// Constructs a latch with a given count and a completion function.
template <typename F>
completion_latch(std::size_t count, BOOST_THREAD_RV_REF(F) funct) :
count_(count),
funct_(boost::move(funct)),
waiters_(0),
leavers_(0)
{
}
template <typename F>
completion_latch(std::size_t count, void(*funct)()) :
count_(count), funct_(funct), waiters_(0), leavers_(0)
{
}
///
~completion_latch()
{
}
/// Blocks until the latch has counted down to zero.
void wait()
{
boost::unique_lock<boost::mutex> lk(mutex_);
around_wait aw(*this, lk);
count_.cond_.wait(lk, detail::counter_is_zero(count_));
}
/// @return true if the internal counter is already 0, false otherwise
bool try_wait()
{
boost::unique_lock<boost::mutex> lk(mutex_);
around_wait aw(*this, lk);
return (count_ == 0);
}
/// try to wait for a specified amount of time
/// @return whether there is a timeout or not.
template <class Rep, class Period>
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
{
boost::unique_lock<boost::mutex> lk(mutex_);
around_wait aw(*this, lk);
return count_.cond_.wait_for(lk, rel_time, detail::counter_is_zero(count_))
? cv_status::no_timeout
: cv_status::timeout;
}
/// try to wait until the specified time_point is reached
/// @return whether there is a timeout or not.
template <class Clock, class Duration>
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<boost::mutex> lk(mutex_);
around_wait aw(*this, lk);
return count_.cond_.wait_until(lk, abs_time, detail::counter_is_zero(count_))
? cv_status::no_timeout
: cv_status::timeout;
}
/// Decrement the count and notify anyone waiting if we reach zero.
/// @Requires count must be greater than 0
void count_down()
{
unique_lock<mutex> lk(mutex_);
count_down(lk);
}
void signal()
{
count_down();
}
/// Decrement the count and notify anyone waiting if we reach zero.
/// Blocks until the latch has counted down to zero.
/// @Requires count must be greater than 0
void count_down_and_wait()
{
boost::unique_lock<boost::mutex> lk(mutex_);
if (count_down(lk))
{
return;
}
around_wait aw(*this, lk);
count_.cond_.wait(lk, detail::counter_is_zero(count_));
}
void sync()
{
count_down_and_wait();
}
/// Reset the counter
/// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
void reset(std::size_t count)
{
boost::lock_guard<boost::mutex> lk(mutex_);
//BOOST_ASSERT(count_ == 0);
count_ = count;
}
/// Resets the latch with the new completion function.
/// The next time the internal count reaches 0, this function will be invoked.
/// This completion function may only be invoked when there are no other threads
/// currently inside the count_down and wait related functions.
/// It may also be invoked from within the registered completion function.
/// @Returns the old completion function if any or noop if
#ifdef BOOST_NO_CXX11_HDR_FUNCTIONAL
template <typename F>
completion_function then(BOOST_THREAD_RV_REF(F) funct)
{
boost::lock_guard<boost::mutex> lk(mutex_);
completion_function tmp(funct_);
funct_ = boost::move(funct);
return tmp;
}
#endif
completion_function then(void(*funct)())
{
boost::lock_guard<boost::mutex> lk(mutex_);
completion_function tmp(funct_);
funct_ = completion_function(funct);
return tmp;
}
private:
mutex mutex_;
detail::counter count_;
completion_function funct_;
detail::counter waiters_;
detail::counter leavers_;
};
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -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 <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_PROVIDES_CONDITION
#include <boost/thread/condition_variable.hpp>
namespace boost
@@ -14,3 +18,4 @@ namespace boost
}
#endif
#endif

View File

@@ -0,0 +1,571 @@
// Copyright (C) 2012 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// 2013/04 Vicente J. Botet Escriba
// Provide implementation up to 9 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined.
// Make use of Boost.Move
// Make use of Boost.Tuple (movable)
// 2012/11 Vicente J. Botet Escriba
// Adapt to boost libc++ implementation
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
// The async_func code is based on the one from libcxx.
//===----------------------------------------------------------------------===//
#ifndef BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
#define BOOST_THREAD_DETAIL_ASYNC_FUNCT_HPP
#include <boost/config.hpp>
#include <boost/utility/result_of.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/detail/invoke.hpp>
#include <boost/thread/detail/make_tuple_indices.hpp>
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)
#include <tuple>
#else
#include <boost/tuple/tuple.hpp>
#endif
namespace boost
{
namespace detail
{
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)
template <class Fp, class ... Args>
class async_func
{
std::tuple<Fp, Args...> f_;
public:
BOOST_THREAD_MOVABLE_ONLY( async_func)
//typedef typename invoke_of<_Fp, _Args...>::type Rp;
typedef typename result_of<Fp(Args...)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f, BOOST_THREAD_RV_REF(Args)... args)
: f_(boost::move(f), boost::move(args)...)
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f) : f_(boost::move(f.f_))
{}
result_type operator()()
{
typedef typename make_tuple_indices<1+sizeof...(Args), 1>::type Index;
return execute(Index());
}
private:
template <size_t ...Indices>
result_type
execute(tuple_indices<Indices...>)
{
return invoke(boost::move(std::get<0>(f_)), boost::move(std::get<Indices>(f_))...);
}
};
//BOOST_THREAD_DCL_MOVABLE_BEG(X) async_func<Fp> BOOST_THREAD_DCL_MOVABLE_END
#else
template <class Fp,
class T0 = tuples::null_type, class T1 = tuples::null_type, class T2 = tuples::null_type,
class T3 = tuples::null_type, class T4 = tuples::null_type, class T5 = tuples::null_type,
class T6 = tuples::null_type, class T7 = tuples::null_type, class T8 = tuples::null_type
, class T9 = tuples::null_type
>
class async_func;
template <class Fp,
class T0 , class T1 , class T2 ,
class T3 , class T4 , class T5 ,
class T6 , class T7 , class T8 >
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
T3 v3_;
T4 v4_;
T5 v5_;
T6 v6_;
T7 v7_;
T8 v8_;
//::boost::tuple<Fp, T0, T1, T2, T3, T4, T5, T6, T7, T8> f_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7, T8)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
, BOOST_THREAD_RV_REF(T3) a3
, BOOST_THREAD_RV_REF(T4) a4
, BOOST_THREAD_RV_REF(T5) a5
, BOOST_THREAD_RV_REF(T6) a6
, BOOST_THREAD_RV_REF(T7) a7
, BOOST_THREAD_RV_REF(T8) a8
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
, v3_(boost::move(a3))
, v4_(boost::move(a4))
, v5_(boost::move(a5))
, v6_(boost::move(a6))
, v7_(boost::move(a7))
, v8_(boost::move(a8))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
, v3_(boost::move(f.a3))
, v4_(boost::move(f.a4))
, v5_(boost::move(f.a5))
, v6_(boost::move(f.a6))
, v7_(boost::move(f.a7))
, v8_(boost::move(f.a8))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
, boost::move(v3_)
, boost::move(v4_)
, boost::move(v5_)
, boost::move(v6_)
, boost::move(v7_)
, boost::move(v8_)
);
}
};
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6, class T7 >
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6, T7>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
T3 v3_;
T4 v4_;
T5 v5_;
T6 v6_;
T7 v7_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6, T7)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
, BOOST_THREAD_RV_REF(T3) a3
, BOOST_THREAD_RV_REF(T4) a4
, BOOST_THREAD_RV_REF(T5) a5
, BOOST_THREAD_RV_REF(T6) a6
, BOOST_THREAD_RV_REF(T7) a7
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
, v3_(boost::move(a3))
, v4_(boost::move(a4))
, v5_(boost::move(a5))
, v6_(boost::move(a6))
, v7_(boost::move(a7))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
, v3_(boost::move(f.a3))
, v4_(boost::move(f.a4))
, v5_(boost::move(f.a5))
, v6_(boost::move(f.a6))
, v7_(boost::move(f.a7))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
, boost::move(v3_)
, boost::move(v4_)
, boost::move(v5_)
, boost::move(v6_)
, boost::move(v7_)
);
}
};
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5, class T6>
class async_func<Fp, T0, T1, T2, T3, T4, T5, T6>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
T3 v3_;
T4 v4_;
T5 v5_;
T6 v6_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5, T6)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
, BOOST_THREAD_RV_REF(T3) a3
, BOOST_THREAD_RV_REF(T4) a4
, BOOST_THREAD_RV_REF(T5) a5
, BOOST_THREAD_RV_REF(T6) a6
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
, v3_(boost::move(a3))
, v4_(boost::move(a4))
, v5_(boost::move(a5))
, v6_(boost::move(a6))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
, v3_(boost::move(f.a3))
, v4_(boost::move(f.a4))
, v5_(boost::move(f.a5))
, v6_(boost::move(f.a6))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
, boost::move(v3_)
, boost::move(v4_)
, boost::move(v5_)
, boost::move(v6_)
);
}
};
template <class Fp, class T0, class T1, class T2, class T3, class T4, class T5>
class async_func<Fp, T0, T1, T2, T3, T4, T5>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
T3 v3_;
T4 v4_;
T5 v5_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2, T3, T4, T5)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
, BOOST_THREAD_RV_REF(T3) a3
, BOOST_THREAD_RV_REF(T4) a4
, BOOST_THREAD_RV_REF(T5) a5
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
, v3_(boost::move(a3))
, v4_(boost::move(a4))
, v5_(boost::move(a5))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
, v3_(boost::move(f.a3))
, v4_(boost::move(f.a4))
, v5_(boost::move(f.a5))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
, boost::move(v3_)
, boost::move(v4_)
, boost::move(v5_)
);
}
};
template <class Fp, class T0, class T1, class T2, class T3, class T4>
class async_func<Fp, T0, T1, T2, T3, T4>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
T3 v3_;
T4 v4_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2, T3, T4)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
, BOOST_THREAD_RV_REF(T3) a3
, BOOST_THREAD_RV_REF(T4) a4
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
, v3_(boost::move(a3))
, v4_(boost::move(a4))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
, v3_(boost::move(f.a3))
, v4_(boost::move(f.a4))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
, boost::move(v3_)
, boost::move(v4_)
);
}
};
template <class Fp, class T0, class T1, class T2, class T3>
class async_func<Fp, T0, T1, T2, T3>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
T3 v3_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2, T3)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
, BOOST_THREAD_RV_REF(T3) a3
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
, v3_(boost::move(a3))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
, v3_(boost::move(f.a3))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
, boost::move(v3_)
);
}
};
template <class Fp, class T0, class T1, class T2>
class async_func<Fp, T0, T1, T2>
{
Fp fp_;
T0 v0_;
T1 v1_;
T2 v2_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1, T2)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
, BOOST_THREAD_RV_REF(T2) a2
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
, v2_(boost::move(a2))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
, v2_(boost::move(f.a2))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
);
}
};
template <class Fp, class T0, class T1>
class async_func<Fp, T0, T1>
{
Fp fp_;
T0 v0_;
T1 v1_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0, T1)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
, BOOST_THREAD_RV_REF(T1) a1
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
, v1_(boost::move(a1))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
, v1_(boost::move(f.a1))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
);
}
};
template <class Fp, class T0>
class async_func<Fp, T0>
{
Fp fp_;
T0 v0_;
public:
BOOST_THREAD_MOVABLE_ONLY(async_func)
typedef typename result_of<Fp(T0)>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_RV_REF(Fp) f
, BOOST_THREAD_RV_REF(T0) a0
)
: fp_(boost::move(f))
, v0_(boost::move(a0))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_RV_REF(async_func) f)
: fp_(boost::move(f.fp))
, v0_(boost::move(f.a0))
{}
result_type operator()()
{
return invoke(boost::move(fp_)
, boost::move(v0_)
);
}
};
template <class Fp>
class async_func<Fp>
{
Fp fp_;
public:
BOOST_THREAD_COPYABLE_AND_MOVABLE(async_func)
typedef typename result_of<Fp()>::type result_type;
BOOST_SYMBOL_VISIBLE
explicit async_func(BOOST_THREAD_FWD_REF(Fp) f)
: fp_(boost::move(f))
{}
BOOST_SYMBOL_VISIBLE
async_func(BOOST_THREAD_FWD_REF(async_func) f)
: fp_(boost::move(f.fp_))
{}
result_type operator()()
{
return fp_();
}
};
#endif
}
}
#endif // header

View File

@@ -1,6 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2011-2012 Vicente J. Botet Escriba
// Copyright (C) 2011-2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
@@ -10,118 +10,332 @@
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/thread/detail/platform.hpp>
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
// ATTRIBUTE_MAY_ALIAS
#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 302 \
&& !defined(__INTEL_COMPILER)
// GCC since 3.3 has may_alias attribute that helps to alleviate optimizer issues with
// regard to violation of the strict aliasing rules.
#define BOOST_THREAD_DETAIL_USE_ATTRIBUTE_MAY_ALIAS
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS __attribute__((__may_alias__))
#else
#define BOOST_THREAD_ATTRIBUTE_MAY_ALIAS
#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)
#if defined __IBMCPP__ && (__IBMCPP__ < 1100) \
&& ! defined BOOST_THREAD_DONT_USE_CHRONO
#define BOOST_THREAD_DONT_USE_CHRONO
#if ! defined BOOST_THREAD_USES_DATETIME
#define BOOST_THREAD_USES_DATETIME
#endif
#endif
// This compiler doesn't support Boost.Move
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
#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
#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
#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
#if defined BOOST_NO_CXX11_UNIFIED_INITIALIZATION_SYNTAX || defined BOOST_NO_CXX11_HDR_INITIALIZER_LIST
#define BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
#define BOOST_THREAD_NO_MAKE_LOCK_GUARD
#define BOOST_THREAD_NO_MAKE_STRICT_LOCK
#define BOOST_THREAD_NO_MAKE_NESTED_STRICT_LOCK
#endif
#if defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS
#define BOOST_THREAD_NO_SYNCHRONIZE
#elif defined _MSC_VER && _MSC_VER <= 1600
// C++ features supported by VC++ 10 (aka 2010)
#define BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS
#define BOOST_THREAD_NO_SYNCHRONIZE
#endif
/// BASIC_THREAD_ID
#if ! defined BOOST_THREAD_DONT_PROVIDE_BASIC_THREAD_ID \
&& ! defined BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
#define BOOST_THREAD_PROVIDES_BASIC_THREAD_ID
#endif
// Default version is 2
/// 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
#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
// Uses Boost.System by default if not stated the opposite defining BOOST_THREAD_DONT_USE_SYSTEM
#if ! defined BOOST_THREAD_DONT_USE_SYSTEM
#define BOOST_THREAD_USES_SYSTEM
#endif
// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO or BOOST_THREAD_DONT_USE_SYSTEM
#if ! defined BOOST_THREAD_DONT_USE_CHRONO && ! defined BOOST_THREAD_DONT_USE_SYSTEM
// 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
#define BOOST_THREAD_USES_CHRONO
#endif
// Don't provided by default in version 1.
#if ! defined BOOST_THREAD_DONT_USE_ATOMIC \
&& ! defined BOOST_THREAD_USES_ATOMIC
#define BOOST_THREAD_USES_ATOMIC
//#define BOOST_THREAD_DONT_USE_ATOMIC
#endif
#if defined BOOST_THREAD_USES_ATOMIC
// Andrey Semashev
#define BOOST_THREAD_ONCE_ATOMIC
#else
//#elif ! defined BOOST_NO_CXX11_THREAD_LOCAL && ! defined BOOST_NO_THREAD_LOCAL && ! defined BOOST_THREAD_NO_UINT32_PSEUDO_ATOMIC
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html#Appendix
#define BOOST_THREAD_ONCE_FAST_EPOCH
#endif
#if BOOST_THREAD_VERSION==2
// PROVIDE_PROMISE_LAZY
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \
&& ! defined BOOST_THREAD_PROVIDES_PROMISE_LAZY
#define BOOST_THREAD_PROVIDES_PROMISE_LAZY
#endif
// 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_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
// USE_MOVE
#if ! defined BOOST_THREAD_DONT_USE_MOVE \
&& ! defined BOOST_THREAD_USES_MOVE
#define BOOST_THREAD_USES_MOVE
#endif
#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
// MAKE_READY_AT_THREAD_EXIT
#if ! defined BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT \
&& ! defined BOOST_THREAD_DONT_PROVIDE_MAKE_READY_AT_THREAD_EXIT
//#if defined BOOST_THREAD_PROVIDES_SIGNATURE_PACKAGED_TASK && defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
#define BOOST_THREAD_PROVIDES_MAKE_READY_AT_THREAD_EXIT
//#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
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_UNWRAP
#define BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
#endif
// FUTURE_INVALID_AFTER_GET
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
#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
// Uses Boost.Move by default if not stated the opposite defining BOOST_THREAD_DONT_USE_MOVE
#if ! defined BOOST_THREAD_DONT_USE_MOVE
#if ! defined BOOST_THREAD_USES_MOVE
//#define BOOST_THREAD_USES_MOVE
#endif
#endif
#if BOOST_THREAD_VERSION==2
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY
#define BOOST_THREAD_PROMISE_LAZY
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
#endif
#endif
#if BOOST_THREAD_VERSION==3
#if ! defined BOOST_THREAD_DONT_PROVIDE_ONCE_CXX11
#define BOOST_THREAD_PROVIDES_ONCE_CXX11
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
#define BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
#define BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE
#define BOOST_THREAD_PROVIDES_FUTURE
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
#define BOOST_THREAD_PROVIDES_FUTURE_CTOR_ALLOCATORS
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSIONS
#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION
#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#endif
#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
#define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
#endif
#if ! defined BOOST_THREAD_DONT_USE_MOVE
#if ! defined BOOST_THREAD_USES_MOVE
#define BOOST_THREAD_USES_MOVE
#endif
#endif
#endif
// BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \
&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#endif
// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52
// For C++11 call_once interface the compiler MUST support constexpr.
// Otherwise once_flag would be initialized during dynamic initialization stage, which is not thread-safe.
#if defined(BOOST_THREAD_PROVIDES_ONCE_CXX11)
#if defined(BOOST_NO_CXX11_CONSTEXPR)
#undef BOOST_THREAD_PROVIDES_ONCE_CXX11
#endif
#endif
#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_DATETIME
#undef BOOST_THREAD_DONT_USE_DATETIME
#define BOOST_THREAD_USES_DATETIME
#endif
#if defined(BOOST_THREAD_PLATFORM_WIN32) && defined BOOST_THREAD_DONT_USE_CHRONO
#undef BOOST_THREAD_DONT_USE_CHRONO
#define BOOST_THREAD_USES_CHRONO
#endif
// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
// BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
#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)
@@ -131,11 +345,18 @@
# pragma warn -8066 // Unreachable code
#endif
#include "platform.hpp"
#include <boost/thread/detail/platform.hpp>
#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)
#if defined(BOOST_THREAD_DYN_DLL) && ! defined BOOST_THREAD_DYN_LINK
# define BOOST_THREAD_DYN_LINK
#endif
@@ -151,8 +372,9 @@
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
#else //Use default
# if defined(BOOST_THREAD_PLATFORM_WIN32)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN) \
|| defined(__MINGW32__) || defined(MINGW32) || defined(BOOST_MINGW32)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib
# define BOOST_THREAD_USE_LIB
# else

View File

@@ -0,0 +1,106 @@
// Distributed under the 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 2013 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_COUNTER_HPP
#define BOOST_THREAD_COUNTER_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
//#include <boost/thread/mutex.hpp>
//#include <boost/thread/lock_types.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/chrono/duration.hpp>
#include <boost/chrono/time_point.hpp>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail {
struct counter
{
condition_variable cond_;
std::size_t value_;
counter(std::size_t value)
: value_(value)
{
}
counter& operator=(counter const& rhs)
{
value_ = rhs.value_;
return *this;
}
counter& operator=(std::size_t value)
{
value_ = value;
return *this;
}
operator std::size_t() const
{
return value_;
}
operator std::size_t&()
{
return value_;
}
void inc_and_notify_all()
{
++value_;
cond_.notify_all();
}
void dec_and_notify_all()
{
--value_;
cond_.notify_all();
}
void assign_and_notify_all(counter const& rhs)
{
value_ = rhs.value_;
cond_.notify_all();
}
void assign_and_notify_all(std::size_t value)
{
value_ = value;
cond_.notify_all();
}
};
struct counter_is_not_zero
{
counter_is_not_zero(counter const& count) : count_(count) {}
bool operator()() const { return count_ != 0; }
counter const& count_;
};
struct counter_is_zero
{
counter_is_zero(counter const& count) : count_(count) {}
bool operator()() const { return count_ == 0; }
counter const& count_;
};
struct is_zero
{
is_zero(std::size_t& count) : count_(count) {}
bool operator()() const { return count_ == 0; }
std::size_t& count_;
};
struct not_equal
{
not_equal(std::size_t& x, std::size_t& y) : x_(x), y_(y) {}
bool operator()() const { return x_ != y_; }
std::size_t& x_;
std::size_t& y_;
};
}
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -8,14 +8,32 @@
#include <boost/config.hpp>
#ifndef BOOST_NO_DELETED_FUNCTIONS
/**
* BOOST_THREAD_DELETE_COPY_CTOR deletes the copy constructor when the compiler supports it or
* makes it private.
*
* BOOST_THREAD_DELETE_COPY_ASSIGN deletes the copy assignment when the compiler supports it or
* makes it private.
*/
#ifndef BOOST_NO_CXX11_DELETED_FUNCTIONS
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
CLASS(CLASS const&) = delete; \
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
CLASS& operator=(CLASS const&) = delete;
#else // BOOST_NO_DELETED_FUNCTIONS
#else // BOOST_NO_CXX11_DELETED_FUNCTIONS
#if defined(BOOST_MSVC) && _MSC_VER >= 1600
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
private: \
CLASS(CLASS const&); \
public:
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
private: \
CLASS& operator=(CLASS const&); \
public:
#else
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
private: \
CLASS(CLASS&); \
@@ -25,8 +43,13 @@
private: \
CLASS& operator=(CLASS&); \
public:
#endif // BOOST_NO_DELETED_FUNCTIONS
#endif
#endif // BOOST_NO_CXX11_DELETED_FUNCTIONS
/**
* BOOST_THREAD_NO_COPYABLE deletes the copy constructor and assignment when the compiler supports it or
* makes them private.
*/
#define BOOST_THREAD_NO_COPYABLE(CLASS) \
BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS)

View File

@@ -0,0 +1,94 @@
// Copyright (C) 2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// 2013/09 Vicente J. Botet Escriba
// Adapt to boost from CCIA C++11 implementation
// Make use of Boost.Move
#ifndef BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
#define BOOST_THREAD_DETAIL_FUNCTION_WRAPPER_HPP
#include <boost/config.hpp>
#include <boost/thread/detail/memory.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
#include <memory>
#include <functional>
namespace boost
{
namespace detail
{
class function_wrapper
{
struct impl_base
{
virtual void call()=0;
virtual ~impl_base()
{
}
};
//typedef boost::interprocess::unique_ptr<impl_base, boost::default_delete<impl_base> > impl_base_type;
impl_base* impl;
template <typename F>
struct impl_type: impl_base
{
F f;
impl_type(F const &f_)
: f(f_)
{}
impl_type(BOOST_THREAD_RV_REF(F) f_)
: f(boost::move(f_))
{}
void call()
{
f();
}
};
public:
BOOST_THREAD_MOVABLE_ONLY(function_wrapper)
//#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
template<typename F>
function_wrapper(F const& f):
impl(new impl_type<F>(f))
{}
//#endif
template<typename F>
function_wrapper(BOOST_THREAD_RV_REF(F) f):
impl(new impl_type<F>(boost::forward<F>(f)))
{}
function_wrapper(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT :
impl(other.impl)
{
other.impl = 0;
}
function_wrapper()
: impl(0)
{
}
~function_wrapper()
{
delete impl;
}
function_wrapper& operator=(BOOST_THREAD_RV_REF(function_wrapper) other) BOOST_NOEXCEPT
{
impl=other.impl;
other.impl=0;
return *this;
}
void operator()()
{ impl->call();}
};
}
}
#endif // header

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,49 @@
//////////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011-2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP
#define BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP
#include <boost/type_traits/is_convertible.hpp>
#include <boost/thread/detail/move.hpp>
namespace boost
{
namespace thread_detail
{
template <typename T1, typename T2>
struct is_convertible : boost::is_convertible<T1,T2> {};
#if defined BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined(BOOST_INTEL_CXX_VERSION) && (BOOST_INTEL_CXX_VERSION <= 1300)
#if defined BOOST_THREAD_USES_MOVE
template <typename T1, typename T2>
struct is_convertible<
rv<T1> &,
rv<rv<T2> > &
> : false_type {};
#endif
#elif defined __GNUC__ && (__GNUC__ < 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ <= 4 ))
template <typename T1, typename T2>
struct is_convertible<T1&, T2&> : boost::is_convertible<T1, T2> {};
#endif
#endif
}
} // namespace boost
#endif // BOOST_THREAD_DETAIL_MEMORY_HPP

View File

@@ -0,0 +1,45 @@
// Distributed under the 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_DETAIL_LOCKABLE_WRAPPER_HPP
#define BOOST_THREAD_DETAIL_LOCKABLE_WRAPPER_HPP
#include <boost/thread/detail/config.hpp>
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
#include <initializer_list>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
#if ! defined BOOST_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
namespace thread_detail
{
template <typename Mutex>
struct lockable_wrapper
{
Mutex* m;
explicit lockable_wrapper(Mutex& m_) :
m(&m_)
{}
};
template <typename Mutex>
struct lockable_adopt_wrapper
{
Mutex* m;
explicit lockable_adopt_wrapper(Mutex& m_) :
m(&m_)
{}
};
}
#endif
}
#include <boost/config/abi_suffix.hpp>
#endif // header

View File

@@ -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 <boost/thread/detail/config.hpp>
#if defined BOOST_THREAD_USES_LOG
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#if defined BOOST_THREAD_USES_LOG_THREAD_ID
#include <boost/thread/thread.hpp>
#endif
#include <iostream>
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<boost::recursive_mutex> _lk_(boost::thread_detail::terminal_mutex()); \
std::cout << boost::this_thread::get_id() << " - "<<__FILE__<<"["<<__LINE__<<"] " <<std::dec
#else
#define BOOST_THREAD_LOG \
{ \
boost::lock_guard<boost::recursive_mutex> _lk_(boost::thread_detail::terminal_mutex()); \
std::cout << __FILE__<<"["<<__LINE__<<"] " <<std::dec
#endif
#define BOOST_THREAD_END_LOG \
std::dec << std::endl; \
}
#else
namespace boost
{
namespace thread_detail
{
struct dummy_stream_t
{
};
template <typename T>
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

View File

@@ -0,0 +1,224 @@
// Copyright (C) 2012-2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// 2013/04 Vicente J. Botet Escriba
// Provide implementation up to 10 parameters when BOOST_NO_CXX11_VARIADIC_TEMPLATES is defined.
// 2012/11 Vicente J. Botet Escriba
// Adapt to boost libc++ implementation
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.TXT for details.
//
// The make_tuple_indices C++11 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 <boost/config.hpp>
#include <boost/static_assert.hpp>
namespace boost
{
namespace detail
{
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
// make_tuple_indices
template <std::size_t...> struct tuple_indices
{};
template <std::size_t Sp, class IntTuple, std::size_t Ep>
struct make_indices_imp;
template <std::size_t Sp, std::size_t ...Indices, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<Indices...>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<Indices..., Sp>, Ep>::type type;
};
template <std::size_t Ep, std::size_t ...Indices>
struct make_indices_imp<Ep, tuple_indices<Indices...>, Ep>
{
typedef tuple_indices<Indices...> type;
};
template <std::size_t Ep, std::size_t Sp = 0>
struct make_tuple_indices
{
BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error");
typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
};
#else
// - tuple forward declaration -----------------------------------------------
template <
std::size_t T0 = 0, std::size_t T1 = 0, std::size_t T2 = 0,
std::size_t T3 = 0, std::size_t T4 = 0, std::size_t T5 = 0,
std::size_t T6 = 0, std::size_t T7 = 0, std::size_t T8 = 0,
std::size_t T9 = 0>
class tuple_indices {};
template <std::size_t Sp, class IntTuple, std::size_t Ep>
struct make_indices_imp;
template <std::size_t Sp, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
, std::size_t I7
, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, Sp>, Ep>::type type;
};
template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
, std::size_t I7
, std::size_t I8
, std::size_t Ep>
struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7, I8>, Ep>
{
typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, Sp>, Ep>::type type;
};
// template <std::size_t Sp, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
// , std::size_t I6
// , std::size_t I7
// , std::size_t I8
// , std::size_t I9
// , std::size_t Ep>
// struct make_indices_imp<Sp, tuple_indices<I0, I1 , I2, I3, I4, I5, I6, I7, I8, I9>, Ep>
// {
// typedef typename make_indices_imp<Sp+1, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9, Sp>, Ep>::type type;
// };
template <std::size_t Ep>
struct make_indices_imp<Ep, tuple_indices<>, Ep>
{
typedef tuple_indices<> type;
};
template <std::size_t Ep, std::size_t I0>
struct make_indices_imp<Ep, tuple_indices<I0>, Ep>
{
typedef tuple_indices<I0> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1>
struct make_indices_imp<Ep, tuple_indices<I0, I1>, Ep>
{
typedef tuple_indices<I0, I1> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2>, Ep>
{
typedef tuple_indices<I0, I1, I2> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3, I4> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3, I4, I5> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
, std::size_t I7
>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
, std::size_t I7
, std::size_t I8
>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8> type;
};
template <std::size_t Ep, std::size_t I0, std::size_t I1, std::size_t I2, std::size_t I3, std::size_t I4, std::size_t I5
, std::size_t I6
, std::size_t I7
, std::size_t I8
, std::size_t I9
>
struct make_indices_imp<Ep, tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9>, Ep>
{
typedef tuple_indices<I0, I1, I2, I3, I4, I5, I6, I7, I8, I9> type;
};
template <std::size_t Ep, std::size_t Sp = 0>
struct make_tuple_indices
{
BOOST_STATIC_ASSERT_MSG(Sp <= Ep, "make_tuple_indices input error");
typedef typename make_indices_imp<Sp, tuple_indices<>, Ep>::type type;
};
#endif
}
}
#endif // header

View File

@@ -1,8 +1,9 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// Copyright (C) 2011-2013 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
@@ -11,9 +12,15 @@
#ifndef BOOST_THREAD_DETAIL_MEMORY_HPP
#define BOOST_THREAD_DETAIL_MEMORY_HPP
#include <boost/config.hpp>
#include <boost/container/allocator_traits.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/config.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_scalar.hpp>
#include <boost/type_traits/is_pointer.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/static_assert.hpp>
namespace boost
{
@@ -27,7 +34,7 @@ namespace boost
typedef typename alloc_traits::pointer pointer;
typedef typename alloc_traits::size_type size_type;
private:
_Alloc& alloc_;
_Alloc alloc_;
size_type s_;
public:
allocator_destructor(_Alloc& a, size_type s)BOOST_NOEXCEPT
@@ -35,19 +42,115 @@ namespace boost
{}
void operator()(pointer p)BOOST_NOEXCEPT
{
alloc_traits::destroy(alloc_, p);
alloc_traits::deallocate(alloc_, p, s_);
}
};
} //namespace thread_detail
typedef container::allocator_arg_t allocator_arg_t;
BOOST_CONSTEXPR allocator_arg_t allocator_arg = {};
BOOST_CONSTEXPR_OR_CONST allocator_arg_t allocator_arg = {};
template <class T, class Alloc>
struct uses_allocator: public container::uses_allocator<T, Alloc>
{
};
template <class Ptr>
struct pointer_traits
{
typedef Ptr pointer;
// typedef <details> element_type;
// typedef <details> difference_type;
// template <class U> using rebind = <details>;
//
// static pointer pointer_to(<details>);
};
template <class T>
struct pointer_traits<T*>
{
typedef T* pointer;
typedef T element_type;
typedef ptrdiff_t difference_type;
// template <class U> using rebind = U*;
//
// static pointer pointer_to(<details>) noexcept;
};
namespace thread_detail {
template <class _Ptr1, class _Ptr2,
bool = is_same<typename remove_cv<typename pointer_traits<_Ptr1>::element_type>::type,
typename remove_cv<typename pointer_traits<_Ptr2>::element_type>::type
>::value
>
struct same_or_less_cv_qualified_imp
: is_convertible<_Ptr1, _Ptr2> {};
template <class _Ptr1, class _Ptr2>
struct same_or_less_cv_qualified_imp<_Ptr1, _Ptr2, false>
: false_type {};
template <class _Ptr1, class _Ptr2, bool = is_scalar<_Ptr1>::value &&
!is_pointer<_Ptr1>::value>
struct same_or_less_cv_qualified
: same_or_less_cv_qualified_imp<_Ptr1, _Ptr2> {};
template <class _Ptr1, class _Ptr2>
struct same_or_less_cv_qualified<_Ptr1, _Ptr2, true>
: false_type {};
}
template <class T>
struct BOOST_SYMBOL_VISIBLE default_delete
{
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() = default;
#else
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
#endif
template <class U>
BOOST_SYMBOL_VISIBLE
default_delete(const default_delete<U>&,
typename enable_if<is_convertible<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
BOOST_SYMBOL_VISIBLE
void operator() (T* ptr) const BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
delete ptr;
}
};
template <class T>
struct BOOST_SYMBOL_VISIBLE default_delete<T[]>
{
public:
#ifndef BOOST_NO_CXX11_DEFAULTED_FUNCTIONS
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() = default;
#else
BOOST_SYMBOL_VISIBLE
BOOST_CONSTEXPR default_delete() BOOST_NOEXCEPT {}
#endif
template <class U>
BOOST_SYMBOL_VISIBLE
default_delete(const default_delete<U[]>&,
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) BOOST_NOEXCEPT {}
template <class U>
BOOST_SYMBOL_VISIBLE
void operator() (U* ptr,
typename enable_if<thread_detail::same_or_less_cv_qualified<U*, T*> >::type* = 0) const BOOST_NOEXCEPT
{
BOOST_STATIC_ASSERT_MSG(sizeof(T) > 0, "default_delete can not delete incomplete type");
delete [] ptr;
}
};
} // namespace boost

View File

@@ -17,7 +17,8 @@
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/move/move.hpp>
#include <boost/move/utility.hpp>
#include <boost/move/traits.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
@@ -26,7 +27,7 @@ namespace boost
namespace detail
{
template <typename T>
struct has_move_emulation_enabled_aux_dummy_specialization;
struct enable_move_utility_emulation_dummy_specialization;
template<typename T>
struct thread_move_t
{
@@ -49,6 +50,7 @@ namespace boost
};
}
#if !defined BOOST_THREAD_USES_MOVE
#ifndef BOOST_NO_SFINAE
template<typename T>
@@ -63,11 +65,14 @@ namespace boost
{
return t;
}
#endif //#if !defined BOOST_THREAD_USES_MOVE
}
#if ! defined BOOST_NO_RVALUE_REFERENCES
#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 +82,17 @@ namespace boost
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
namespace detail { \
template <typename T> \
struct has_move_emulation_enabled_aux_dummy_specialization<
struct enable_move_utility_emulation_dummy_specialization<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: integral_constant<bool, true> \
: integral_constant<bool, false> \
{}; \
}
#elif ! defined BOOST_NO_RVALUE_REFERENCES && defined BOOST_MSVC
#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 +102,10 @@ namespace boost
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
namespace detail { \
template <typename T> \
struct has_move_emulation_enabled_aux_dummy_specialization<
struct enable_move_utility_emulation_dummy_specialization<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: integral_constant<bool, true> \
: integral_constant<bool, false> \
{}; \
}
@@ -107,6 +113,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 +122,10 @@ namespace boost
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
namespace detail { \
template <typename T> \
struct has_move_emulation_enabled_aux_dummy_specialization<
struct enable_move_utility_emulation_dummy_specialization<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: integral_constant<bool, true> \
: integral_constant<bool, false> \
{}; \
}
@@ -132,17 +139,19 @@ namespace boost
#define BOOST_THREAD_DCL_MOVABLE(TYPE) \
template <> \
struct has_move_emulation_enabled_aux< TYPE > \
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \
{};
struct enable_move_utility_emulation< TYPE > \
{ \
static const bool value = false; \
};
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
template <typename T> \
struct has_move_emulation_enabled_aux<
struct enable_move_utility_emulation<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true> \
{};
{ \
static const bool value = false; \
};
#endif
@@ -176,7 +185,7 @@ namespace detail
#endif
#if ! defined BOOST_NO_RVALUE_REFERENCES
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
#define BOOST_THREAD_MOVABLE(TYPE)
@@ -227,19 +236,26 @@ namespace detail
#ifndef BOOST_NO_RVALUE_REFERENCES
namespace boost
{ namespace thread_detail
{
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <class T>
typename decay<T>::type
decay_copy(T&& t)
{
return boost::forward<T>(t);
}
#else
template <class T>
typename decay<T>::type
decay_copy(BOOST_THREAD_FWD_REF(T) t)
{
return boost::forward<T>(t);
}
#endif
}
}
#endif
#include <boost/config/abi_suffix.hpp>

View File

@@ -19,7 +19,7 @@
// choose platform
#if defined(linux) || defined(__linux) || defined(__linux__)
# define BOOST_THREAD_LINUX
# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000)
//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(100000)
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
# define BOOST_THREAD_BSD
#elif defined(sun) || defined(__sun)
@@ -36,7 +36,7 @@
# define BOOST_THREAD_BEOS
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define BOOST_THREAD_MACOS
# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000)
//# define BOOST_THREAD_WAIT_BUG boost::posix_time::microseconds(1000)
#elif defined(__IBMCPP__) || defined(_AIX)
# define BOOST_THREAD_AIX
#elif defined(__amigaos__)

View File

@@ -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 <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#ifndef BOOST_NO_IOSTREAM
#include <ostream>
#endif
#include <boost/thread/detail/move.hpp>
#include <boost/thread/mutex.hpp>
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
#endif
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/thread/detail/make_tuple_indices.hpp>
#include <boost/thread/detail/invoke.hpp>
#include <boost/thread/detail/is_convertible.hpp>
#include <boost/assert.hpp>
#include <list>
#include <algorithm>
@@ -34,6 +40,9 @@
#include <boost/chrono/ceil.hpp>
#endif
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
#include <tuple>
#endif
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
@@ -46,13 +55,45 @@ namespace boost
namespace detail
{
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template<typename F, class ...ArgTypes>
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>(f_), boost::forward<ArgTypes>(args_)...)
{}
#endif
template <std::size_t ...Indices>
void run2(tuple_indices<Indices...>)
{
invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
}
void run()
{
typedef typename make_tuple_indices<std::tuple_size<std::tuple<F, ArgTypes...> >::value, 1>::type index_type;
run2(index_type());
}
private:
std::tuple<typename decay<F>::type, typename decay<ArgTypes>::type...> fp;
};
#else // defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template<typename F>
class thread_data:
public detail::thread_data_base
{
public:
BOOST_THREAD_NO_COPYABLE(thread_data)
#ifndef BOOST_NO_RVALUE_REFERENCES
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
thread_data(BOOST_THREAD_RV_REF(F) f_):
f(boost::forward<F>(f_))
{}
@@ -69,10 +110,13 @@ namespace boost
f(f_)
{}
#endif
//thread_data() {}
void run()
{
f();
}
private:
F f;
};
@@ -110,6 +154,7 @@ namespace boost
f();
}
};
#endif
}
class BOOST_THREAD_DECL thread
@@ -120,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_RVALUE_REFERENCES
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template<typename F, class ...ArgTypes>
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<typename boost::remove_reference<F>::type, ArgTypes...>
>(
boost::forward<F>(f), boost::forward<ArgTypes>(args)...
)
);
}
#else
template<typename F>
static inline detail::thread_data_ptr make_thread_info(BOOST_THREAD_RV_REF(F) f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(
boost::forward<F>(f)));
}
#endif
static inline detail::thread_data_ptr make_thread_info(void (*f)())
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(
@@ -145,7 +221,12 @@ namespace boost
}
#else
template<typename F>
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<F&,BOOST_THREAD_RV_REF(F)>::value ||
is_same<typename decay<F>::type, thread>::value,
dummy* >::type=0
)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
}
@@ -156,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)
@@ -166,6 +246,7 @@ namespace boost
thread() BOOST_NOEXCEPT;
~thread()
{
#if defined BOOST_THREAD_PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE
if (joinable()) {
std::terminate();
@@ -174,12 +255,12 @@ namespace boost
detach();
#endif
}
#ifndef BOOST_NO_RVALUE_REFERENCES
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
template <
class F
>
explicit thread(BOOST_THREAD_RV_REF(F) f
, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
//, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
):
thread_info(make_thread_info(thread_detail::decay_copy(boost::forward<F>(f))))
{
@@ -188,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>(f))))
{
start_thread(attrs);
@@ -203,7 +284,7 @@ namespace boost
start_thread();
}
template <class F>
thread(attributes& attrs, F f):
thread(attributes const& attrs, F f):
thread_info(make_thread_info(f))
{
start_thread(attrs);
@@ -211,15 +292,19 @@ namespace boost
#else
template <class F>
explicit thread(F f
// todo Disable also if Or is_same<typename decay<F>::type, thread>
, typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
, typename disable_if_c<
boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F)>::value
//|| is_same<typename decay<F>::type, thread>::value
, dummy* >::type=0
):
thread_info(make_thread_info(f))
{
start_thread();
}
template <class F>
thread(attributes& attrs, F f
, typename disable_if<boost::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0):
thread(attributes const& attrs, F f
, typename disable_if<boost::thread_detail::is_convertible<F&,BOOST_THREAD_RV_REF(F) >, dummy* >::type=0
):
thread_info(make_thread_info(f))
{
start_thread(attrs);
@@ -229,14 +314,22 @@ namespace boost
explicit thread(BOOST_THREAD_RV_REF(F) f
, typename disable_if<is_same<typename decay<F>::type, thread>, dummy* >::type=0
):
thread_info(make_thread_info(f))
#ifdef BOOST_THREAD_USES_MOVE
thread_info(make_thread_info(boost::move<F>(f))) // todo : Add forward
#else
thread_info(make_thread_info(f)) // todo : Add forward
#endif
{
start_thread();
}
template <class F>
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>(f))) // todo : Add forward
#else
thread_info(make_thread_info(f)) // todo : Add forward
#endif
{
start_thread(attrs);
}
@@ -267,8 +360,32 @@ namespace boost
return *this;
}
#if defined(BOOST_THREAD_PROVIDES_VARIADIC_THREAD)
template <class F, class Arg, class ...Args>
thread(F&& f, Arg&& arg, Args&&... args) :
thread_info(make_thread_info(
thread_detail::decay_copy(boost::forward<F>(f)),
thread_detail::decay_copy(boost::forward<Arg>(arg)),
thread_detail::decay_copy(boost::forward<Args>(args))...)
)
{
start_thread();
}
template <class F, class Arg, class ...Args>
thread(attributes const& attrs, F&& f, Arg&& arg, Args&&... args) :
thread_info(make_thread_info(
thread_detail::decay_copy(boost::forward<F>(f)),
thread_detail::decay_copy(boost::forward<Arg>(arg)),
thread_detail::decay_copy(boost::forward<Args>(args))...)
)
{
start_thread(attrs);
}
#else
template <class F,class A1>
thread(F f,A1 a1,typename disable_if<boost::is_convertible<F&,thread_attributes >, dummy* >::type=0):
thread(F f,A1 a1,typename disable_if<boost::thread_detail::is_convertible<F&,thread_attributes >, dummy* >::type=0):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
{
start_thread();
@@ -328,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;
class 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 <class Rep, class Period>
bool try_join_for(const chrono::duration<Rep, Period>& rel_time)
@@ -351,8 +476,13 @@ namespace boost
{
using namespace chrono;
system_clock::time_point s_now = system_clock::now();
typename Clock::time_point c_now = Clock::now();
return try_join_until(s_now + ceil<nanoseconds>(t - c_now));
bool joined= false;
do {
typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
joined = try_join_until(s_now + d);
} while (! joined);
return true;
}
template <class Duration>
bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
@@ -363,57 +493,72 @@ namespace boost
}
#endif
#if defined(BOOST_THREAD_PLATFORM_WIN32)
private:
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<chrono::system_clock, chrono::nanoseconds>& tp);
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
{
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
return do_try_join_until(rel_time.count());
}
#endif
public:
#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<chrono::system_clock, chrono::nanoseconds>& tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();
timespec ts;
seconds s = duration_cast<seconds>(d);
ts.tv_sec = static_cast<long>(s.count());
ts.tv_nsec = static_cast<long>((d - s).count());
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<typename TimeDuration>
inline bool timed_join(TimeDuration const& rel_time)
{
return timed_join(get_system_time()+rel_time);
}
void detach() BOOST_NOEXCEPT;
#endif
void detach();
static unsigned hardware_concurrency() BOOST_NOEXCEPT;
static unsigned physical_concurrency() BOOST_NOEXCEPT;
#define BOOST_THREAD_DEFINES_THREAD_NATIVE_HANDLE
typedef detail::thread_data_base::native_handle_type native_handle_type;
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();
@@ -423,10 +568,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
@@ -434,7 +582,7 @@ namespace boost
return lhs.swap(rhs);
}
#ifndef BOOST_NO_RVALUE_REFERENCES
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
inline thread&& move(thread& t) BOOST_NOEXCEPT
{
return static_cast<thread&&>(t);
@@ -445,16 +593,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
@@ -490,11 +646,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
@@ -572,6 +724,61 @@ 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<thread*>(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
{
inline 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() {
if (this_thread::get_id() == get_id())
boost::throw_exception(thread_resource_error(system::errc::resource_deadlock_would_occur, "boost thread: trying joining itself"));
BOOST_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
{
if (this_thread::get_id() == get_id())
boost::throw_exception(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<class charT, class traits>
BOOST_SYMBOL_VISIBLE
@@ -582,6 +789,7 @@ namespace boost
}
#endif
#if defined BOOST_THREAD_PROVIDES_THREAD_EQ
inline bool thread::operator==(const thread& other) const
{
return get_id()==other.get_id();
@@ -591,6 +799,7 @@ namespace boost
{
return get_id()!=other.get_id();
}
#endif
namespace detail
{
@@ -618,6 +827,19 @@ namespace boost
};
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
struct shared_state_base;
#if defined(BOOST_THREAD_PLATFORM_WIN32)
inline void make_ready_at_thread_exit(shared_ptr<shared_state_base> as)
{
detail::thread_data_base* const current_thread_data(detail::get_current_thread_data());
if(current_thread_data)
{
current_thread_data->make_ready_at_thread_exit(as);
}
}
#else
void BOOST_THREAD_DECL make_ready_at_thread_exit(shared_ptr<shared_state_base> as);
#endif
}
namespace this_thread

View File

@@ -8,6 +8,7 @@
#include <list>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_guard.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -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<shared_mutex> guard(m);
for(std::list<thread*>::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<shared_mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
if ((*it)->get_id() == id)
return true;
}
return false;
}
else
{
return false;
}
}
template<typename F>
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<shared_mutex> guard(m);
threads.push_back(thrd);
}
}
void remove_thread(thread* thrd)
{
boost::lock_guard<shared_mutex> 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<shared_mutex> guard(m);
for(std::list<thread*>::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<shared_mutex> guard(m);
for(std::list<thread*>::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<shared_mutex> guard(m);
return threads.size();
}
private:
std::list<thread*> threads;
mutable shared_mutex m;

View File

@@ -9,6 +9,8 @@
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#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

View File

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

View File

@@ -0,0 +1,351 @@
// (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 <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/lock_concepts.hpp>
#include <boost/thread/lock_traits.hpp>
#include <boost/thread/lockable_concepts.hpp>
#include <boost/thread/strict_lock.hpp>
#include <boost/static_assert.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/throw_exception.hpp>
#include <boost/utility/swap.hpp>
#include <boost/config/abi_prefix.hpp>
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 <typename T, typename MutexType = boost::mutex>
class externally_locked;
template <typename T, typename MutexType>
class externally_locked
{
//BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));
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.
*/
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 by moving the cloaked type.
*/
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) // BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(T()))
: obj_(), mtx_(&mtx)
{
}
/**
* Copy constructor
*/
externally_locked(externally_locked const& rhs) //BOOST_NOEXCEPT
: obj_(rhs.obj_), mtx_(rhs.mtx_)
{
}
/**
* Move constructor
*/
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) //BOOST_NOEXCEPT
: obj_(move(rhs.obj_)), mtx_(rhs.mtx_)
{
}
/// assignment
externally_locked& operator=(externally_locked const& rhs) //BOOST_NOEXCEPT
{
obj_=rhs.obj_;
mtx_=rhs.mtx_;
return *this;
}
/// move assignment
externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) // BOOST_NOEXCEPT
{
obj_=move(rhs.obj_);
mtx_=rhs.mtx_;
return *this;
}
void swap(externally_locked& rhs) //BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR)
{
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_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
*/
T& get(strict_lock<mutex_type>& 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<mutex_type>& lk) const
{
BOOST_THREAD_ASSERT_PRECONDITION( lk.owns_lock(mtx_), lock_error() ); /*< run time check throw if not locks the same >*/
return obj_;
}
template <class Lock>
T& get(nested_strict_lock<Lock>& lk)
{
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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 <class Lock>
const T& get(nested_strict_lock<Lock>& lk) const
{
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
*/
template <class Lock>
T& get(Lock& lk)
{
BOOST_CONCEPT_ASSERT(( StrictLock<Lock> ));
BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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_;
}
mutex_type* mutex() const BOOST_NOEXCEPT
{
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<T&,M> 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 <typename T, typename MutexType>
class externally_locked<T&, MutexType>
{
//BOOST_CONCEPT_ASSERT(( CopyConstructible<T> ));
BOOST_CONCEPT_ASSERT(( BasicLockable<MutexType> ));
public:
typedef MutexType mutex_type;
BOOST_THREAD_COPYABLE_AND_MOVABLE( externally_locked )
/**
* Effects: Constructs an externally locked object storing the cloaked reference object.
*/
externally_locked(T& obj, mutex_type& mtx) BOOST_NOEXCEPT :
obj_(&obj), mtx_(&mtx)
{
}
/// copy constructor
externally_locked(externally_locked const& rhs) BOOST_NOEXCEPT :
obj_(rhs.obj_), mtx_(rhs.mtx_)
{
}
/// move constructor
externally_locked(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT :
obj_(rhs.obj_), mtx_(rhs.mtx_)
{
}
/// assignment
externally_locked& operator=(externally_locked const& rhs) BOOST_NOEXCEPT
{
obj_=rhs.obj_;
mtx_=rhs.mtx_;
return *this;
}
/// move assignment
externally_locked& operator=(BOOST_THREAD_RV_REF(externally_locked) rhs) BOOST_NOEXCEPT
{
obj_=rhs.obj_;
mtx_=rhs.mtx_;
return *this;
}
void swap(externally_locked& rhs) BOOST_NOEXCEPT
{
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_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
*/
T& get(strict_lock<mutex_type> 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<mutex_type> 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 <class Lock>
T& get(nested_strict_lock<Lock> const& lk)
{
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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 <class Lock>
const T& get(nested_strict_lock<Lock> const& lk) const
{
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
*/
template <class Lock>
T& get(Lock const& lk)
{
BOOST_CONCEPT_ASSERT(( StrictLock<Lock> ));
BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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_THROW_IF_PRECONDITION_NOT_SATISFIED is not defined and the lk parameter doesn't satisfy the preconditions
*/
template <class Lock>
T const& get(Lock const& lk) const
{
BOOST_CONCEPT_ASSERT(( StrictLock<Lock> ));
BOOST_STATIC_ASSERT( (is_strict_lock<Lock>::value)); /*< lk is a strict lock "sur parolle" >*/
BOOST_STATIC_ASSERT( (is_same<mutex_type, typename Lock::mutex_type>::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_;
}
mutex_type* mutex() const BOOST_NOEXCEPT
{
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 <typename T, typename MutexType>
void swap(externally_locked<T, MutexType> & lhs, externally_locked<T, MutexType> & rhs) // BOOST_NOEXCEPT
{
lhs.swap(rhs);
}
}
#include <boost/config/abi_suffix.hpp>
#endif // header

View File

@@ -0,0 +1,170 @@
// (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_STREAM_HPP
#define BOOST_THREAD_EXTERNALLY_LOCKED_STREAM_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/externally_locked.hpp>
#include <boost/thread/lock_traits.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/strict_lock.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
template <typename Stream, typename RecursiveMutex=recursive_mutex>
class externally_locked_stream;
template <class Stream, typename RecursiveMutex=recursive_mutex>
class stream_guard
{
friend class externally_locked_stream<Stream, RecursiveMutex> ;
public:
typedef typename externally_locked_stream<Stream, RecursiveMutex>::mutex_type mutex_type;
BOOST_THREAD_MOVABLE_ONLY( stream_guard)
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx) :
mtx_(&mtx)
{
mtx.lock();
}
stream_guard(externally_locked_stream<Stream, RecursiveMutex>& mtx, adopt_lock_t) :
mtx_(&mtx)
{
}
stream_guard(BOOST_THREAD_RV_REF(stream_guard) rhs) BOOST_NOEXCEPT
: mtx_(rhs.mtx_)
{
rhs.mtx_= 0;
}
~stream_guard()
{
if (mtx_ != 0) mtx_->unlock();
}
bool owns_lock(const mutex_type * l) const BOOST_NOEXCEPT
{
return l == mtx_->mutex();
}
/**
* @Requires mtx_
*/
Stream& get() const
{
BOOST_THREAD_ASSERT_PRECONDITION( mtx_, lock_error() );
return mtx_->get(*this);
}
Stream& bypass() const
{
return get();
}
private:
externally_locked_stream<Stream, RecursiveMutex>* mtx_;
};
template <typename Stream, typename RecursiveMutex>
struct is_strict_lock_sur_parole<stream_guard<Stream, RecursiveMutex> > : true_type
{
};
/**
* externally_locked_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 <typename Stream, typename RecursiveMutex>
class externally_locked_stream: public externally_locked<Stream&, RecursiveMutex>
{
typedef externally_locked<Stream&, RecursiveMutex> base_type;
public:
BOOST_THREAD_NO_COPYABLE( externally_locked_stream)
/**
* Effects: Constructs an externally locked object storing the cloaked reference object.
*/
externally_locked_stream(Stream& stream, RecursiveMutex& mtx) BOOST_NOEXCEPT :
base_type(stream, mtx)
{
}
stream_guard<Stream, RecursiveMutex> hold() BOOST_NOEXCEPT
{
return stream_guard<Stream, RecursiveMutex> (*this);
}
Stream& bypass() const
{
stream_guard<Stream, RecursiveMutex> lk(*this);
return get(lk);
}
};
//]
template <typename Stream, typename RecursiveMutex, typename T>
inline const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, T arg)
{
lck.get() << arg;
return lck;
}
template <typename Stream, typename RecursiveMutex>
inline const stream_guard<Stream, RecursiveMutex>& operator<<(const stream_guard<Stream, RecursiveMutex>& lck, Stream& (*arg)(Stream&))
{
lck.get() << arg;
return lck;
}
template <typename Stream, typename RecursiveMutex, typename T>
inline const stream_guard<Stream, RecursiveMutex>& operator>>(const stream_guard<Stream, RecursiveMutex>& lck, T& arg)
{
lck.get() >> arg;
return lck;
}
template <typename Stream, typename RecursiveMutex, typename T>
inline stream_guard<Stream, RecursiveMutex> operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, T arg)
{
stream_guard<Stream, RecursiveMutex> lk(mtx);
mtx.get(lk) << arg;
return boost::move(lk);
}
template <typename Stream, typename RecursiveMutex>
inline stream_guard<Stream, RecursiveMutex> operator<<(externally_locked_stream<Stream, RecursiveMutex>& mtx, Stream& (*arg)(Stream&))
{
stream_guard<Stream, RecursiveMutex> lk(mtx);
mtx.get(lk) << arg;
return boost::move(lk);
}
template <typename Stream, typename RecursiveMutex, typename T>
inline stream_guard<Stream, RecursiveMutex> operator>>(externally_locked_stream<Stream, RecursiveMutex>& mtx, T& arg)
{
stream_guard<Stream, RecursiveMutex> lk(mtx);
mtx.get(lk) >> arg;
return boost::move(lk);
}
}
#include <boost/config/abi_suffix.hpp>
#endif // header

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,61 @@
// (C) Copyright 2008-10 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THREAD_FUTURE_ERROR_CODE_HPP
#define BOOST_THREAD_FUTURE_ERROR_CODE_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/detail/scoped_enum_emulation.hpp>
#include <boost/system/error_code.hpp>
#include <boost/type_traits/integral_constant.hpp>
namespace boost
{
//enum class future_errc
BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
{
broken_promise = 1,
future_already_retrieved,
promise_already_satisfied,
no_state
}
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
namespace system
{
template <>
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type {};
#ifdef BOOST_NO_CXX11_SCOPED_ENUMS
template <>
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
#endif
} // system
BOOST_THREAD_DECL
const system::error_category& future_category() BOOST_NOEXCEPT;
namespace system
{
inline
error_code
make_error_code(future_errc e) BOOST_NOEXCEPT
{
return error_code(underlying_cast<int>(e), boost::future_category());
}
inline
error_condition
make_error_condition(future_errc e) BOOST_NOEXCEPT
{
return error_condition(underlying_cast<int>(e), future_category());
}
} // system
} // boost
#endif // header

View File

@@ -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 <boost/thread/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
template <typename Lockable>
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 <typename Lockable>
bool is_locked_by_this_thread(testable_mutex<Lockable> const& mtx)
{
return mtx.is_locked_by_this_thread();
}
template <typename Lockable>
bool is_locked_by_this_thread(Lockable const&)
{
return true;
}
}
#include <boost/config/abi_suffix.hpp>
#endif // header

View File

@@ -0,0 +1,167 @@
// Distributed under the 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 2013 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_LATCH_HPP
#define BOOST_THREAD_LATCH_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/counter.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/chrono/duration.hpp>
#include <boost/chrono/time_point.hpp>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class latch
{
/// @Requires: count_ must be greater than 0
/// Effect: Decrement the count. Unlocks the lock and notify anyone waiting if we reached zero.
/// Returns: true if count_ reached the value 0.
/// @ThreadSafe ensured by the @c lk parameter
bool count_down(unique_lock<mutex> &lk)
/// pre_condition (count_ > 0)
{
BOOST_ASSERT(count_ > 0);
if (--count_ == 0)
{
++generation_;
lk.unlock();
cond_.notify_all();
return true;
}
return false;
}
/// Effect: Decrement the count is > 0. Unlocks the lock notify anyone waiting if we reached zero.
/// Returns: true if count_ is 0.
/// @ThreadSafe ensured by the @c lk parameter
bool try_count_down(unique_lock<mutex> &lk)
{
if (count_ > 0)
{
return count_down(lk);
}
return true;
}
public:
BOOST_THREAD_NO_COPYABLE( latch)
/// Constructs a latch with a given count.
latch(std::size_t count) :
count_(count), generation_(0)
{
}
/// Destructor
/// Precondition: No threads are waiting or invoking count_down on @c *this.
~latch()
{
}
/// Blocks until the latch has counted down to zero.
void wait()
{
boost::unique_lock<boost::mutex> lk(mutex_);
std::size_t generation(generation_);
cond_.wait(lk, detail::not_equal(generation, generation_));
}
/// @return true if the internal counter is already 0, false otherwise
bool try_wait()
{
boost::unique_lock<boost::mutex> lk(mutex_);
return (count_ == 0);
}
/// try to wait for a specified amount of time is elapsed.
/// @return whether there is a timeout or not.
template <class Rep, class Period>
cv_status wait_for(const chrono::duration<Rep, Period>& rel_time)
{
boost::unique_lock<boost::mutex> lk(mutex_);
std::size_t generation(generation_);
return cond_.wait_for(lk, rel_time, detail::not_equal(generation, generation_))
? cv_status::no_timeout
: cv_status::timeout;
}
/// try to wait until the specified time_point is reached
/// @return whether there were a timeout or not.
template <class Clock, class Duration>
cv_status wait_until(const chrono::time_point<Clock, Duration>& abs_time)
{
boost::unique_lock<boost::mutex> lk(mutex_);
std::size_t generation(generation_);
return cond_.wait_until(lk, abs_time, detail::not_equal(generation, generation_))
? cv_status::no_timeout
: cv_status::timeout;
}
/// Decrement the count and notify anyone waiting if we reach zero.
/// @Requires count must be greater than 0
void count_down()
{
boost::unique_lock<boost::mutex> lk(mutex_);
count_down(lk);
}
/// Effect: Decrement the count if it is > 0 and notify anyone waiting if we reached zero.
/// Returns: true if count_ was 0 or reached 0.
bool try_count_down()
{
boost::unique_lock<boost::mutex> lk(mutex_);
return try_count_down(lk);
}
void signal()
{
count_down();
}
/// Decrement the count and notify anyone waiting if we reach zero.
/// Blocks until the latch has counted down to zero.
/// @Requires count must be greater than 0
void count_down_and_wait()
{
boost::unique_lock<boost::mutex> lk(mutex_);
std::size_t generation(generation_);
if (count_down(lk))
{
return;
}
cond_.wait(lk, detail::not_equal(generation, generation_));
}
void sync()
{
count_down_and_wait();
}
/// Reset the counter
/// #Requires This method may only be invoked when there are no other threads currently inside the count_down_and_wait() method.
void reset(std::size_t count)
{
boost::lock_guard<boost::mutex> lk(mutex_);
//BOOST_ASSERT(count_ == 0);
count_ = count;
}
private:
mutex mutex_;
condition_variable cond_;
std::size_t count_;
std::size_t generation_;
};
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -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 <boost/thread/detail/config.hpp>
#include <boost/thread/lock_types.hpp>
#include <boost/thread/lockable_traits.hpp>
#include <algorithm>
#include <iterator>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
template <typename MutexType1, typename MutexType2>
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2)
{
boost::unique_lock<MutexType1> l1(m1, boost::try_to_lock);
if (!l1)
{
return 1;
}
if (!m2.try_lock())
{
return 2;
}
l1.release();
return 0;
}
template <typename MutexType1, typename MutexType2, typename MutexType3>
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3)
{
boost::unique_lock<MutexType1> 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 <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
{
boost::unique_lock<MutexType1> 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 <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
unsigned try_lock_internal(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5)
{
boost::unique_lock<MutexType1> 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 <typename MutexType1, typename MutexType2>
unsigned lock_helper(MutexType1& m1, MutexType2& m2)
{
boost::unique_lock<MutexType1> l1(m1);
if (!m2.try_lock())
{
return 1;
}
l1.release();
return 0;
}
template <typename MutexType1, typename MutexType2, typename MutexType3>
unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3)
{
boost::unique_lock<MutexType1> l1(m1);
if (unsigned const failed_lock=try_lock_internal(m2,m3))
{
return failed_lock;
}
l1.release();
return 0;
}
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
{
boost::unique_lock<MutexType1> l1(m1);
if (unsigned const failed_lock=try_lock_internal(m2,m3,m4))
{
return failed_lock;
}
l1.release();
return 0;
}
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
unsigned lock_helper(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4, MutexType5& m5)
{
boost::unique_lock<MutexType1> l1(m1);
if (unsigned const failed_lock=try_lock_internal(m2,m3,m4,m5))
{
return failed_lock;
}
l1.release();
return 0;
}
}
namespace detail
{
template <bool x>
struct is_mutex_type_wrapper
{
};
template <typename MutexType1, typename MutexType2>
void lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper<true> )
{
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 <typename Iterator>
void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> );
}
template <typename MutexType1, typename MutexType2>
void lock(MutexType1& m1, MutexType2& m2)
{
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2>
void lock(const MutexType1& m1, MutexType2& m2)
{
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2>
void lock(MutexType1& m1, const MutexType2& m2)
{
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2>
void lock(const MutexType1& m1, const MutexType2& m2)
{
detail::lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2, typename MutexType3>
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 <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
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 <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
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 <typename Mutex, bool x = is_mutex_type<Mutex>::value>
struct try_lock_impl_return
{
typedef int type;
};
template <typename Iterator>
struct try_lock_impl_return<Iterator, false>
{
typedef Iterator type;
};
template <typename MutexType1, typename MutexType2>
int try_lock_impl(MutexType1& m1, MutexType2& m2, is_mutex_type_wrapper<true> )
{
return ((int) detail::try_lock_internal(m1, m2)) - 1;
}
template <typename Iterator>
Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> );
}
template <typename MutexType1, typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1, MutexType2& m2)
{
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1, MutexType2& m2)
{
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1, const MutexType2& m2)
{
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2>
typename detail::try_lock_impl_return<MutexType1>::type try_lock(const MutexType1& m1, const MutexType2& m2)
{
return detail::try_lock_impl(m1, m2, detail::is_mutex_type_wrapper<is_mutex_type<MutexType1>::value>());
}
template <typename MutexType1, typename MutexType2, typename MutexType3>
int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3)
{
return ((int) detail::try_lock_internal(m1, m2, m3)) - 1;
}
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4>
int try_lock(MutexType1& m1, MutexType2& m2, MutexType3& m3, MutexType4& m4)
{
return ((int) detail::try_lock_internal(m1, m2, m3, m4)) - 1;
}
template <typename MutexType1, typename MutexType2, typename MutexType3, typename MutexType4, typename MutexType5>
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 <typename Iterator>
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 <typename Iterator>
Iterator try_lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> )
{
if (begin == end)
{
return end;
}
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
unique_lock<lock_type> 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 <typename Iterator>
void lock_impl(Iterator begin, Iterator end, is_mutex_type_wrapper<false> )
{
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
if (begin == end)
{
return;
}
bool start_with_begin = true;
Iterator second = begin;
++second;
Iterator next = second;
for (;;)
{
unique_lock<lock_type> 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<Iterator> 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 <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,197 @@
// (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 <boost/thread/lock_traits.hpp>
#include <boost/thread/lock_options.hpp>
#include <boost/thread/lockable_concepts.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/chrono/chrono.hpp>
#include <boost/concept_check.hpp>
#include <boost/static_assert.hpp>
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 <typename Lk>
struct BasicLock
{
typedef typename Lk::mutex_type mutex_type;
void cvt_mutex_ptr(mutex_type*) {}
BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> ));
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<mutex_type*>(0))
{}
private:
BasicLock operator=(BasicLock const&);
mutex_type& mtx;
}
;
template <typename Lk>
struct Lock
{
BOOST_CONCEPT_ASSERT(( BasicLock<Lk> ));
typedef typename Lk::mutex_type mutex_type;
BOOST_CONCEPT_ASSERT(( Lockable<mutex_type> ));
BOOST_CONCEPT_USAGE(Lock)
{
Lk l1(mtx, try_to_lock);
if (l1.try_lock()) return;
}
Lock() :
mtx(*static_cast<mutex_type*>(0))
{}
private:
Lock operator=(Lock const&);
mutex_type& mtx;
};
template <typename Lk>
struct TimedLock
{
BOOST_CONCEPT_ASSERT(( Lock<Lk> ));
typedef typename Lk::mutex_type mutex_type;
BOOST_CONCEPT_ASSERT(( TimedLockable<mutex_type> ));
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<mutex_type*>(0))
{}
private:
TimedLock operator=(TimedLock const&);
mutex_type& mtx;
boost::chrono::system_clock::time_point t;
boost::chrono::system_clock::duration d;
};
template <typename Lk>
struct UniqueLock
{
BOOST_CONCEPT_ASSERT(( TimedLock<Lk> ));
typedef typename Lk::mutex_type mutex_type;
BOOST_CONCEPT_USAGE(UniqueLock)
{
}
UniqueLock() :
mtx(*static_cast<mutex_type*>(0))
{}
private:
UniqueLock operator=(UniqueLock const&);
mutex_type& mtx;
};
template <typename Lk>
struct SharedLock
{
BOOST_CONCEPT_ASSERT(( TimedLock<Lk> ));
typedef typename Lk::mutex_type mutex_type;
BOOST_CONCEPT_USAGE(SharedLock)
{
}
SharedLock() :
mtx(*static_cast<mutex_type*>(0))
{}
private:
SharedLock operator=(SharedLock const&);
mutex_type& mtx;
};
template <typename Lk>
struct UpgradeLock
{
BOOST_CONCEPT_ASSERT(( SharedLock<Lk> ));
typedef typename Lk::mutex_type mutex_type;
BOOST_CONCEPT_USAGE(UpgradeLock)
{
}
UpgradeLock() :
mtx(*static_cast<mutex_type*>(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 <typename Lk>
struct StrictLock
{
typedef typename Lk::mutex_type mutex_type;
BOOST_CONCEPT_ASSERT(( BasicLockable<mutex_type> ));
BOOST_STATIC_ASSERT(( is_strict_lock<Lk>::value ));
BOOST_CONCEPT_USAGE( StrictLock)
{
if (l1.owns_lock(&mtx)) return;
}
StrictLock() :
l1(*static_cast<Lk*>(0)),
mtx(*static_cast<mutex_type*>(0))
{}
private:
StrictLock operator=(StrictLock const&);
Lk const& l1;
mutex_type const& mtx;
};
}
#endif

View File

@@ -0,0 +1,78 @@
// Distributed under the 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 <boost/thread/lock_types.hpp>
#include <boost/thread/lock_algorithms.hpp>
#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
#include <tuple> // todo change to <boost/tuple.hpp> once Boost.Tuple or Boost.Fusion provides Move semantics.
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx)
{
return unique_lock<Lockable> (mtx);
}
template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx, adopt_lock_t)
{
return unique_lock<Lockable> (mtx, adopt_lock);
}
template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx, defer_lock_t)
{
return unique_lock<Lockable> (mtx, defer_lock);
}
template <typename Lockable>
unique_lock<Lockable> make_unique_lock(Lockable& mtx, try_to_lock_t)
{
return unique_lock<Lockable> (mtx, try_to_lock);
}
#if ! defined(BOOST_THREAD_NO_MAKE_UNIQUE_LOCKS)
#if ! defined BOOST_NO_CXX11_VARIADIC_TEMPLATES
template <typename ...Lockable>
std::tuple<unique_lock<Lockable> ...> make_unique_locks(Lockable& ...mtx)
{
boost::lock(mtx...);
return std::tuple<unique_lock<Lockable> ...>(unique_lock<Lockable>(mtx, adopt_lock)...);
}
#else
template <typename L1, typename L2>
std::tuple<unique_lock<L1>, unique_lock<L2> > make_unique_locks(L1& m1, L2& m2)
{
boost::lock(m1, m2);
return std::tuple<unique_lock<L1>,unique_lock<L2> >(
unique_lock<L1>(m1, adopt_lock),
unique_lock<L2>(m2, adopt_lock)
);
}
template <typename L1, typename L2, typename L3>
std::tuple<unique_lock<L1>, unique_lock<L2>, unique_lock<L3> > make_unique_locks(L1& m1, L2& m2, L3& m3)
{
boost::lock(m1, m2, m3);
return std::tuple<unique_lock<L1>,unique_lock<L2>,unique_lock<L3> >(
unique_lock<L1>(m1, adopt_lock),
unique_lock<L2>(m2, adopt_lock),
unique_lock<L3>(m3, adopt_lock)
);
}
#endif
#endif
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,88 @@
// Distributed under the 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 <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/detail/lockable_wrapper.hpp>
#include <boost/thread/lock_options.hpp>
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS
#include <boost/thread/is_locked_by_this_thread.hpp>
#include <boost/assert.hpp>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
template <typename Mutex>
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_THREAD_NO_CXX11_HDR_INITIALIZER_LIST
lock_guard(std::initializer_list<thread_detail::lockable_wrapper<Mutex> > l_) :
m(*(const_cast<thread_detail::lockable_wrapper<Mutex>*>(l_.begin())->m))
{
m.lock();
}
lock_guard(std::initializer_list<thread_detail::lockable_adopt_wrapper<Mutex> > l_) :
m(*(const_cast<thread_detail::lockable_adopt_wrapper<Mutex>*>(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_THREAD_NO_MAKE_LOCK_GUARD
template <typename Lockable>
lock_guard<Lockable> make_lock_guard(Lockable& mtx)
{
return { thread_detail::lockable_wrapper<Lockable>(mtx) };
}
template <typename Lockable>
lock_guard<Lockable> make_lock_guard(Lockable& mtx, adopt_lock_t)
{
return { thread_detail::lockable_adopt_wrapper<Lockable>(mtx) };
}
#endif
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -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 <boost/config/abi_prefix.hpp>
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 <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,45 @@
// Distributed under the 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 <boost/thread/detail/config.hpp>
//#include <boost/thread/detail/move.hpp>
//#include <boost/thread/exceptions.hpp>
//
//#ifdef BOOST_THREAD_USES_CHRONO
//#include <boost/chrono/time_point.hpp>
//#include <boost/chrono/duration.hpp>
//#endif
#include <boost/type_traits/integral_constant.hpp>
#include <boost/config/abi_prefix.hpp>
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 parole".
*/
template <typename Lock>
struct is_strict_lock_sur_parolle : false_type {};
template <typename Lock>
struct is_strict_lock_sur_parole : is_strict_lock_sur_parolle<Lock> {};
template <typename Lock>
struct is_strict_lock : is_strict_lock_sur_parole<Lock> {};
}
#include <boost/config/abi_suffix.hpp>
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -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 <boost/thread/detail/delete.hpp>
#include <boost/chrono/chrono.hpp>
namespace boost
{
//[basic_lockable_adapter
template <typename BasicLockable>
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 <typename Lockable>
class lockable_adapter : public basic_lockable_adapter<Lockable>
{
public:
typedef Lockable mutex_type;
bool try_lock()
{
return this->lockable().try_lock();
}
};
//]
//[timed_lockable_adapter
template <typename TimedLock>
class timed_lockable_adapter: public lockable_adapter<TimedLock>
{
public:
typedef TimedLock mutex_type;
template <typename Clock, typename Duration>
bool try_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return this->lockable().try_lock_until(abs_time);
}
template <typename Rep, typename Period>
bool try_lock_for(chrono::duration<Rep, Period> const & rel_time)
{
return this->lockable().try_lock_for(rel_time);
}
};
//]
//[shared_lockable_adapter
template <typename SharableLock>
class shared_lockable_adapter: public timed_lockable_adapter<SharableLock>
{
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 <typename Clock, typename Duration>
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return this->lockable().try_lock_shared_until(abs_time);
}
template <typename Rep, typename Period>
bool try_lock_shared_for(chrono::duration<Rep, Period> const & rel_time)
{
return this->lockable().try_lock_shared_for(rel_time);
}
};
//]
//[upgrade_lockable_adapter
template <typename UpgradableLock>
class upgrade_lockable_adapter: public shared_lockable_adapter<UpgradableLock>
{
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 <typename Clock, typename Duration>
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return this->lockable().try_lock_upgrade_until(abs_time);
}
template <typename Rep, typename Period>
bool try_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
{
return this->lockable().try_lock_upgrade_for(rel_time);
}
bool try_unlock_shared_and_lock()
{
return this->lockable().try_unlock_shared_and_lock();
}
template <typename Clock, typename Duration>
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return this->lockable().try_unlock_shared_and_lock_until(abs_time);
}
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
{
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 <typename Clock, typename Duration>
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return this->lockable().try_unlock_shared_and_lock_upgrade_until(abs_time);
}
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> const & rel_time)
{
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 <typename Clock, typename Duration>
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const & abs_time)
{
return this->lockable().try_unlock_upgrade_and_lock_until(abs_time);
}
template <typename Rep, typename Period>
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const & rel_time)
{
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

View File

@@ -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 <boost/chrono/chrono.hpp>
#include <boost/concept_check.hpp>
namespace boost
{
/**
* BasicLockable object supports the basic features
* required to delimit a critical region
* Supports the basic lock and unlock functions.
*/
//[BasicLockable
template <typename Mutex>
struct BasicLockable
{
BOOST_CONCEPT_USAGE(BasicLockable)
{
l.lock();
l.unlock();
}
BasicLockable() : l(*static_cast<Mutex*>(0)) {}
private:
BasicLockable operator=(BasicLockable const&);
Mutex& l;
}
;
//]
/**
* Lockable extends BasicLockable
* with try_lock functions.
*/
//[Lockable
template <typename Mutex>
struct Lockable
{
BOOST_CONCEPT_ASSERT(( BasicLockable<Mutex> ));
BOOST_CONCEPT_USAGE(Lockable)
{
if (l.try_lock()) return;
}
Lockable() : l(*static_cast<Mutex*>(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 <typename Mutex>
struct TimedLockable
{
BOOST_CONCEPT_ASSERT(( Lockable<Mutex> ));
BOOST_CONCEPT_USAGE(TimedLockable)
{
if (l.try_lock_until(t)) return;
if (l.try_lock_for(d)) return;
}
TimedLockable() : l(*static_cast<Mutex*>(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 <typename Mutex>
struct SharedLockable
{
BOOST_CONCEPT_ASSERT(( TimedLockable<Mutex> ));
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<Mutex*>(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 <typename Mutex>
struct UpgradeLockable
{
BOOST_CONCEPT_ASSERT(( SharedLockable<Mutex> ));
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<Mutex*>(0)) {}
private:
UpgradeLockable operator=(UpgradeLockable const&);
Mutex& l;
chrono::system_clock::time_point t;
chrono::system_clock::duration d;
};
//]
}
#endif

View File

@@ -0,0 +1,207 @@
// Distributed under the 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 <boost/thread/detail/config.hpp>
#include <boost/assert.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/type_traits/is_class.hpp>
#include <boost/config/abi_prefix.hpp>
// 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<typename T, bool=boost::is_class<T>::value> \
struct has_member_called_##member_name \
{ \
BOOST_STATIC_CONSTANT(bool, value=false); \
}; \
\
template<typename T> \
struct has_member_called_##member_name<T,true> \
{ \
typedef char true_type; \
struct false_type \
{ \
true_type dummy[2]; \
}; \
\
struct fallback { int member_name; }; \
struct derived: \
T, fallback \
{ \
derived(); \
}; \
\
template<int fallback::*> struct tester; \
\
template<typename U> \
static false_type has_member(tester<&U::member_name>*); \
template<typename U> \
static true_type has_member(...); \
\
BOOST_STATIC_CONSTANT( \
bool, value=sizeof(has_member<derived>(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<typename T,bool=has_member_called_lock<T>::value >
struct has_member_lock
{
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct has_member_lock<T,true>
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U,typename V>
static true_type has_member(V (U::*)());
template<typename U>
static false_type has_member(U);
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type));
};
template<typename T,bool=has_member_called_unlock<T>::value >
struct has_member_unlock
{
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct has_member_unlock<T,true>
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U,typename V>
static true_type has_member(V (U::*)());
template<typename U>
static false_type has_member(U);
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type));
};
template<typename T,bool=has_member_called_try_lock<T>::value >
struct has_member_try_lock
{
BOOST_STATIC_CONSTANT(bool, value=false);
};
template<typename T>
struct has_member_try_lock<T,true>
{
typedef char true_type;
struct false_type
{
true_type dummy[2];
};
template<typename U>
static true_type has_member(bool (U::*)());
template<typename U>
static false_type has_member(U);
BOOST_STATIC_CONSTANT(
bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
};
}
template<typename T>
struct is_basic_lockable
{
BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
detail::has_member_unlock<T>::value);
};
template<typename T>
struct is_lockable
{
BOOST_STATIC_CONSTANT(bool, value =
is_basic_lockable<T>::value &&
detail::has_member_try_lock<T>::value);
};
#else
template<typename T>
struct is_basic_lockable
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template<typename T>
struct is_lockable
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
#endif
template<typename T>
struct is_recursive_mutex_sur_parole
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
template<typename T>
struct is_recursive_mutex_sur_parolle : is_recursive_mutex_sur_parole<T>
{
};
template<typename T>
struct is_recursive_basic_lockable
{
BOOST_STATIC_CONSTANT(bool, value = is_basic_lockable<T>::value &&
is_recursive_mutex_sur_parolle<T>::value);
};
template<typename T>
struct is_recursive_lockable
{
BOOST_STATIC_CONSTANT(bool, value = is_lockable<T>::value &&
is_recursive_mutex_sur_parolle<T>::value);
};
}
template<typename T>
struct is_mutex_type
{
BOOST_STATIC_CONSTANT(bool, value = sync::is_lockable<T>::value);
};
}
#include <boost/config/abi_suffix.hpp>
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -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 <boost/thread/lockable_traits.hpp>
namespace boost
{
namespace sync
{
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
template<>
struct is_basic_lockable<mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_lockable<mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_basic_lockable<timed_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
template<>
struct is_lockable<timed_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
#endif
}
}
#endif

View File

@@ -0,0 +1,243 @@
//////////////////////////////////////////////////////////////////////////////
//
// (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 <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#include <boost/chrono/chrono.hpp>
/// \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 >*/
null_mutex() {}
/// 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 <typename Clock, typename Duration>
bool try_lock_until(chrono::time_point<Clock, Duration> const &)
{
return true;
}
/// Simulates a mutex try_lock_for() operation.
/// Equivalent to "return true;"
template <typename Rep, typename Period>
bool try_lock_for(chrono::duration<Rep, Period> 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 <typename Clock, typename Duration>
bool try_lock_shared_until(chrono::time_point<Clock, Duration> const &)
{
return true;
}
/// Simulates a mutex try_lock_shared_for() operation.
/// Equivalent to "return true;"
template <typename Rep, typename Period>
bool try_lock_shared_for(chrono::duration<Rep, Period> 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 <typename Clock, typename Duration>
bool try_lock_upgrade_until(chrono::time_point<Clock, Duration> const &)
{
return true;
}
/// Simulates a mutex try_lock_upgrade_for() operation.
/// Equivalent to "return true;"
template <typename Rep, typename Period>
bool try_lock_upgrade_for(chrono::duration<Rep, Period> 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 <typename Clock, typename Duration>
bool try_unlock_shared_and_lock_until(chrono::time_point<Clock, Duration> const &)
{
return true;
}
/// Simulates a mutex try_unlock_shared_and_lock_for() operation.
/// Equivalent to "return true;"
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_for(chrono::duration<Rep, Period> 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 <typename Clock, typename Duration>
bool try_unlock_shared_and_lock_upgrade_until(chrono::time_point<Clock, Duration> const &)
{
return true;
}
/// Simulates a mutex try_unlock_shared_and_lock_upgrade_for() operation.
/// Equivalent to "return true;"
template <typename Rep, typename Period>
bool try_unlock_shared_and_lock_upgrade_for(chrono::duration<Rep, Period> 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 <typename Clock, typename Duration>
bool try_unlock_upgrade_and_lock_until(chrono::time_point<Clock, Duration> const &)
{
return true;
}
/// Simulates a mutex try_unlock_upgrade_and_lock_for() operation.
/// Equivalent to "return true;"
template <typename Rep, typename Period>
bool try_unlock_upgrade_and_lock_for(chrono::duration<Rep, Period> const &)
{
return true;
}
#endif
/// Simulates unlock_upgrade_and_lock_shared().
/// Empty function.
void unlock_upgrade_and_lock_shared()
{
}
};
} //namespace boost {
#endif

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