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

Compare commits

...

522 Commits

Author SHA1 Message Date
Marshall Clow
af296f2cd0 Release 1.54.0 beta1
[SVN r84619]
2013-06-03 14:02:28 +00:00
Vicente J. Botet Escriba
0b2c57876f Thread: update history.
[SVN r84490]
2013-05-25 12:08:54 +00:00
Vicente J. Botet Escriba
ba03de1f06 Thread: merge 84414 to fix #8596.
[SVN r84468]
2013-05-24 21:27:53 +00:00
Vicente J. Botet Escriba
100bd73f03 Thread: merge last externally°locked evolution + async_funct.
[SVN r84198]
2013-05-09 04:49:18 +00:00
Vicente J. Botet Escriba
4d2110f5e5 Thread: merge latch; invoke.
[SVN r84101]
2013-05-01 16:40:32 +00:00
Vicente J. Botet Escriba
e294e6bcc8 Thread fix #8451.
[SVN r83995]
2013-04-21 07:34:19 +00:00
Vicente J. Botet Escriba
093a329c1a Thread: fix #8443.
[SVN r83993]
2013-04-21 07:30:55 +00:00
Vicente J. Botet Escriba
13141f8ada Thread: merge from trunk to fix #6843,#6966.
[SVN r83938]
2013-04-17 04:30:48 +00:00
Vicente J. Botet Escriba
64c73fac46 Detail: Added undef/redef Intel atomic macros.
[SVN r83909]
2013-04-14 22:50:18 +00:00
Vicente J. Botet Escriba
22369e9d8c Thread: merge from trunk 1.54: Added lambda tests, refactored future::then, added tests for future::wait...
[SVN r83811]
2013-04-08 17:23:02 +00:00
Vicente J. Botet Escriba
677dbe7688 Thread: merge from trunk 1.54. Fix #8027,#8323,#8337.
[SVN r83660]
2013-03-31 10:56:43 +00:00
Vicente J. Botet Escriba
b1a674869d Thread: merge from trunk. 1.54
[SVN r83525]
2013-03-23 01:48:21 +00:00
Vicente J. Botet Escriba
f9b257e368 Thread: merge from trunk 1.54 - once_atomic; null_mutex
[SVN r82838]
2013-02-12 18:32:00 +00:00
Vicente J. Botet Escriba
8416d3e8bb Thread: merge [82645].
[SVN r82650]
2013-01-27 21:50:23 +00:00
Vicente J. Botet Escriba
8b89d21814 Thread: Fix #7918
[SVN r82635]
2013-01-27 13:33:42 +00:00
Vicente J. Botet Escriba
8804ab8e73 Thread: merge async_pass timeout extension: [82542].
[SVN r82568]
2013-01-20 17:14:51 +00:00
Vicente J. Botet Escriba
0ba92626f0 Thread; merge 82471
[SVN r82502]
2013-01-15 20:19:33 +00:00
Vicente J. Botet Escriba
ce46c31555 Thread: merge 82459,82457,82456,82455
[SVN r82491]
2013-01-14 17:17:50 +00:00
Vicente J. Botet Escriba
e160cf0254 Thread: merge from trun 1.53: some minor fixes on the regression tests.
[SVN r82437]
2013-01-10 21:38:43 +00:00
Vicente J. Botet Escriba
67da33a182 Thread: merge from trunk latest changes.
[SVN r82356]
2013-01-04 18:40:49 +00:00
Vicente J. Botet Escriba
d07835908f Thread: merge from trunk rollback to version 2
[SVN r82320]
2013-01-02 17:09:46 +00:00
Vicente J. Botet Escriba
e618900149 Thread: merge from trunk 1.53
[SVN r82306]
2013-01-01 09:41:02 +00:00
Vicente J. Botet Escriba
e012b8abb2 Thread: merge from trunk condition_variables no-it + doc
[SVN r82159]
2012-12-21 22:15:14 +00:00
Vicente J. Botet Escriba
8ee9ed1904 Thread: merge doc
[SVN r82037]
2012-12-16 22:45:22 +00:00
Vicente J. Botet Escriba
565a022a5a Merge from trunk 1.53
[SVN r82029]
2012-12-16 19:01:45 +00:00
Vicente J. Botet Escriba
0f7d406b9f Thread: merge [81788]-tools dir missing
[SVN r81914]
2012-12-13 21:33:57 +00:00
Vicente J. Botet Escriba
4d5474d600 Thread: merge from trunk 1.53 strict lock tests
[SVN r81814]
2012-12-10 07:37:23 +00:00
Vicente J. Botet Escriba
233484f254 Thread: merge from trunk noit, default to version 3, synchronized_value move semantics
[SVN r81763]
2012-12-07 17:10:06 +00:00
Vicente J. Botet Escriba
ad3247dd29 Thread: merge from trunk 1.53
[SVN r81667]
2012-12-02 09:22:33 +00:00
Vicente J. Botet Escriba
0ae81b8d4c Thread: merge [81032][81034]
[SVN r81035]
2012-10-21 11:56:52 +00:00
Vicente J. Botet Escriba
05f02e1476 Thread: merge 80986
[SVN r81024]
2012-10-20 15:19:13 +00:00
Vicente J. Botet Escriba
23ea174056 Thread: update doc fixes
[SVN r80999]
2012-10-16 17:48:12 +00:00
Vicente J. Botet Escriba
ce19b13c43 Thread: merged 80966
[SVN r80985]
2012-10-14 15:26:00 +00:00
Vicente J. Botet Escriba
8262d61ff5 Thread: Merge 80757
[SVN r80955]
2012-10-11 15:56:21 +00:00
Vicente J. Botet Escriba
4d013af927 Thread: merge from trunk
[SVN r80801]
2012-10-01 00:24:05 +00:00
Vicente J. Botet Escriba
2d8852199b Thread: Merge from trunk
[SVN r80668]
2012-09-23 12:38:00 +00:00
Vicente J. Botet Escriba
12a1c7c71c Thread: merge from trunk
[SVN r80516]
2012-09-13 18:57:04 +00:00
Vicente J. Botet Escriba
89e944914b Thread: Merged from trunk : 1.52
[SVN r80476]
2012-09-09 19:39:44 +00:00
Vicente J. Botet Escriba
7bc8c437ab Thread: merge from trunk: 1.52
[SVN r80450]
2012-09-08 14:59:26 +00:00
Vicente J. Botet Escriba
c4420d7591 Thread: merge fix for #6174
[SVN r80040]
2012-08-15 09:54:21 +00:00
Andrey Semashev
6ef2dade3a Merged changes from trunk.
[SVN r79794]
2012-07-29 08:44:22 +00:00
Vicente J. Botet Escriba
c594f5d9ae Thread: update changes
[SVN r79408]
2012-07-10 20:58:07 +00:00
Vicente J. Botet Escriba
a73cf83971 Thread: Merge from trunk
[SVN r79397]
2012-07-09 22:13:44 +00:00
Vicente J. Botet Escriba
67a5a6f39e Thread: merge from trunk
[SVN r79373]
2012-07-09 05:55:01 +00:00
Vicente J. Botet Escriba
348bd080ef Thread: remove unused file: shared_mutex.cpp 7044
[SVN r79238]
2012-07-03 06:20:41 +00:00
Vicente J. Botet Escriba
bca4c3d5fa Thread: Added other fixed tickets in history
[SVN r79031]
2012-06-21 21:26:35 +00:00
Vicente J. Botet Escriba
9e6384bf79 Thread: merge from trunk to fix some minor bugs
[SVN r78973]
2012-06-16 21:10:08 +00:00
Anthony Williams
dcd544082e Merged boost.thread from trunk
[SVN r78543]
2012-05-22 17:03:15 +00:00
Dave Abrahams
1013ce68c1 Replace all uses of boost/utility.hpp with more-granular includes. Solves modularization dependency nightmare.
[SVN r78502]
2012-05-18 04:44:04 +00:00
Vicente J. Botet Escriba
aea84b03fc Thread: link with Boost.Chrono for vacpp-11.1
[SVN r78451]
2012-05-13 08:46:43 +00:00
Anthony Williams
7608db4b0e Combine scoped enum emulation from thread library into detail/scoped_enum_emulation.hpp
[SVN r78407]
2012-05-10 17:06:15 +00:00
Anthony Williams
62f1c4b086 Reinstate abi prefix/suffix headers
[SVN r78399]
2012-05-10 07:30:41 +00:00
Vicente J. Botet Escriba
ab6864f3b4 Thread: try to fix ticket 6130 for linux systems
[SVN r78285]
2012-04-30 20:23:56 +00:00
Vicente J. Botet Escriba
b8bd80a5f4 Thread: Use NO_COPYABLE macro
[SVN r78280]
2012-04-30 16:06:04 +00:00
Vicente J. Botet Escriba
fffc5ddd1f Thread: Added some traces to catch spourious issue
[SVN r78279]
2012-04-30 16:05:24 +00:00
Vicente J. Botet Escriba
cd4c858048 Thread: Added some traces to catch spourious issue
[SVN r78278]
2012-04-30 16:04:22 +00:00
Vicente J. Botet Escriba
3fb1bd3d1d Thread: warning removal
[SVN r78277]
2012-04-30 16:03:30 +00:00
Vicente J. Botet Escriba
75aff7f1a6 Thread: Try to fix spourious issue
[SVN r78276]
2012-04-30 16:01:19 +00:00
Vicente J. Botet Escriba
3f3c5c8ac5 Thread: warning removal
[SVN r78275]
2012-04-30 16:00:29 +00:00
Vicente J. Botet Escriba
40b66a83f7 Thread: removed warning
[SVN r78254]
2012-04-29 14:27:43 +00:00
Vicente J. Botet Escriba
0b15d66dc0 Thread: Added use of macro BOOST_THREAD_MAKE_RV_REF and some traces to try to solve PGI regression test
[SVN r78243]
2012-04-28 16:11:03 +00:00
Vicente J. Botet Escriba
ceacda6c6a Thread: Refactor the no-copyable classes using the macro BOOST_THREAD_NO_COPYABLE
[SVN r78240]
2012-04-28 12:25:28 +00:00
Vicente J. Botet Escriba
0a22ac9209 Thread: Add a workaround for the bug identified in ticket 6130 by adding some microseconds to the time to wait
[SVN r78239]
2012-04-28 12:24:08 +00:00
Vicente J. Botet Escriba
ba1d54d672 Thread: inhibit allocators on wince as there is a bug on Boost.Intrusive
[SVN r78226]
2012-04-28 00:08:53 +00:00
Vicente J. Botet Escriba
b5a18dc71a Thread: Boost.Chrono seems to work on vacpp 11.1
[SVN r78225]
2012-04-27 23:29:01 +00:00
Vicente J. Botet Escriba
4a0141511d Thread: Boost.Chrono seems to work on vacpp 11.1
[SVN r78224]
2012-04-27 23:08:24 +00:00
Vicente J. Botet Escriba
f0a6e49984 Thread: Try to fix some errors with vacpp
[SVN r78222]
2012-04-27 22:24:17 +00:00
Vicente J. Botet Escriba
f60e1d1230 Thread: Try to fix some spourious error
[SVN r78197]
2012-04-25 21:55:07 +00:00
Vicente J. Botet Escriba
625db78abf Thread: more move semantics refactoring cleanup
[SVN r78139]
2012-04-22 16:33:46 +00:00
Vicente J. Botet Escriba
b470ffdb56 Thread: Added macro BOOST_THREAD_DCL_MOVABLE to mask has_move_emulation_enabled_aux specialization
[SVN r78123]
2012-04-22 08:12:27 +00:00
Vicente J. Botet Escriba
78095afdbc Thread: Fix issue with macro BOOST_THREAD_RV_REF and the use of templates as arguments, see with Sun compiler
[SVN r78086]
2012-04-19 22:19:52 +00:00
Vicente J. Botet Escriba
e83cdc6721 Thread: Change to version 3 and don't deprecate legacy time related functions, even if they are not part of the concepts since version 3
[SVN r78029]
2012-04-16 20:49:18 +00:00
Vicente J. Botet Escriba
7ba000fe45 Thread: Set by default to don't use Boost.Move
[SVN r77994]
2012-04-15 12:29:33 +00:00
Vicente J. Botet Escriba
cae6a36c19 Thread: fix some macros using old move emilation
[SVN r77985]
2012-04-15 09:55:25 +00:00
Vicente J. Botet Escriba
8549895373 Thread: Make use of the new macros to reduce the code duplication-IV
[SVN r77946]
2012-04-13 09:39:17 +00:00
Vicente J. Botet Escriba
efa907881e Thread: Make use of the new macros to reduce the code duplication-III
[SVN r77941]
2012-04-12 22:59:23 +00:00
Vicente J. Botet Escriba
744cae8270 Thread: Make use of the new macros to reduce the code duplication
[SVN r77939]
2012-04-12 20:32:20 +00:00
Vicente J. Botet Escriba
28899243b1 Thread: symplify additonaly the conditional code + fix some spurious regression errors
[SVN r77933]
2012-04-12 11:12:23 +00:00
Vicente J. Botet Escriba
267288ba19 Thread! remove unused param warning
[SVN r77930]
2012-04-12 08:07:00 +00:00
Vicente J. Botet Escriba
3487d05fac Thread: Fix typo
[SVN r77929]
2012-04-12 08:06:13 +00:00
Vicente J. Botet Escriba
031186a8e6 Thread: Add some macros to simplify the conditional code in particular the one related to mmove semantics+ fix some minor regression issues
[SVN r77928]
2012-04-11 23:42:26 +00:00
Vicente J. Botet Escriba
f970c9fddc Thread: remove some warnings + rename BOOST_EXPLICIT_MOVE by BOOST_THREAD_MAKE_RV_REF
[SVN r77918]
2012-04-11 17:16:45 +00:00
Vicente J. Botet Escriba
e9ceaaa2bb Thread: Set examples exmplcit
[SVN r77888]
2012-04-10 16:22:51 +00:00
Vicente J. Botet Escriba
0e7c436df5 Thread: Added container tests
[SVN r77887]
2012-04-10 16:21:43 +00:00
Vicente J. Botet Escriba
745e23f2c3 Thread: move specialization of uses_allocator
[SVN r77885]
2012-04-10 13:29:36 +00:00
Vicente J. Botet Escriba
1f7b8a6583 Thread: Added -ansi -permissive on some compilers
[SVN r77884]
2012-04-10 12:33:51 +00:00
Vicente J. Botet Escriba
b2790c6df5 Thread: Added pt test constructor from const functor + pt allocator ctor free fct+ cleanup of other tests
[SVN r77877]
2012-04-10 01:37:18 +00:00
Vicente J. Botet Escriba
f5e3c1c348 Thread: Added pt func_ctor test + update some test to pass Sun compiler regression
[SVN r77876]
2012-04-10 00:24:07 +00:00
Vicente J. Botet Escriba
ba955f003e Thread: Fix packaged_task callable copy
[SVN r77875]
2012-04-10 00:14:12 +00:00
Vicente J. Botet Escriba
75e0ffbbce Thread: rollback the last changes in packaged_task
[SVN r77870]
2012-04-09 23:21:16 +00:00
Vicente J. Botet Escriba
9168dd7d1d Thread: fix commit error
[SVN r77860]
2012-04-09 19:23:37 +00:00
Vicente J. Botet Escriba
ee5f871f1a Thread: fix commit error
[SVN r77857]
2012-04-09 18:56:39 +00:00
Vicente J. Botet Escriba
c896c8fda4 Thread: fix commit error
[SVN r77853]
2012-04-09 17:52:46 +00:00
Vicente J. Botet Escriba
0e895a1e28 Thread: Added packaged_task::reste() + more tests
[SVN r77852]
2012-04-09 17:18:39 +00:00
Vicente J. Botet Escriba
d95081094f Thread: remove some warnings
[SVN r77849]
2012-04-09 15:26:40 +00:00
Vicente J. Botet Escriba
011dda9816 Thread: Added packaged_task ctor allocator + result_type + Fix issue signaled on the ML with task_object(task_object const&) in presence of task_object(task_object &&)
[SVN r77845]
2012-04-08 23:51:07 +00:00
Vicente J. Botet Escriba
34c377328f Thread: Added some packaged_task tests
[SVN r77844]
2012-04-08 23:24:19 +00:00
Vicente J. Botet Escriba
382204f702 Thread: Make use of the boost version of use_allocator
[SVN r77843]
2012-04-08 22:40:37 +00:00
Vicente J. Botet Escriba
19aed55e52 Thread: Fix type
[SVN r77841]
2012-04-08 20:56:34 +00:00
Vicente J. Botet Escriba
9d1e1fb64a Thread: Activate share mutex upwards conversions tests
[SVN r77839]
2012-04-08 19:23:34 +00:00
Vicente J. Botet Escriba
d75cda0cc3 Thread: Provided an alternative implementation for thread::id using pthread_t and Windows Thread Id
[SVN r77838]
2012-04-08 19:22:38 +00:00
Vicente J. Botet Escriba
a4c7f68320 Thread: Added needed header
[SVN r77836]
2012-04-08 18:57:07 +00:00
Vicente J. Botet Escriba
547431da0b Thread: fix typo
[SVN r77825]
2012-04-08 07:57:32 +00:00
Vicente J. Botet Escriba
c3fdc098fe Thread: Try to fix some failing tests on sun
[SVN r77806]
2012-04-07 07:59:23 +00:00
Vicente J. Botet Escriba
6ed276190d Thread: rename macros and try to fix some failing sun test
[SVN r77789]
2012-04-05 22:39:22 +00:00
Vicente J. Botet Escriba
59265265d9 Thread: 6342: Adapt the one_flag and call_once to the c++11 interface
[SVN r77767]
2012-04-04 20:01:11 +00:00
Vicente J. Botet Escriba
8d9370b005 Thread: Try to pass these tests on VACPP
[SVN r77766]
2012-04-04 19:56:56 +00:00
Vicente J. Botet Escriba
fd97c6e7a7 Thread: Try to pass these test on Sun using BOOST_EXPLICIT_MOVE
[SVN r77754]
2012-04-04 15:15:11 +00:00
Vicente J. Botet Escriba
297da0745f Thread: Try to pass these test on Sun using BOOST_EXPLICIT_MOVE
[SVN r77753]
2012-04-04 15:14:05 +00:00
Vicente J. Botet Escriba
cb231e02a6 Thread: Try to pass these test on Sun using BOOST_EXPLICIT_MOVE
[SVN r77751]
2012-04-03 20:57:24 +00:00
Vicente J. Botet Escriba
298b51fefa Thread: Check if adding BOOST_EXPLICIT_MOVE helps on Sun
[SVN r77729]
2012-04-02 22:49:11 +00:00
Vicente J. Botet Escriba
80befa1c94 Thread: rollback 76581 partialy so that no link with boost chrono is done on vaccp
[SVN r77728]
2012-04-02 22:33:05 +00:00
Vicente J. Botet Escriba
11dce20534 Thread: Remove duplicated file #3160
[SVN r77719]
2012-04-02 16:37:53 +00:00
Vicente J. Botet Escriba
56bd079f96 Thread: Added call to terminate if joinable for #6266 and #6269
[SVN r77718]
2012-04-02 16:32:33 +00:00
Vicente J. Botet Escriba
733b49ae42 Thread: Fix Jamfile removing not needed source shared_mutex.cpp
[SVN r77705]
2012-04-01 22:14:06 +00:00
Vicente J. Botet Escriba
08ed4c4201 Thread: Added shared mutex upwards conversion + configuration macros
[SVN r77704]
2012-04-01 21:52:47 +00:00
Vicente J. Botet Escriba
09d5125278 Thread: Fix typos due to copy/paste
[SVN r77701]
2012-04-01 20:38:31 +00:00
Vicente J. Botet Escriba
6e1a3f3c27 Thread: Added specific macros for futures and importing container specific into boost
[SVN r77687]
2012-04-01 15:51:18 +00:00
Vicente J. Botet Escriba
5b3743d9a6 Thread: Split test with and wothout args
[SVN r77686]
2012-04-01 15:48:56 +00:00
Vicente J. Botet Escriba
ec135b1b8e Thread: Added missing file
[SVN r77684]
2012-04-01 09:14:50 +00:00
Vicente J. Botet Escriba
60e34cff11 Thread: Make use of the generic shared implementation for the missing features in windows.
[SVN r77668]
2012-03-31 15:38:56 +00:00
Vicente J. Botet Escriba
da8dc9f5aa Thread: Add the possibility to use the more complete and generic implementation of shared_mutex in windows.
[SVN r77667]
2012-03-31 15:37:44 +00:00
Vicente J. Botet Escriba
27aa44acb5 Thread: Added promise allocator ctor + more tests
[SVN r77666]
2012-03-31 15:19:22 +00:00
Vicente J. Botet Escriba
ff1d051359 Thread: Added reverse_lock
[SVN r77662]
2012-03-31 08:39:21 +00:00
Vicente J. Botet Escriba
85e32534fa Thread: Added shared_lock_guard
[SVN r77661]
2012-03-31 08:06:57 +00:00
Vicente J. Botet Escriba
bc49b7d03a Thread: Update doc with a lot of changes to follow the updated code
[SVN r77660]
2012-03-31 07:37:59 +00:00
Vicente J. Botet Escriba
ee97068208 Thread Fix incoherent BOOST_NOEXCEPT prototype
[SVN r77659]
2012-03-31 07:16:20 +00:00
Vicente J. Botet Escriba
0f7e069dd9 Thread: Added explicit int conversion from lock should fail
[SVN r77658]
2012-03-31 06:52:55 +00:00
Vicente J. Botet Escriba
3c3c6d5efe Thread: Fix warning + added DEPRECATED tag
[SVN r77655]
2012-03-30 19:16:51 +00:00
Vicente J. Botet Escriba
f163054557 Thread: Added more noexcept
[SVN r77640]
2012-03-30 04:46:47 +00:00
Vicente J. Botet Escriba
fb80bea056 Thread: Disable The use of Boost.Thread for SunPro compiler
[SVN r77612]
2012-03-28 20:40:31 +00:00
Vicente J. Botet Escriba
abad5c3028 Thread: Added BOOST_EXPLICIT_MOVE
[SVN r77588]
2012-03-27 18:22:30 +00:00
Vicente J. Botet Escriba
d0c164220d Thread: DOn't use Boost.Test when not needed to avoid issues on Sun
[SVN r77586]
2012-03-27 17:26:10 +00:00
Vicente J. Botet Escriba
34b1a86a68 Thread: Update F_pass and Frvalue tests for compilers that doesn't support rvalue references or delete constructors.
[SVN r77551]
2012-03-25 22:31:11 +00:00
Vicente J. Botet Escriba
06f5da7f5b Thread: cleanup
[SVN r77550]
2012-03-25 21:25:20 +00:00
Vicente J. Botet Escriba
1e80ccb8d3 Thread: Protect uses of Boost.Chrono for compilers don't providing support for
[SVN r77460]
2012-03-21 21:05:26 +00:00
Vicente J. Botet Escriba
8ad34a689a Thread: Fixed error on promise v2 + added tests (share)
[SVN r77443]
2012-03-20 23:49:31 +00:00
Vicente J. Botet Escriba
a421e10e3b Thread: Comment not yet commited tests
[SVN r77427]
2012-03-20 07:48:36 +00:00
Vicente J. Botet Escriba
1c4b42bb95 Thread: Make test names shorter
[SVN r77401]
2012-03-19 12:12:21 +00:00
Vicente J. Botet Escriba
bba3be457b Thread: Fix missing include
[SVN r77399]
2012-03-19 06:49:13 +00:00
Vicente J. Botet Escriba
3abfbb8ba1 Thread: Added upgrade_mutex on windows
[SVN r77396]
2012-03-18 23:42:23 +00:00
Vicente J. Botet Escriba
331a35070c Thread: comment not yet committed examples
[SVN r77394]
2012-03-18 22:55:13 +00:00
Vicente J. Botet Escriba
99ad690382 Thread: Added Chrono related functions to exclusive lock+ upgrade_mutex typedef
[SVN r77393]
2012-03-18 22:49:24 +00:00
Vicente J. Botet Escriba
4301b21702 Thread: Added LOCK::move() member function when no RVALUE is available (Useful for Sun compiler to force move semantics) + possibility to have explicit lock conversions+chrono timed related unique_lock constructor from upgrade_lock
[SVN r77392]
2012-03-18 22:35:11 +00:00
Vicente J. Botet Escriba
fceab582fe Thread: Added future/shared/future/promise/packaged_task::move() member function when no RVALUE is available (Useful for Sun compiler to force move semantics)
[SVN r77391]
2012-03-18 22:06:44 +00:00
Vicente J. Botet Escriba
e8a4ed40a5 Thread: Make test names shorter + Added more tests on locks
[SVN r77388]
2012-03-18 21:27:30 +00:00
Vicente J. Botet Escriba
b698c1437b Thread: Update test to run
[SVN r77384]
2012-03-18 19:54:39 +00:00
Vicente J. Botet Escriba
14cea92e06 Thread: Added thread::move member function when BOOST_THREAD_USES_MOVE is defined (Useful for Sun compiler)
[SVN r77379]
2012-03-18 18:35:20 +00:00
Vicente J. Botet Escriba
3a8e04cac6 Thread: Make test names shorter + Added some examples of shared mutex and tests
[SVN r77378]
2012-03-18 18:21:45 +00:00
Vicente J. Botet Escriba
5b01721440 Thread: Add time chrono related functions to shared_mutex(win) + activate tests
[SVN r77376]
2012-03-18 17:29:33 +00:00
Vicente J. Botet Escriba
aad2b35ac9 Thread: Fix bug on time related functions that should base the _for functions on the until_ ones
[SVN r77375]
2012-03-18 17:26:30 +00:00
Vicente J. Botet Escriba
f8371daeb8 Thread: Avoid some warnings as unused variable it and warning C4275: non dll-interface class 'std::logic_error' used as base for dll-interface class 'boost::future_error'
[SVN r77360]
2012-03-17 14:42:36 +00:00
Vicente J. Botet Escriba
74519977fd Thread: Avoid warning boost/bind/bind.hpp(392) : warning C4244: 'argument' : conversion from 'double' to 'int', possible loss of data
[SVN r77356]
2012-03-17 12:47:54 +00:00
Vicente J. Botet Escriba
c0bea158d4 Thread: Use of BOOST_ASSERT_MSG
[SVN r77330]
2012-03-14 06:39:07 +00:00
Vicente J. Botet Escriba
70686b4913 Thread: Comment not yet committed test
[SVN r77294]
2012-03-10 17:27:10 +00:00
Vicente J. Botet Escriba
14502dd715 Thread: Added test for upgrade_lock
[SVN r77293]
2012-03-10 17:17:14 +00:00
Vicente J. Botet Escriba
8ee986536b Thread: Added test for shared_lock move from other locks
[SVN r77292]
2012-03-10 17:07:39 +00:00
Vicente J. Botet Escriba
8ed82798d2 Thread: Fix #6673 and partial fix for 6671, 6672, 6675 which need to add the documentation and test
[SVN r77291]
2012-03-10 17:05:34 +00:00
Vicente J. Botet Escriba
ebfe10b7df Thread: Fix error on pthread/shared_mutex.hpp try_lock_xxx_for, which should use the try_lock_xxx_until+fix #6674
[SVN r77290]
2012-03-10 17:01:27 +00:00
Vicente J. Botet Escriba
4aa26180ca Thread: removed output to cout to fix 6612
[SVN r77224]
2012-03-04 20:56:42 +00:00
Vicente J. Botet Escriba
89496448d9 Thread: Update doc removing thread_move_t
[SVN r77136]
2012-02-28 18:49:22 +00:00
Vicente J. Botet Escriba
dfa0a3979a Thread: Add explicit #error when the test is not applicable
[SVN r77041]
2012-02-16 18:12:03 +00:00
Vicente J. Botet Escriba
396cd7db4f Thread: Added traces to try to catch some issues
[SVN r77038]
2012-02-16 17:40:47 +00:00
Vicente J. Botet Escriba
0351d59060 Thread: Added chrono i/f and improve move semantics for shared_mutex and shared_lock (pthread)
[SVN r77011]
2012-02-13 23:20:42 +00:00
Vicente J. Botet Escriba
6f0b0e976d Thread: uncomment Frvalue_pass test
[SVN r77004]
2012-02-13 07:48:23 +00:00
Vicente J. Botet Escriba
dd5d687014 Thread: Added chrono i/f for shared_mutex pthread
[SVN r77003]
2012-02-12 22:38:59 +00:00
Vicente J. Botet Escriba
5d8b0891bd Thread: Don't fail when native_handle is not defined
[SVN r76996]
2012-02-12 16:47:19 +00:00
Vicente J. Botet Escriba
7dc95f63d3 Thread: Move semantics cleanup
[SVN r76995]
2012-02-12 16:44:43 +00:00
Jürgen Hunold
a7adc5865b Fix: correct logic for enabling c++11 explicit conversion operators
[SVN r76959]
2012-02-09 20:21:43 +00:00
Vicente J. Botet Escriba
cdbe5766fa Thread: try to fix 6456 - trunk compilation errors converting future_errc to int
[SVN r76952]
2012-02-08 21:34:29 +00:00
Vicente J. Botet Escriba
b1cac0731c Thread: Added explicit to operator bool for locks
[SVN r76951]
2012-02-08 21:32:05 +00:00
Vicente J. Botet Escriba
fc8de511c6 Thread: Added detail/scoped_enumm.hpp file and adaptat enum classes to the new interface
[SVN r76777]
2012-01-29 18:27:26 +00:00
Vicente J. Botet Escriba
defdb8ff1c Thread: Try to fix 4885 - Access violation in set_tss_data at process exit due to invalid assumption about TlsAlloc
[SVN r76752]
2012-01-28 16:02:01 +00:00
Vicente J. Botet Escriba
9a08a8478f Thread: Try to fix 6431 - MinGW: Cannot export (anonymous namespace)::thread_binder
[SVN r76598]
2012-01-20 18:53:55 +00:00
Vicente J. Botet Escriba
a6f7a0180b Thread: Try to fix min stack size
[SVN r76597]
2012-01-20 18:52:21 +00:00
Vicente J. Botet Escriba
5a59df4476 Thread: Try to fix min stack size
[SVN r76596]
2012-01-20 18:51:24 +00:00
Vicente J. Botet Escriba
1df9d7c575 Thread: avoid the use of Boost.Chrono for vacpp toolset
[SVN r76581]
2012-01-18 21:07:13 +00:00
Vicente J. Botet Escriba
65008b11f7 Thread: Try to fix some checks that fails depending on the way the threads are switched (the time constraint is too high)
[SVN r76580]
2012-01-18 21:04:47 +00:00
Vicente J. Botet Escriba
b18314878a Thread: try to make it possible to avoid the use of Boost.Chrono
[SVN r76570]
2012-01-18 00:13:17 +00:00
Vicente J. Botet Escriba
11a951c679 Thread: Try to fix some checks that fails depending on the way the threads are switched (the time constraint is too high)
[SVN r76565]
2012-01-17 22:24:06 +00:00
Vicente J. Botet Escriba
c67e3ff7b9 Thread: try to fix #6420 - Call to forward ambiguous
[SVN r76561]
2012-01-17 18:51:36 +00:00
Vicente J. Botet Escriba
e5a633cc41 Thread: Try to fix #6418 - error: 'X(X&&)' cannot be defaulted
[SVN r76558]
2012-01-17 18:31:03 +00:00
Vicente J. Botet Escriba
3724d847cf Thread: Try to fix #6419 - Error: PTHREAD_STACK_MIN is not always defined when PTHREADS are used
[SVN r76557]
2012-01-17 18:28:46 +00:00
Vicente J. Botet Escriba
b6063b5c60 * [@http://svn.boost.org/trac/boost/ticket/2741 #2741] Proposal to manage portable and non portable thread attributes.
* [@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/6224 #6224] c++11 compliance: Add the use of standard noexcept 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/6230 #6230] c++11 compliance: Follows the exception reporting mechanism as defined in the 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/6194 #6194] Adapt to Boost.Move. 
 	
Fixed Bugs:

* [@http://svn.boost.org/trac/boost/ticket/2575 #2575] Bug- Boost 1.36.0 on Itanium platform.
* [@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:🧵 pthreas_exit causes terminate().

* [@http://svn.boost.org/trac/boost/ticket/5351 #5351] interrupt a future get boost::unknown_exception.
* [@http://svn.boost.org/trac/boost/ticket/5516 #5516] Upgrade lock is not acquired when previous upgrade lock releases if another read lock is present. 
* [@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.



[SVN r76543]
2012-01-16 17:32:08 +00:00
Vicente J. Botet Escriba
09362f0eac Thread: merge from trunk to fix #6141, #5594, #5040 and #5502.
[SVN r76346]
2012-01-07 20:52:57 +00:00
Vicente J. Botet Escriba
32b3f3f569 Thread: Fix typo on auto_ptr
[SVN r76345]
2012-01-07 20:15:14 +00:00
Vicente J. Botet Escriba
0d08362291 Thread: Added new v2 files
[SVN r76300]
2012-01-03 22:31:11 +00:00
Vicente J. Botet Escriba
9f120a80a7 Thread: Updated Jamfiles to take care of Boost.Chrono, Boost.System and the new tests
[SVN r76298]
2012-01-03 21:50:37 +00:00
Vicente J. Botet Escriba
2eb6fd754e Thread: Added doc related to a lot of tickets mainly the time related #6195, noexcept #6224, exceptions #6230, cv_status #6273
[SVN r76297]
2012-01-03 21:45:31 +00:00
Vicente J. Botet Escriba
9f4a8973d0 Thread: Added test related to tickets
[SVN r76296]
2012-01-03 21:25:58 +00:00
Vicente J. Botet Escriba
a4d9355060 Threads: Added a lot of unit tests
[SVN r76295]
2012-01-03 21:23:11 +00:00
Vicente J. Botet Escriba
5a7545afbd Thread Towards #6273 - Add cv_status enum class and use it on the conditions wait functions
[SVN r76294]
2012-01-03 21:12:59 +00:00
Vicente J. Botet Escriba
8affa33718 Thread fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2309 #2309] Lack of g++ symbol visibility support in Boost.Thread. 
* [@http://svn.boost.org/trac/boost/ticket/2639 #2639] documentation should be extended(defer_lock, try_to_lock, ...).

* [@http://svn.boost.org/trac/boost/ticket/3639 #3639] Boost.Thread doesn't build with Sun-5.9 on Linux.
* [@http://svn.boost.org/trac/boost/ticket/3762 #3762] Thread can't be compiled with winscw (Codewarrior by Nokia).
* [@http://svn.boost.org/trac/boost/ticket/3885 #3885] document about mix usage of boost.thread and native thread api.
* [@http://svn.boost.org/trac/boost/ticket/3975 #3975] Incorrect precondition for promise::set_wait_callback().

* [@http://svn.boost.org/trac/boost/ticket/4048 #4048] thread::id formatting involves locale
* [@http://svn.boost.org/trac/boost/ticket/4315 #4315] gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored. 
* [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds.
* [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints.

* [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x.
* [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor.
* [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6.
* [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure.
* [@http://svn.boost.org/trac/boost/ticket/5839 #5839] thread.cpp: ThreadProxy leaks on exceptions.
* [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions. 

* [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems.
* [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo).
* [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio.
* [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR. 
* [@http://svn.boost.org/trac/boost/ticket/6207 #6207] shared_lock swap compiler error on clang 3.0 c++11. 
* [@http://svn.boost.org/trac/boost/ticket/6208 #6208] try_lock_wrapper swap compiler error on clang 3.0 c++11. 




[SVN r76291]
2012-01-03 17:31:50 +00:00
Vicente J. Botet Escriba
4d25ea1760 Thread: protect of threading=single by forcing threading=multi
[SVN r76283]
2012-01-02 22:08:02 +00:00
Vicente J. Botet Escriba
6ec8e2ccec Thread: Fix error following last commit 76277 for #6141
[SVN r76280]
2012-01-02 17:48:18 +00:00
Vicente J. Botet Escriba
97d0ae6527 Thread: #6141 - Compilation error when boost.thread and boost.move are used together
[SVN r76277]
2012-01-02 17:12:01 +00:00
Vicente J. Botet Escriba
50a74d0eda Thread: Try to solve #6341 Boost.Thread defines boost::move which conflicts with Boost.Move
[SVN r76268]
2012-01-02 00:33:32 +00:00
Vicente J. Botet Escriba
f9e03b5eaa Thread: Notify shread_cond when state.exclusive_waiting_blocked=false in shared_mutex::timed_lock to resolve #5502
[SVN r76084]
2011-12-20 21:13:22 +00:00
Vicente J. Botet Escriba
ad571bd898 Thread: Fix error returning in constructor
[SVN r76078]
2011-12-20 12:42:45 +00:00
Vicente J. Botet Escriba
de8ef9aee4 Thread: reverse part of commit r76040 which breaks msvc-10.0
[SVN r76075]
2011-12-19 23:50:03 +00:00
Vicente J. Botet Escriba
21f75da2f6 Thread: don't overload move when BOOST_NO_RVALUE_REFERENCES is not defined
[SVN r76074]
2011-12-19 23:22:08 +00:00
Vicente J. Botet Escriba
233dbf8075 Thread: dont use thread_move_t when BOOST_NO_RVALUE_REFERENCES is not defined
[SVN r76073]
2011-12-19 23:20:31 +00:00
Vicente J. Botet Escriba
d8f1ba9b3d Thread: added move definition when BOOST_NO_RVALUE_REFERENCES is not defined
[SVN r76040]
2011-12-18 14:34:09 +00:00
Vicente J. Botet Escriba
1241f18215 Thread: replace BOOST_HAS_RVALUE_REFS by BOOST_NO_RVALUE_REFERENCES and protect uses of thread_move_t
[SVN r76039]
2011-12-18 14:31:36 +00:00
Vicente J. Botet Escriba
b6604882eb Thread: Added BOOST_THREAD_VERSION so that we can add backward incompatible features
[SVN r76037]
2011-12-18 13:37:37 +00:00
Vicente J. Botet Escriba
a9c9d5c499 Thread: #4048 thread::id formatting: use ios_flags_saver
[SVN r76011]
2011-12-17 09:02:10 +00:00
Vicente J. Botet Escriba
9a827d937e Thread: #4921 BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB are crucial and need to be documented
[SVN r75905]
2011-12-11 18:16:07 +00:00
Vicente J. Botet Escriba
38594f889a Thread: #5013 - documentation: boost:🧵 pthreas_exit causes terminate()
[SVN r75904]
2011-12-11 18:12:55 +00:00
Vicente J. Botet Escriba
04c17e45b3 Thread: #5594 boost::shared_mutex not fully compatible with Windows CE.
[SVN r75903]
2011-12-11 15:43:13 +00:00
Vicente J. Botet Escriba
730a8de024 Thread: #5040 future.hpp in boost::thread does not compile with /clr
[SVN r75901]
2011-12-11 13:32:41 +00:00
Vicente J. Botet Escriba
7eac2fe3e4 Thread: Fix auto_ptr error
[SVN r75886]
2011-12-10 14:59:43 +00:00
Vicente J. Botet Escriba
267243d959 Thread: Fix typo
[SVN r75885]
2011-12-10 14:51:16 +00:00
Vicente J. Botet Escriba
f587262c8e Thread: Added compliance matrix
[SVN r75884]
2011-12-10 11:56:45 +00:00
Vicente J. Botet Escriba
ebf458dbd0 Thread: update fixed tickets for 1.49
[SVN r75883]
2011-12-10 11:54:36 +00:00
Vicente J. Botet Escriba
f64b5559dd Thread: #6200-mutex error better handle EINTR
[SVN r75882]
2011-12-10 10:55:53 +00:00
Vicente J. Botet Escriba
2ddcd5f678 Thread: #6200-mutex error better handle EINTR
[SVN r75860]
2011-12-07 23:15:20 +00:00
Vicente J. Botet Escriba
cac715937a Thread: boost thread unit test module bug on Microsoft Visual Studio debug mode
[SVN r75858]
2011-12-07 21:08:52 +00:00
Vicente J. Botet Escriba
39f43feb11 Thread: Added more fixed tickets
[SVN r75807]
2011-12-05 00:27:46 +00:00
Vicente J. Botet Escriba
58d65b17ea Thread: #5859 win32 shared_mutex constructor leaks on exceptions
[SVN r75806]
2011-12-04 23:06:24 +00:00
Vicente J. Botet Escriba
4314f0cac3 Thread: #3762 Thread can't be compiled with winscw (Codewarrior by Nokia) (win part)
[SVN r75802]
2011-12-04 15:18:32 +00:00
Vicente J. Botet Escriba
d4da369930 Thread: 6207/6208 shared_lock/try_lock_wrapper swap compiler error on clang 3.0 c++11
[SVN r75801]
2011-12-04 14:58:08 +00:00
Vicente J. Botet Escriba
6f1876b618 Thread: #6100 Compute hardware_concurrency() using get_nprocs() on GLIBC systems
[SVN r75800]
2011-12-04 14:33:08 +00:00
Vicente J. Botet Escriba
c6e872ceb0 Thread: #2309 - Lack of g++ symbol visibility support in Boost.Thread
[SVN r75799]
2011-12-04 10:36:34 +00:00
Vicente J. Botet Escriba
72d809819f Thread: #3639 Boost.Thread doesn't build with Sun-5.9 on Linux
[SVN r75798]
2011-12-04 09:35:34 +00:00
Vicente J. Botet Escriba
dd09ef3362 Thread: 4315 gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored
[SVN r75791]
2011-12-03 17:56:38 +00:00
Vicente J. Botet Escriba
aa7941fae2 Thread: 2639 documentation should be extended(defer_lock, try_to_lock, ...) + 3885 document about mix usage of boost.thread and native thread api. + 3975 Incorrect precondition for promise::set_wait_callback() + 4819 boost.thread's documentation misprints.
[SVN r75790]
2011-12-03 14:28:17 +00:00
Vicente J. Botet Escriba
35af4a8f35 Thread: 3762 Thread can't be compiled with winscw (Codewarrior by Nokia) (pthread part)
[SVN r75789]
2011-12-03 14:11:02 +00:00
Vicente J. Botet Escriba
a01fd3dd76 Thread: 4480 (move part) + 6175 Compile error with SunStudio
[SVN r75788]
2011-12-03 14:06:32 +00:00
Vicente J. Botet Escriba
d220da89d1 Thread: 4480 OpenVMS patches for compiler issues workarounds (only sleep part)
[SVN r75787]
2011-12-03 13:57:06 +00:00
Vicente J. Botet Escriba
55c75e9299 Thread: 5423 thread issues with C++0x
[SVN r75786]
2011-12-03 13:50:40 +00:00
Vicente J. Botet Escriba
616ea87a0a Thread: 5739 set-but-not-used warnings with gcc-4.6
[SVN r75785]
2011-12-03 13:25:55 +00:00
Vicente J. Botet Escriba
319ba2fe75 Thread: 6200 patch to have condition_variable and mutex error better handle EINTR
[SVN r75781]
2011-12-03 10:09:11 +00:00
Vicente J. Botet Escriba
d79eeff779 Thread:6168 recursive_mutex is using wrong config symbol (possible typo)
[SVN r75780]
2011-12-03 10:02:37 +00:00
Gennadiy Rozental
26d38748db eliminated test_case_template.hpp
[SVN r74735]
2011-10-05 10:28:08 +00:00
Gennadiy Rozental
5c124234bb eliminated unit_test_framework and BOOST_MESSAGE
[SVN r74731]
2011-10-05 09:52:10 +00:00
Anthony Williams
b991c9a8a0 Merged thread changes from trunk
[SVN r72431]
2011-06-06 08:28:31 +00:00
Anthony Williams
681af396b8 Change pin_to_zero and interruptible_wait to use (u)intmax_t rather than (unsigned) long, to avoid warnings about truncation
[SVN r72303]
2011-05-31 12:28:11 +00:00
Anthony Williams
cac0eaa6c3 Put static functions inside extern "C" block rather than trying to declare each as extern "C"
[SVN r72176]
2011-05-26 09:00:58 +00:00
Anthony Williams
a64fa2c18f extern "C" functions are static
[SVN r72166]
2011-05-25 21:18:59 +00:00
Neil Groves
f07640850b [boost][thread] - Resolved Ticket 5170 by making the extern "C" functions static.
[SVN r72120]
2011-05-23 13:24:16 +00:00
Marshall Clow
ab665c8c56 Merge fixes to release; Fixes #1988
[SVN r71676]
2011-05-02 20:56:53 +00:00
Marshall Clow
e43586ffac Renamed BOOST_NO_THREADEX -> BOOST_HAS_THREADEX and BOOST_NO_GETSYSTEMTIMEASFILETIME --> BOOST_HAS_GETSYSTEMTIMEASFILETIME - Refs #1988
[SVN r71533]
2011-04-27 15:51:07 +00:00
Anthony Williams
9cc243837d Fixed typo
[SVN r70470]
2011-03-23 08:17:45 +00:00
Anthony Williams
de7e3baabc Applied patch from issue #4849
[SVN r70383]
2011-03-21 23:09:07 +00:00
Anthony Williams
7ec9804540 Merged Boost.Thread changes from trunk
[SVN r70382]
2011-03-21 22:59:40 +00:00
Anthony Williams
5e29afcb57 Remove inner definition of cond_res from timed_wait so outer variable
is set correctly


[SVN r69621]
2011-03-07 08:39:37 +00:00
Anthony Williams
0a1085d9be Patch condition variables to ensure that the cond mutex is unlocked before we try and check for interruption
[SVN r69547]
2011-03-04 15:44:53 +00:00
David Deakins
0439d53704 Minor patch to fix support for Windows CE (use 0xFFFFFFFF in place of TLS_OUT_OF_INDEXES on Windows CE since Windows CE does not define this constant).
[SVN r69115]
2011-02-21 04:07:13 +00:00
Hartmut Kaiser
7c9116af2e Spirit: merge from trunk
[SVN r68078]
2011-01-13 02:11:19 +00:00
Hartmut Kaiser
5ac2ff4521 Reverted accidental commit, sorry...
[SVN r67895]
2011-01-09 22:21:03 +00:00
Hartmut Kaiser
8565a3e472 Spirit: replaced proto::lit with spirit::lit
[SVN r67754]
2011-01-07 17:50:06 +00:00
Anthony Williams
3648bc8cb0 Throw condition_error if pthread_cond_wait fails, rather than asserting
[SVN r67734]
2011-01-06 22:49:41 +00:00
Anthony Williams
70584af9c0 Merged fix for issue #4736 from trunk
[SVN r66588]
2010-11-15 10:13:12 +00:00
Anthony Williams
73121eda9d Better fix for #4736 --- ensure we have tried to allocate TLS value
before complaining that it's not there, especially in native threads


[SVN r66518]
2010-11-12 09:11:22 +00:00
Anthony Williams
381554f8bc Merged fix for issue #4736 from trunk
[SVN r66482]
2010-11-10 11:24:52 +00:00
Anthony Williams
768e92b0e9 Added comment about lack of cleanup on native threads on some platforms
[SVN r66480]
2010-11-10 10:02:42 +00:00
Anthony Williams
98333b7dcf fix for issue #4736 --- avoid setting tls data after the key has been destroyed
[SVN r66471]
2010-11-09 12:54:23 +00:00
Anthony Williams
4dc1cb1ba1 Merged Boost.Thread from trunk
[SVN r66259]
2010-10-29 23:27:00 +00:00
Anthony Williams
4e0007780c Fix for issue #2330 - remove race condition in condition_variable::wait wrt interruption checking
[SVN r66228]
2010-10-28 14:18:00 +00:00
Vladimir Prus
506019dd62 Remove debug print
[SVN r66171]
2010-10-25 07:52:02 +00:00
Anthony Williams
10f0c3e08e Fix for issue #4531 --- promise::lazy_init uses shared_ptr atomic access functions to avoid race
[SVN r66146]
2010-10-22 14:01:12 +00:00
Anthony Williams
fa2950a04b Fix for #4650 --- put tss_cleanup_implemented in the boost namespace
[SVN r66142]
2010-10-22 09:58:33 +00:00
Anthony Williams
ebfb62ca49 Fixed issue #4727 --- only use microsec clock if available
[SVN r66141]
2010-10-22 09:26:15 +00:00
Anthony Williams
96023e81af Fix for issue #4258 --- static linking now works with recent versions of the mingw runtime
[SVN r66140]
2010-10-22 08:57:19 +00:00
Vladimir Prus
e30be60bc4 Merge r64010, wherein jam has been moved.
[SVN r65233]
2010-09-04 11:02:21 +00:00
Andrey Semashev
7bfafec128 Fixed compilation with MSVC and, probably, other compilers.
[SVN r64999]
2010-08-25 16:41:08 +00:00
Andrey Semashev
9c07d0ff5d Fixed compilation with MSVC and, probably, other compilers.
[SVN r64996]
2010-08-25 15:25:16 +00:00
Anthony Williams
e12d2bc486 Marged changes to Boost.Thread from trunk
[SVN r63915]
2010-07-12 07:47:39 +00:00
Anthony Williams
72a85b396c Fix for issue #4368 --- ensure mutex is destroyed if setattr call fails
[SVN r63799]
2010-07-09 22:00:51 +00:00
Anthony Williams
87786091bb Tidied up call_once to remove unused throw_count stuff
[SVN r63796]
2010-07-09 21:21:48 +00:00
Anthony Williams
784494274b Fix for issue #4225 to allow static initialization of boost::once_flag
[SVN r63795]
2010-07-09 21:15:57 +00:00
Anthony Williams
68012dd92c Fix for issue #4413 --- allow wait_for_any to work with empty ranges
[SVN r63790]
2010-07-09 19:18:16 +00:00
Anthony Williams
a37d2a1364 Merged boost.thread changes over from trunk
[SVN r63789]
2010-07-09 19:13:09 +00:00
Anthony Williams
e40be775fe Ensure futures and shared_mutex work on MSVC-10; fix for issue #2501
[SVN r63750]
2010-07-08 15:25:45 +00:00
Anthony Williams
64e6924132 Moved the test for _GNU_SOURCE to last to try and fix issue #4395
[SVN r63701]
2010-07-06 15:12:21 +00:00
Anthony Williams
4bbf47086d Added missing "typename"
[SVN r63651]
2010-07-05 14:37:13 +00:00
Anthony Williams
7c674bc255 Added overload for swap member function that takes an lvalue reference
in all cases


[SVN r63650]
2010-07-05 14:35:45 +00:00
Daniel James
cc662c102c Merge documentation fixes.
* Use `doc/src/*.css` instead of `doc/html/*.css`.
* Remove wiki and people directories.
* Some documentation fixes.
* Left out `minimal.css` changes and boostbook changes because of clashes.


[SVN r63347]
2010-06-26 12:30:09 +00:00
Steven Watanabe
6b9a2d791b Protect get_thread_info from macro expansion to prevent errors on Haiku. Fixes #4341.
[SVN r63295]
2010-06-24 19:38:16 +00:00
Steven Watanabe
4551e8759b Use __SUNPRO_CC instead of SUNPRO_CC. Fixes #4363.
[SVN r63216]
2010-06-22 01:59:23 +00:00
Daniel James
9442976bdb Update various libraries' documentation build.
Mostly to use the images and css files under doc/src instead of
doc/html, usually be deleting the settings in order to use the defaults.
Also add 'boost.root' to some builds in order to fix links which rely on
it.

[SVN r63146]
2010-06-20 18:00:48 +00:00
Steven Watanabe
8d07df176f Fix non-friend stream operator of thread::id
[SVN r62804]
2010-06-11 14:49:07 +00:00
Steven Watanabe
4b22aff33e Add old auto-link macro for backwards compatibility.
[SVN r62802]
2010-06-11 14:38:28 +00:00
Anthony Williams
93dee254d0 Don't use windows threads if BOOST_DISABLE_WIN32 defined. Fix for
issue #3760


[SVN r62723]
2010-06-10 08:43:10 +00:00
Anthony Williams
a29b598205 Fix for issue #3761 --- if define operator<< for thread::id outside
the class if not supported inside.


[SVN r62722]
2010-06-10 08:34:52 +00:00
Anthony Williams
e3b20eaae9 Remove warnings. Fix for issue #3611
[SVN r62721]
2010-06-10 08:22:39 +00:00
Anthony Williams
d369fb0f94 Emulate recursive mutex if pthread_mutexattr_settype not
available. Fix for issue #2955


[SVN r62720]
2010-06-10 08:10:26 +00:00
Anthony Williams
d816bca42f Only apply Sunpro workarounds for older compilers. Fix for issue #4071
[SVN r62719]
2010-06-10 07:43:17 +00:00
Anthony Williams
d6bb11c4e9 Added __cdecl to PVAPI. Fix for issue #1470
[SVN r62718]
2010-06-10 07:40:12 +00:00
Anthony Williams
2fdcefac05 Added static cast in move of upgrade_lock to work with MSVC10 and g++4.5
[SVN r62717]
2010-06-10 07:38:23 +00:00
Anthony Williams
044c3cc11e Explicitly cast to rvalue reference in cast_to_rval so it works with
MSVC10 and g++4.5


[SVN r62715]
2010-06-10 07:36:57 +00:00
Anthony Williams
bd9223b525 Don't warn about long long usage with gcc. Fix for issue #3680
[SVN r62654]
2010-06-09 13:04:06 +00:00
Anthony Williams
347703dab2 Changed while(true) to for(;;) to avoid warnings. Fix for issue #3195
[SVN r62652]
2010-06-09 12:36:11 +00:00
Anthony Williams
f9a0e450e1 Removed thread_info_mutex as unnecessary and cause of potentially-throwing destructor. Fix for issue #3097
[SVN r62650]
2010-06-09 11:35:41 +00:00
Anthony Williams
f6b8cdd1f5 Use BOOST_THREAD_DYN_LINK instead of BOOST_THREAD_DYN_DLL for
compatibility with the rest of boost. Fix for issue #2874


[SVN r62643]
2010-06-09 08:55:09 +00:00
Anthony Williams
6727013302 Use time_duration::tick_type rather than long when calculating due
time to fix issue #4318


[SVN r62642]
2010-06-09 08:19:47 +00:00
Anthony Williams
cda12a2660 Added BOOST_THREAD_DECL to friend declaration of
this_thread::get_id. Fix for issue #4316


[SVN r62641]
2010-06-09 07:59:31 +00:00
Anthony Williams
c3c2072472 Added unimplemented default constructor to derived to avoid complaints
about the constructors of T in some compilers. Fix for issue #4317


[SVN r62639]
2010-06-09 07:52:25 +00:00
Anthony Williams
bfc226fdc0 Add extra braces to fix issue #4321
[SVN r62638]
2010-06-09 07:46:29 +00:00
Anthony Williams
fd28e1a7fb Added missing #includes. Fix for issue #4322
[SVN r62637]
2010-06-09 07:40:09 +00:00
Anthony Williams
b11911f5e5 Moved thread startup and shutdown hooks to namespace boost
[SVN r62636]
2010-06-09 07:37:44 +00:00
Anthony Williams
a1587d070f Replace use of noncopyable with private copy operations, issue #3244
[SVN r62633]
2010-06-09 06:58:35 +00:00
Anthony Williams
df2f43bc61 Added documentation for this_thread::sleep overload that takes a
system_time. see issue #3179


[SVN r62632]
2010-06-09 06:48:37 +00:00
Anthony Williams
895e8eea52 Added "inline" on system_time overload of timed_wait to fix issue #2747
[SVN r62631]
2010-06-09 06:42:57 +00:00
Anthony Williams
97d6249f3b Added patch from issue #4305 --- limit SunCC workarounds to older versions
[SVN r62601]
2010-06-08 21:39:56 +00:00
Anthony Williams
7a8ed98eb5 Removed commented out code
[SVN r62564]
2010-06-08 13:06:58 +00:00
Anthony Williams
d611eece19 Updated tests for mutex members to handle range-based lock() and try_lock(), and fix issue #2704
[SVN r62562]
2010-06-08 12:06:03 +00:00
Anthony Williams
a99320f5a4 Updated get_due_time to handle the case where a "tick" is less than
100ns, trac issue #2447


[SVN r62555]
2010-06-08 08:40:46 +00:00
Anthony Williams
c97484943a Check limits when attempting to lock shared_mutex --- trac issue #2293
[SVN r62553]
2010-06-08 07:28:53 +00:00
Anthony Williams
547d9bd844 Fix for issue #868 --- provide element_type typedef
[SVN r62552]
2010-06-08 07:11:28 +00:00
Anthony Williams
1a65aab05a Applied patch from ticket 2918
[SVN r62505]
2010-06-07 09:08:09 +00:00
Anthony Williams
2e869aeb86 Added documentation for thread move assignment
[SVN r62504]
2010-06-07 09:04:54 +00:00
Anthony Williams
d729776575 Added documentation of thread move constructor
[SVN r62503]
2010-06-07 08:59:27 +00:00
Anthony Williams
895c436405 Fix for issue #4238: timed_lock_upgrade should not call timed_lock
[SVN r62502]
2010-06-07 08:43:15 +00:00
Anthony Williams
4ae2932792 Fix copy constructor and copy-assignment operator for condition_variable_any
[SVN r62501]
2010-06-07 08:28:42 +00:00
Anthony Williams
a52be2bdbb Consistently use count_type rather than unsigned for indexes into
future waiters vector


[SVN r62500]
2010-06-07 08:25:43 +00:00
Anthony Williams
31c4792216 Added missing inline
[SVN r62229]
2010-05-26 06:48:58 +00:00
Anthony Williams
39fd9c0b47 Fix for trac issue #3269
[SVN r62123]
2010-05-21 17:14:23 +00:00
Anthony Williams
9c25df3402 Sleeping for a negative time is same as sleeping for 0ms, fix for
issue #3178


[SVN r62122]
2010-05-21 16:59:56 +00:00
Anthony Williams
fb150b5038 Added support for BOOST_NO_IOSTREAM
[SVN r62119]
2010-05-21 15:19:06 +00:00
Anthony Williams
8cff3a167e Added documentation for boost::move on thread objects
[SVN r62079]
2010-05-18 08:25:02 +00:00
Anthony Williams
2be1431f60 Test for __APPLE__ before _GNU_SOURCE so we can compile on Intel/Darwin
[SVN r62053]
2010-05-17 08:22:14 +00:00
Anthony Williams
255b7ed7f6 Fix for compile error win Sun CC 5.9
[SVN r61618]
2010-04-27 13:23:00 +00:00
Anthony Williams
58fd27399e Added patch to fix issue #2501
[SVN r61429]
2010-04-20 15:02:47 +00:00
Anthony Williams
65d2898ff0 Merged changes to boost.thread over from trunk
[SVN r60991]
2010-04-01 15:04:15 +00:00
Anthony Williams
5f88ba1e47 Fix use of rvalue ref in futures
[SVN r60990]
2010-04-01 12:56:44 +00:00
Anthony Williams
ab569461d8 Modified boost::thread to work with MSVC10 RC
[SVN r59856]
2010-02-23 13:46:13 +00:00
Anthony Williams
7093fc670b Disable templated rvalue ref constructor for MSVC10
[SVN r59758]
2010-02-19 09:54:00 +00:00
Anthony Williams
6f2b030253 Fixes to some uses of rvalue references; patch to avoid var size warnings on 64-bit platforms in future.hpp
[SVN r59752]
2010-02-18 21:54:46 +00:00
Anthony Williams
0e61e679af Overload boost::move for thread& and thread&&
[SVN r59727]
2010-02-17 08:34:09 +00:00
Anthony Williams
b40998e1b5 Changed boost.thread to use BOOST_NO_RVALUE_REFERENCES rather than BOOST_HAS_RVALUE_REFS
[SVN r59699]
2010-02-16 14:57:30 +00:00
Anthony Williams
174d701bc3 Using BOOST_ASSERT rather than assert
[SVN r57940]
2009-11-26 09:35:31 +00:00
Anthony Williams
f2143d08b9 Added missing BOOST_THREAD_DECL for at_thread_exit_function
[SVN r57937]
2009-11-26 08:13:44 +00:00
Anthony Williams
1273e2620d Don't use timed_lock to do a lock
[SVN r57936]
2009-11-26 08:13:01 +00:00
Anthony Williams
c719f6e37e Added test and fix for issue 2742
[SVN r57925]
2009-11-25 11:05:55 +00:00
Anthony Williams
37922d8ce0 Added a wait call to new call_once
[SVN r57924]
2009-11-25 09:42:29 +00:00
Anthony Williams
7b79a31f40 A partial fix for issue #2100: use boost::throw_exception for all exceptions except thread_interrupted
[SVN r57912]
2009-11-24 21:49:27 +00:00
Anthony Williams
9a09406f77 Ensure call_once event is correctly cleaned up
[SVN r57889]
2009-11-24 11:52:09 +00:00
Anthony Williams
9bdb778478 Only allocate an event if there is contention in call_once
[SVN r57882]
2009-11-24 09:59:21 +00:00
Anthony Williams
9621dafe46 Clarify note on call_once
[SVN r57862]
2009-11-23 11:31:08 +00:00
Anthony Williams
d7c9837844 Added a note highlighting that recursive use of call_once will cause deadlock.
[SVN r57861]
2009-11-23 11:24:53 +00:00
Anthony Williams
9087fd904d Merged documentation changes to boost.thread (re at_thread_exit) from trunk
[SVN r57381]
2009-11-04 21:48:18 +00:00
Anthony Williams
27bb7803ae Update docs for at_thread_exit
[SVN r57380]
2009-11-04 21:38:45 +00:00
Anthony Williams
66ac6942b6 Merged boost.thread changes from trunk
[SVN r57243]
2009-10-30 09:50:13 +00:00
Anthony Williams
c0e1086f2c More fixes for compilers with rvalue ref support
[SVN r57173]
2009-10-27 13:22:08 +00:00
Anthony Williams
ffa751c617 Fix for move assignment of unique_lock if rvalue refs supported
[SVN r57171]
2009-10-27 10:40:57 +00:00
Anthony Williams
b8ad60a2d6 Fix for bug #2067 --- use shared_mutex for thread_group rather than a simple mutex
[SVN r57169]
2009-10-27 09:45:53 +00:00
Anthony Williams
5db0aac816 Added futures to boost.thread
[SVN r57064]
2009-10-22 09:33:21 +00:00
Anthony Williams
20980fe54d Merged thread changes from trunk
[SVN r56992]
2009-10-19 09:18:13 +00:00
Troy D. Straszheim
3fae7c5184 rm cmake from trunk. I'm not entirely sure this is necessary to satisfy the inspect script, but I'm not taking any chances, and it is easy to put back
[SVN r56942]
2009-10-17 02:07:38 +00:00
Troy D. Straszheim
fb54acfe69 rm cmake from the release branch before it goes out broken. Policy dictates that you never commit to release, you commit to trunk and merge to release.
[SVN r56941]
2009-10-17 01:10:45 +00:00
Anthony Williams
47889a8f22 boost.thread exception types are now header-only so some uses of boost.thread can be header only
[SVN r56019]
2009-09-04 19:55:31 +00:00
Troy D. Straszheim
8d22c3869b Copyrights on CMakeLists.txt to keep them from clogging up the inspect
reports.  This is essentially the same commit as r55095 on the release
branch.



[SVN r55159]
2009-07-26 00:49:56 +00:00
Troy D. Straszheim
0e69edd066 Add basic copyright/license to keep cmake out of the inspection report
[SVN r55095]
2009-07-22 21:51:01 +00:00
Vladimir Prus
235ed4afe0 Check _GNU_SOURCE before using get_nprocs.
The latter function is not POSIX, but a GNU extension and therefore
not available universally.


[SVN r54408]
2009-06-27 09:22:41 +00:00
Anthony Williams
627cb7f774 Fixed typo
[SVN r53412]
2009-05-29 20:48:07 +00:00
Anthony Williams
09021af350 Changed thread_specific_ptr to use a map for faster lookup, and erase empty nodes
[SVN r53389]
2009-05-29 11:34:25 +00:00
Anthony Williams
31c280d1fa TSS cleanup not called for NULL data
[SVN r53388]
2009-05-29 11:05:01 +00:00
Anthony Williams
629f344f34 Test and fix for first part of issue #2797
[SVN r53387]
2009-05-29 10:57:39 +00:00
Anthony Williams
db5f924e24 Remove commented-out thread_group code
[SVN r53386]
2009-05-29 10:45:06 +00:00
Anthony Williams
9be3eb282a Attempts to improve the boost::thread move semantics; separated tests to give clearer ID; incorporated patch to fix issue #2062
[SVN r53385]
2009-05-29 09:57:15 +00:00
John Maddock
effd891a16 Remove options that are no longer required and get the PDF docs building.
[SVN r51142]
2009-02-09 16:26:26 +00:00
Anthony Williams
13db35cbf5 Undo commit from r49977 which added extraneous throw to thread example
[SVN r49978]
2008-11-28 11:01:21 +00:00
Anthony Williams
0f2d480e3c Added test for making std::thread work with std::vector
[SVN r49977]
2008-11-28 10:57:12 +00:00
Anthony Williams
9edc61e37b Removed controversial catch(...) clauses from thread class
[SVN r49969]
2008-11-27 21:15:37 +00:00
Michael A. Jackson
f4dab6aac5 Updating CMake files to latest trunk. Added dependency information for regression tests and a few new macros for internal use.
[SVN r49627]
2008-11-07 17:02:56 +00:00
Michael A. Jackson
9e0550d140 Continuing merge of CMake build system files into trunk with the encouragement of Doug Gregor
[SVN r49510]
2008-11-01 13:15:41 +00:00
Anthony Williams
0d1701c509 Enhanced thread move tests
[SVN r49124]
2008-10-03 07:02:57 +00:00
Anthony Williams
f2f62f93ea Test and fix for trac issue #2380: return boost::move(some_thread) now works
[SVN r49112]
2008-10-02 16:39:03 +00:00
Anthony Williams
8a329f66fb Renamed lock variables to lk to avoid name shadow warnings
[SVN r49013]
2008-09-29 16:32:24 +00:00
Anthony Williams
05d4c52918 fixed check on return code from pthread_mutex_timedlock
[SVN r48997]
2008-09-29 09:04:13 +00:00
Anthony Williams
8fd0dd0cc0 Define a raw DLL main which is called by the C runtime if we're statically linked into a DLL --- fix for issue #2199
[SVN r48537]
2008-09-02 16:56:57 +00:00
Anthony Williams
8eea5811ba Don't allocate TLS Key unless we need it; deallocate it on process exit --- partial fix for bug #2199
[SVN r48536]
2008-09-02 16:54:56 +00:00
Anthony Williams
a154c2adab Removed locked and get_active_count
[SVN r48531]
2008-09-02 10:38:17 +00:00
Anthony Williams
10bf4ed576 Removed locked and get_active_count
[SVN r48530]
2008-09-02 10:38:04 +00:00
Anthony Williams
60d12dd395 Added recursive_mutex/condition::wait() change to list of breaking changes
[SVN r48528]
2008-09-02 10:22:06 +00:00
Anthony Williams
b4e9be3c52 Added missing relative time constructor to unique_lock
[SVN r48213]
2008-08-19 10:26:53 +00:00
Anthony Williams
dcebae6d4a Renamed internal bind stuff to invoker, as more expressive
[SVN r48209]
2008-08-19 07:03:22 +00:00
Anthony Williams
0d776bcd26 Updated changes list
[SVN r48037]
2008-08-08 20:37:30 +00:00
Anthony Williams
2d6ed47cf2 Updated signature of create_thread
[SVN r48036]
2008-08-08 20:21:29 +00:00
Anthony Williams
ea06434425 Doc updates missed by previous checkin
[SVN r47826]
2008-07-26 08:37:55 +00:00
Anthony Williams
6508eff95e Added note about max number of arguments
[SVN r47818]
2008-07-25 22:22:58 +00:00
Anthony Williams
69930684a9 Added a description for the new thread constructors that allow functions with arguments.
[SVN r47817]
2008-07-25 22:21:05 +00:00
Anthony Williams
b1931a3eda Fix for trac issue #2118
[SVN r47816]
2008-07-25 22:01:04 +00:00
Anthony Williams
63b44d4e32 Added documentation for the lock and try_lock free functions
[SVN r47815]
2008-07-25 21:57:33 +00:00
Anthony Williams
f7cb8d8141 Added a description for the scoped_try_lock typedefs
[SVN r47814]
2008-07-25 21:30:37 +00:00
Anthony Williams
48c857e02c Fix for issue #2105: specify which header to include for each class or function
[SVN r47810]
2008-07-25 21:12:29 +00:00
Anthony Williams
442dc58e0f Use sysconf(_SC_NPROCESSORS_ONLN) where it is available, as a fallback
[SVN r47654]
2008-07-21 10:39:50 +00:00
Anthony Williams
25460c652c Use sysconf to detect number of processors on AIX too
[SVN r47653]
2008-07-21 10:25:08 +00:00
Anthony Williams
31a98f0a1e BOOST_NO_SFINAE isn't enough to identify compilers that can't auto-detect mutexes, so create a new macro for that, and add IBM and Sun compilers to list
[SVN r47652]
2008-07-21 10:04:26 +00:00
Anthony Williams
36c44b6f45 Borland-specific fixes should apply to all compilers for which enable_if is broken: check for BOOST_NO_SFINAE instead
[SVN r47554]
2008-07-18 13:42:10 +00:00
Anthony Williams
27426b18d1 Split lock and try_lock into mutex and range overloads without using enable_if, so it works on Borland compilers
[SVN r47472]
2008-07-16 14:41:09 +00:00
Anthony Williams
3ea9ce1c8c Fixes to make basic thread functionality work with Borland compilers again
[SVN r47471]
2008-07-16 13:19:43 +00:00
Anthony Williams
4dfc636c84 test and fix for issue #2080
[SVN r47199]
2008-07-07 22:19:28 +00:00
Anthony Williams
5fe4312c6c test and fix for issue #2081
[SVN r47197]
2008-07-07 22:04:10 +00:00
Anthony Williams
63e675a6bb Corrected description to avoid reference to arguments
[SVN r47172]
2008-07-07 07:30:27 +00:00
Anthony Williams
e92aeac7d7 Added notify functions to class synopsis
[SVN r47171]
2008-07-07 07:28:32 +00:00
Anthony Williams
f1f7eac1f2 Backwards compatibility with xtime --- test and fix for issue #2052
[SVN r47149]
2008-07-06 21:58:11 +00:00
Anthony Williams
eff0c84553 Test and fix for issue #2076
[SVN r47120]
2008-07-05 21:55:36 +00:00
Anthony Williams
58c8ce61c7 Fix for issue #2065
[SVN r47077]
2008-07-04 15:45:52 +00:00
Anthony Williams
6ac5e6953a Qualify everything with boost:: to try and avoid name clashes on AIX
[SVN r47070]
2008-07-04 07:30:35 +00:00
Anthony Williams
5d9ad59af2 Use rvalue refs for move semantics of unique_lock where available
[SVN r47033]
2008-07-03 09:16:49 +00:00
Anthony Williams
3c48a05437 Added try_lock_upgrade to shared_mutex: second half of #1867 fix
[SVN r46961]
2008-07-01 16:28:06 +00:00
Anthony Williams
4462124ff2 Added try_lock_upgrade to shared_mutex: second half of #1867 fix
[SVN r46960]
2008-07-01 16:27:59 +00:00
Anthony Williams
373f557ef7 Reduced thread counts to make tests run faster
[SVN r46958]
2008-07-01 16:22:47 +00:00
Anthony Williams
495e561398 Partial fix for issue #1867 - ensure boost::shared_mutex supports try_lock
[SVN r46956]
2008-07-01 16:04:51 +00:00
Anthony Williams
d24a579033 Partial fix for issue #1867 - ensure boost::shared_mutex supports try_lock
[SVN r46955]
2008-07-01 16:04:43 +00:00
Anthony Williams
77130424b4 Removed tabs from source files
[SVN r46706]
2008-06-26 06:43:30 +00:00
Anthony Williams
eb30688937 Added license and copyright to docs
[SVN r46705]
2008-06-26 06:41:00 +00:00
Anthony Williams
880bac0633 Added missing include of detail/config.hpp
[SVN r46624]
2008-06-23 12:14:58 +00:00
Anthony Williams
851d6a987f Correctly remove the reference type when copying the thread function into the thread data area so we don't end up with a dangling reference
[SVN r46295]
2008-06-10 15:29:35 +00:00
Anthony Williams
9bebd7b35f Disable general templated thread constructor for movable types, in order to prevent it trying to act as a thread copy constructor for EDG based compilers
[SVN r46273]
2008-06-09 14:00:03 +00:00
Anthony Williams
309acb9597 Don't try and use _interlockedbittestandset primitives if we don't know they're present
[SVN r46219]
2008-06-07 20:54:19 +00:00
Anthony Williams
a56887167e Added swap for try_lock_wrapper
[SVN r46164]
2008-06-05 12:25:58 +00:00
Anthony Williams
e984dff4e4 Combined TSS header for pthread and win32, #1958 now fixed for pthread too
[SVN r46162]
2008-06-05 11:19:06 +00:00
Anthony Williams
685e4d446b Test and fix for bug #1958 on Win32
[SVN r46161]
2008-06-05 11:16:05 +00:00
Anthony Williams
8af680f307 Added swap for unique_lock
[SVN r46160]
2008-06-05 10:39:08 +00:00
Anthony Williams
6c60cce60d Removed partial initializer for res: both values will be assigned later, so no need to initialize either
[SVN r46124]
2008-06-04 16:05:29 +00:00
Anthony Williams
5882a675bb Added extra initializer to timeout to try and eliminate warnings with some compilers
[SVN r46123]
2008-06-04 16:03:51 +00:00
Anthony Williams
a5e95845b3 Added documentation for swap()
[SVN r46122]
2008-06-04 16:00:13 +00:00
Anthony Williams
5b83d81e40 Added free function swap() for threads
[SVN r46121]
2008-06-04 15:50:34 +00:00
Anthony Williams
c8e5ad564d basic_condition_variable::lock_entry extracted to basic_cv_lock_entry in order to try and eliminate problems on Borland compiler
[SVN r46094]
2008-06-03 20:56:39 +00:00
Anthony Williams
5edfa273ff removed unused header
[SVN r46093]
2008-06-03 20:55:40 +00:00
Anthony Williams
4db57bcb10 Move thread_data to detail namespace rather than have it as a nested type of boost::thread, to try and help compilers that have problems with the partial specializations for reference_wrapper
[SVN r45912]
2008-05-29 15:38:08 +00:00
Anthony Williams
3f13340903 Don't construct function objects directly in boost::thread constructor as some compilers can't handle that.
[SVN r45911]
2008-05-29 15:36:52 +00:00
Anthony Williams
6abb53c9d3 Move definition of constructor and destructor of condition_variable into condition_variable_fwd.hpp, so they are always available
[SVN r45909]
2008-05-29 15:16:55 +00:00
Anthony Williams
fdd20a519e Use wrapper functions in try_lock_wrapper rather than using declarations, as the latter confuse some compilers
[SVN r45908]
2008-05-29 15:16:04 +00:00
Anthony Williams
67cc49f333 More tests for generic locks, and a new range version
[SVN r45897]
2008-05-29 09:02:05 +00:00
Anthony Williams
31a34cd0b5 Added missing "no"
[SVN r45870]
2008-05-28 14:50:25 +00:00
Anthony Williams
ef8c08ba99 Removed surplus "the"
[SVN r45869]
2008-05-28 12:55:30 +00:00
Anthony Williams
2991ca6c6f Added abi prefix and suffix headers
[SVN r45865]
2008-05-28 11:02:06 +00:00
Anthony Williams
52bace18b2 hardware_concurrency works for CYGWIN
[SVN r45860]
2008-05-28 09:38:14 +00:00
Anthony Williams
767d14ae4f Added documentation for time support in the thread library
[SVN r45859]
2008-05-28 09:00:32 +00:00
Anthony Williams
1a5c911e36 Added documentation for time support in the thread library
[SVN r45858]
2008-05-28 09:00:23 +00:00
Anthony Williams
6e42a04e43 Added note about move support
[SVN r45856]
2008-05-28 08:09:07 +00:00
Anthony Williams
28be2cfeef intrusive_ptr_add_ref and intrusive_ptr_release need to be inline if defined in the header
[SVN r45809]
2008-05-27 06:32:05 +00:00
Anthony Williams
8be168fd87 Basic tests for lock() when other thread is acquiring locks in same or opposite order
[SVN r45767]
2008-05-26 08:59:48 +00:00
Anthony Williams
eee95fef57 Initial test for generic lock functions
[SVN r45766]
2008-05-26 08:40:21 +00:00
Anthony Williams
9ea179b052 Initial test for generic lock functions
[SVN r45765]
2008-05-26 08:40:13 +00:00
Anthony Williams
6868280409 Try and avoid compile errors in test_thread_callable_object_one_argument
[SVN r45764]
2008-05-26 07:36:16 +00:00
Anthony Williams
e00b764454 The signature of _interlockedbittestandset changes between MSVC 2005 and MSVC 2008
[SVN r45689]
2008-05-23 19:53:06 +00:00
Anthony Williams
999613c686 Added note about mutex not being recursive
[SVN r45688]
2008-05-23 19:33:18 +00:00
Anthony Williams
c2661d7eb5 define intrusive_ptr_add_ref and intrusive_ptr_release at namespace scope rather than inline as friends in order to try and avoid compiler problems
[SVN r45682]
2008-05-23 15:18:19 +00:00
Anthony Williams
4d21dd1f47 try_lock_wrapper implements operator! in order to try and avoid compiler problems
[SVN r45681]
2008-05-23 15:17:14 +00:00
Anthony Williams
a0a0e57527 Fixed #ifdef to actually use BTS primitives on MSVC 9
[SVN r45676]
2008-05-23 13:16:01 +00:00
Anthony Williams
d8af0d0b4e Reset thread_info on move rather than assigning 0
[SVN r45672]
2008-05-23 10:48:07 +00:00
Anthony Williams
113288e3b0 tidying up move
[SVN r45661]
2008-05-22 16:33:34 +00:00
Anthony Williams
afecfd7c2d Refactored boost::thread code to try and remove duplication
[SVN r45647]
2008-05-22 11:49:48 +00:00
Anthony Williams
94d89aac5f more rvalue reference stuff
[SVN r45626]
2008-05-21 21:11:30 +00:00
Anthony Williams
8831b13efc Use lock_guard<> instead of unique_lock<> internally. Clear out generations after notify_all, as they're all notified
[SVN r45625]
2008-05-21 21:10:45 +00:00
Peter Dimov
01f99da03a Extended boost::thread to 9 arguments, hopefully fixed member function ambiguity.
[SVN r45621]
2008-05-21 20:44:08 +00:00
Anthony Williams
080654e3ef New tests for a normal function with one argument, and a member function with 0 or 1 arguments
[SVN r45607]
2008-05-21 13:38:04 +00:00
Anthony Williams
2ac2eb2a61 try_lock_wrapper has its own operator bool_type to avoid problems with a using declaration
[SVN r45602]
2008-05-21 10:39:47 +00:00
Anthony Williams
61b940b705 Renamed namespace user to user_test_ns to try and avoid a name clash on some platforms
[SVN r45601]
2008-05-21 09:51:53 +00:00
Anthony Williams
4a4f87e017 support for a generic lock() function
[SVN r45481]
2008-05-18 09:10:20 +00:00
Anthony Williams
6d5e7f63a7 Added beginnings of real rvalue-reference support
[SVN r45479]
2008-05-18 08:45:44 +00:00
Anthony Williams
f77285f375 Updated docs to make it explicit that terminate is called if a thread function throws an exception
[SVN r45294]
2008-05-12 09:04:02 +00:00
Anthony Williams
dc5d03a6dc Cleaned up to remove warnings
[SVN r45244]
2008-05-09 07:59:57 +00:00
Anthony Williams
ea0961b7f6 Fixed type truncation warning
[SVN r45243]
2008-05-09 07:49:22 +00:00
Anthony Williams
33d9f9774c Test and fix for bug #1905
[SVN r45242]
2008-05-09 07:48:44 +00:00
Anthony Williams
86097fa038 Use _WIN32 rather than WIN32 to prevent include of <unistd.h>
[SVN r45241]
2008-05-09 07:47:14 +00:00
Anthony Williams
70d9dbc45a Added default constructor to lock types
[SVN r45212]
2008-05-08 14:34:40 +00:00
Anthony Williams
3926fd3a20 Added docs for native_handle
[SVN r45211]
2008-05-08 12:59:59 +00:00
Anthony Williams
7861cf1146 Added native_handle to mutex types where possible
[SVN r45210]
2008-05-08 12:59:10 +00:00
Anthony Williams
0516b86a6e new BTS-based mutex implementation on win32
[SVN r45119]
2008-05-04 22:39:52 +00:00
Anthony Williams
ec735d3e9b Simplified move support
[SVN r45108]
2008-05-04 09:52:54 +00:00
Anthony Williams
1c5c070983 Updated locks.hpp to work with gcc as well as msvc
[SVN r44846]
2008-04-28 12:26:27 +00:00
Anthony Williams
a5c02b73dc Added entry to breaking changes about default-constructed threads and the current thread: issue #1835
[SVN r44840]
2008-04-28 09:10:38 +00:00
Anthony Williams
918b920670 Added detail::try_lock_wrapper for use as scoped_try_lock typedefs, to fix issue #1873
[SVN r44838]
2008-04-28 09:00:58 +00:00
Anthony Williams
de67d2e27e Fixed g++ compile error
[SVN r44773]
2008-04-26 07:34:46 +00:00
Anthony Williams
bc89df04cb Revamped condition variable to try and fix swallowed-notify problems (trac issue #1834)
[SVN r44699]
2008-04-21 16:22:16 +00:00
Anthony Williams
c26a4cf082 added private copy assignment operator and copy constructor to remove warnings
[SVN r44698]
2008-04-21 16:20:31 +00:00
Anthony Williams
6e1a866b13 Fix for issue #1657
[SVN r44424]
2008-04-14 21:04:33 +00:00
Anthony Williams
f91986ad0d Added extended adopt/defer/try constructors to upgrade_lock
[SVN r44370]
2008-04-13 15:50:08 +00:00
Anthony Williams
795cc23f3e Added test and fix for win32 condition_variable broadcast bug similar to #1803
[SVN r44168]
2008-04-11 08:52:09 +00:00
Anthony Williams
a3695bd4a0 Updated thread.hpp as catch-all header
[SVN r44153]
2008-04-10 18:34:42 +00:00
Anthony Williams
08dc521daf Added native_handle to condition_variable on pthreads
[SVN r44152]
2008-04-10 15:52:01 +00:00
Anthony Williams
8b916d21b1 added tests for plain timed_lock on shared_mutex
[SVN r44150]
2008-04-10 14:15:26 +00:00
Anthony Williams
c40f47a78a added overloads of timed_lock_shared with a relative timeout to shared_mutex
[SVN r44149]
2008-04-10 14:07:39 +00:00
Anthony Williams
e9fb470b06 Added native_handle to thread on posix platforms
[SVN r44148]
2008-04-10 13:35:07 +00:00
Anthony Williams
343d049772 fix for trac ticket #1804
[SVN r44147]
2008-04-10 13:27:44 +00:00
Anthony Williams
86f9480da4 fix for notify problem in trac ticket #1803
[SVN r44146]
2008-04-10 13:14:43 +00:00
Anthony Williams
8696b610ca Added test for trac ticket #1803: condition_variable::notify_one may fail to wake a waiting thread on win32
[SVN r44136]
2008-04-09 19:33:06 +00:00
Anthony Williams
6f13227eda Added locked-> owns_lock change to breaking changes
[SVN r44089]
2008-04-07 13:09:36 +00:00
Anthony Williams
58d5110e61 removed forward declaration for undefined type exclusive_lock
[SVN r43847]
2008-03-24 21:44:36 +00:00
Anthony Williams
76e53c7bc5 Removed some warnings: those from issue #1640 and others
[SVN r43730]
2008-03-19 17:25:13 +00:00
Anthony Williams
cfb08be1a8 New documentation for new thread library
[SVN r43671]
2008-03-17 10:29:27 +00:00
Anthony Williams
b5bbb7fb1c Test and fix for bug #1693 to ensure thread_specific_ptr works as desired
[SVN r43666]
2008-03-17 08:36:09 +00:00
Anthony Williams
a76c33f8cc made the callable_no_args function object a named object rather than a temporary, in order to avoid gratuitous breakage on some compilers
[SVN r43528]
2008-03-06 07:59:16 +00:00
Anthony Williams
810306b8f3 thread constructor now accepts up to three additional arguments to pass to thread function
[SVN r43464]
2008-03-03 10:52:44 +00:00
Anthony Williams
6c22bdb3bd Test and fix for issue #1665
[SVN r43461]
2008-03-03 08:44:42 +00:00
Daniel James
6a0d3e98bc Fix broken copyright urls. Fixes #1573.
[SVN r43422]
2008-02-27 18:51:14 +00:00
Anthony Williams
3809321037 added test for duration overloads of timed_lock, and added missing implementation to win32 version
[SVN r43094]
2008-02-04 13:16:32 +00:00
Anthony Williams
eef695bdf0 Provide tss_cleanup_implemented as a dummy function on Windows CE to allow tests to run
[SVN r42818]
2008-01-16 15:23:36 +00:00
Anthony Williams
ab01ab1e4d removed references to NULL
[SVN r42657]
2008-01-10 14:19:36 +00:00
Anthony Williams
c8d8a108a7 Updated thread ID test
[SVN r42228]
2007-12-21 10:54:59 +00:00
Anthony Williams
7afd9efcc5 added hardware_concurrency support for apple, freebsd and sun platforms
[SVN r42195]
2007-12-20 08:37:02 +00:00
Anthony Williams
56ded87ad2 added missing parentheses
[SVN r42194]
2007-12-20 07:46:00 +00:00
Anthony Williams
82e503339b Implement hardware_concurrency for pthread
[SVN r42168]
2007-12-19 10:45:01 +00:00
Anthony Williams
713d0c7ace Updated thread ID, and added tests
[SVN r42166]
2007-12-19 10:39:45 +00:00
Anthony Williams
25ad6e3f8f boost::move support for locks
[SVN r42118]
2007-12-17 12:52:50 +00:00
Anthony Williams
df0197b617 Updated move function test to be fair to Borland
[SVN r42117]
2007-12-17 11:24:13 +00:00
Anthony Williams
a89c4f01ad explicit move functions for threads, with a test
[SVN r42087]
2007-12-15 22:36:43 +00:00
Anthony Williams
ae67099633 added timed_wait overloads that take a duration
[SVN r42086]
2007-12-15 22:34:30 +00:00
Anthony Williams
57542d3a5c fixed order of comparison in timeout check
[SVN r41819]
2007-12-07 08:11:11 +00:00
Anthony Williams
9a1da14116 improved timeout checks
[SVN r41741]
2007-12-05 10:58:45 +00:00
Anthony Williams
ed050d753d added missing include of detail/config.hpp
[SVN r41738]
2007-12-05 08:27:44 +00:00
Anthony Williams
8bec363710 changed order of declaration to eliminate warnings
[SVN r41687]
2007-12-04 14:07:01 +00:00
Anthony Williams
7c68e190a9 Added test for thread move constructor; implemented move on pthreads
[SVN r41686]
2007-12-04 13:02:58 +00:00
Anthony Williams
7ebf5ea3d1 add explicit casts to remove warnings
[SVN r41684]
2007-12-04 12:08:38 +00:00
Anthony Williams
11e0435a4b don't dllexport/dllimport inline functions
[SVN r41683]
2007-12-04 11:44:25 +00:00
Anthony Williams
d15ee57cd1 split shared mutex tests in two to take less time
[SVN r41682]
2007-12-04 10:04:30 +00:00
Anthony Williams
56d660b7fd changed boost::move to boost::detail::thread_move to fix issue #1492
[SVN r41681]
2007-12-04 09:15:37 +00:00
Anthony Williams
792958e693 fixed typo in condition_variable_any::timed_wait
[SVN r41679]
2007-12-04 07:57:23 +00:00
Anthony Williams
914e67dc04 check predicate before returning if we time out on a predicated version of timed_wait
[SVN r41668]
2007-12-03 22:00:26 +00:00
Anthony Williams
b50a7ccb61 interruptible_wait (and hence condition timed_wait) now uses a WaitableTimer where possible, to be robust in the face of clock changes
[SVN r41505]
2007-11-30 18:38:21 +00:00
Anthony Williams
f827709d42 add support for relative timeouts to condition timed_wait
[SVN r41413]
2007-11-27 14:24:29 +00:00
Anthony Williams
36abb42175 reverted accidental checkin of new timed_wait functions on condition_variable
[SVN r41405]
2007-11-26 21:15:04 +00:00
Anthony Williams
40f3b1b4c8 once_flag uses zero-initialization on POSIX as well as windows
[SVN r41401]
2007-11-26 17:01:08 +00:00
Anthony Williams
4f35e25688 fixed import/export declarations so new once code works with pthread-win32
[SVN r41398]
2007-11-26 15:44:07 +00:00
Anthony Williams
270e88edd7 Don't compare native_handle_t against 0 --- do appropriate checks in create_native_thread for platforms where pthread_t is not comparable
[SVN r41396]
2007-11-26 13:29:15 +00:00
Anthony Williams
5ded171247 workaround for Borland compiler
[SVN r41395]
2007-11-26 12:17:45 +00:00
503 changed files with 61314 additions and 4298 deletions

View File

@@ -1,22 +0,0 @@
#----------------------------------------------------------------------------
# This file was automatically generated from the original CMakeLists.txt file
# Add a variable to hold the headers for the library
set (lib_headers
thread.hpp
thread
)
# Add a library target to the build system
boost_library_project(
thread
SRCDIRS src
TESTDIRS test
HEADERS ${lib_headers}
# DOCDIRS
# DESCRIPTION
MODULARIZED
# AUTHORS
# MAINTAINERS
)

View File

@@ -1,6 +1,7 @@
# $Id$
# Copyright 2006-2007 Roland Schwarz.
# Copyright 2007 Anthony Williams
# 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)
@@ -39,11 +40,94 @@ import path ;
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
: default-build <threading>multi
<toolset>gcc:<cxxflags>-Wno-long-long
#<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
<toolset>gcc:<cxxflags>-Wextra
<toolset>gcc:<cxxflags>-pedantic
<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>-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
<toolset>pathscale:<cxxflags>-pedantic
<toolset>clang:<cxxflags>-Wextra
<toolset>clang:<cxxflags>-pedantic
#<toolset>clang:<cxxflags>-ansi
#<toolset>clang:<cxxflags>-fpermissive
<toolset>clang:<cxxflags>-Wno-long-long
<toolset>clang:<cxxflags>-Wunused-function
<toolset>clang:<cxxflags>-Wno-variadic-macros
<toolset>gcc-mingw-4.4.0:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.5.0:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.6.0:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.6.3:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.7.0:<cxxflags>-fdiagnostics-show-option
<toolset>gcc-mingw-4.8.0:<cxxflags>-fdiagnostics-show-option
#<toolset>gcc:<cxxflags>-Wno-missing-field-initializers
<toolset>darwin-4.6.2:<cxxflags>-Wno-delete-non-virtual-dtor
<toolset>darwin-4.7.0:<cxxflags>-Wno-delete-non-virtual-dtor
#<toolset>clang-2.8:<cxxflags>-Wno-delete-non-virtual-dtor
#<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-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_THREAD_THROW_IF_PRECONDITION_NOT_SATISFIED
#<define>BOOST_SYSTEM_NO_DEPRECATED
#<define>BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
<library>/boost/system//boost_system
;
local rule default_threadapi ( )
@@ -59,19 +143,19 @@ feature.set-default threadapi : [ default_threadapi ] ;
rule tag ( name : type ? : property-set )
{
local result = $(name) ;
if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB
{
local api = [ $(property-set).get <threadapi> ] ;
# non native api gets additional tag
if $(api) != [ default_threadapi ] {
result = $(result)_$(api) ;
}
}
# forward to the boost tagging rule
return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
$(result) : $(type) : $(property-set) ] ;
}
@@ -129,7 +213,7 @@ rule win32_pthread_paths ( properties * )
.notified = true ;
}
}
else
else
{
result += <include>$(include_path) ;
result += <library>$(lib_path) ;
@@ -151,6 +235,12 @@ rule usage-requirements ( properties * )
# in that case?
}
}
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) ;
}
@@ -161,7 +251,7 @@ rule requirements ( properties * )
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
if <target-os>windows in $(properties)
if <target-os>windows in $(properties)
{
local paths = [ win32_pthread_paths $(properties) ] ;
if $(paths)
@@ -174,15 +264,22 @@ rule requirements ( properties * )
}
}
}
result += <define>BOOST_THREAD_DONT_USE_CHRONO ;
if <toolset>pgi in $(properties) || <toolset>vacpp in $(properties)
{
result += <library>/boost/atomic//boost_atomic ;
}
return $(result) ;
}
alias thread_sources
: ## win32 sources ##
win32/thread.cpp
win32/exceptions.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
future.cpp
: ## requirements ##
<threadapi>win32
;
@@ -190,8 +287,8 @@ alias thread_sources
alias thread_sources
: ## pthread sources ##
pthread/thread.cpp
pthread/exceptions.cpp
pthread/once.cpp
future.cpp
: ## requirements ##
<threadapi>pthread
;

View File

@@ -1,4 +1,5 @@
# (C) Copyright 2008 Anthony Williams
# (C) Copyright 2008-11 Anthony Williams
# (C) Copyright 2011-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)
@@ -15,22 +16,17 @@ boostbook standalone
# Use graphics not text for navigation:
<xsl:param>navig.graphics=1
# How far down we chunk nested sections, basically all of them:
<xsl:param>chunk.section.depth=3
<xsl:param>chunk.section.depth=2
# Don't put the first section on the same page as the TOC:
<xsl:param>chunk.first.sections=1
# How far down sections get TOC's
<xsl:param>toc.section.depth=10
<xsl:param>toc.section.depth=4
# Max depth in each TOC:
<xsl:param>toc.max.depth=3
<xsl:param>toc.max.depth=2
# How far down we go with TOC's
<xsl:param>generate.section.toc.level=10
# Path for links to Boost:
<xsl:param>boost.root=../../../..
# Path for libraries index:
<xsl:param>boost.libraries=../../../../libs/libraries.htm
# Use the main Boost stylesheet:
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
;

View File

@@ -18,6 +18,9 @@ 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);
~barrier();
@@ -63,7 +66,10 @@ are unblocked, and the barrier is reset. ]]
[[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].]]
]

View File

@@ -1,11 +1,320 @@
[/
(C) Copyright 2007-8 Anthony Williams.
(C) Copyright 2007-11 Anthony Williams.
(C) Copyright 2011-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:changes Changes since boost 1.35]
[section:changes History]
[/
[heading Version 4.2.0 - boost 1.55]
[*New Features:]
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
[*Fixed Bugs:]
]
[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/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/8530 #8530] [Coverity] Unused variable thread_handle, uninitialized variable cond_mutex in thread/pthread/thread_data.hpp
* [@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.
[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.
* [@http://svn.boost.org/trac/boost/ticket/2637 #2637] Request for shared_mutex duration timed_lock and timed_lock_shared.
* [@http://svn.boost.org/trac/boost/ticket/2741 #2741] Proposal to manage portable and non portable thread attributes.
* [@http://svn.boost.org/trac/boost/ticket/3567 #3567] Request for shared_lock_guard.
* [@http://svn.boost.org/trac/boost/ticket/6194 #6194] Adapt to Boost.Move.
* [@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/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/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.
* [@http://svn.boost.org/trac/boost/ticket/5351 #5351] interrupt a future get boost::unknown_exception.
* [@http://svn.boost.org/trac/boost/ticket/5516 #5516] Upgrade lock is not acquired when previous upgrade lock releases if another read lock is present.
* [@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 &&)
[heading Version 2.1.1 - boost 1.49]
Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2309 #2309] Lack of g++ symbol visibility support in Boost.Thread.
* [@http://svn.boost.org/trac/boost/ticket/2639 #2639] documentation should be extended(defer_lock, try_to_lock, ...).
* [@http://svn.boost.org/trac/boost/ticket/3639 #3639] Boost.Thread doesn't build with Sun-5.9 on Linux.
* [@http://svn.boost.org/trac/boost/ticket/3762 #3762] Thread can't be compiled with winscw (Codewarrior by Nokia).
* [@http://svn.boost.org/trac/boost/ticket/3885 #3885] document about mix usage of boost.thread and native thread api.
* [@http://svn.boost.org/trac/boost/ticket/3975 #3975] Incorrect precondition for promise::set_wait_callback().
* [@http://svn.boost.org/trac/boost/ticket/4048 #4048] thread::id formatting involves locale
* [@http://svn.boost.org/trac/boost/ticket/4315 #4315] gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored.
* [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds.
* [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints.
* [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x.
* [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor.
* [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6.
* [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure.
* [@http://svn.boost.org/trac/boost/ticket/5839 #5839] thread.cpp: ThreadProxy leaks on exceptions.
* [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions.
* [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems.
* [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo).
* [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio.
* [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR.
* [@http://svn.boost.org/trac/boost/ticket/6207 #6207] shared_lock swap compiler error on clang 3.0 c++11.
* [@http://svn.boost.org/trac/boost/ticket/6208 #6208] try_lock_wrapper swap compiler error on clang 3.0 c++11.
[heading Version 2.1.0 - Changes since boost 1.40]
The 1.41.0 release of Boost adds futures to the thread library. There are also a few minor changes.
[heading Changes since boost 1.35]
The 1.36.0 release of Boost includes a few new features in the thread library:
@@ -21,7 +330,7 @@ The 1.36.0 release of Boost includes a few new features in the thread library:
* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts.
[heading Changes since boost 1.34]
[heading Version 2.0.0 - Changes since boost 1.34]
Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface
changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking
@@ -81,3 +390,36 @@ been moved to __thread_id__.
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
[endsect]
[section:future Future]
The following features will be included in next releases.
# Complete the C++11 missing features, in particular
* [@http://svn.boost.org/trac/boost/ticket/6227 #6227] C++11 compliance: Use of variadic templates on Generic Locking Algorithms on compilers providing them.
# Add some minor features, in particular
* [@http://svn.boost.org/trac/boost/ticket/7589 #7589] Synchro: Add polymorphic lockables.
# Add some features based on C++ proposals, in particular
* [@http://svn.boost.org/trac/boost/ticket/8273 #8273] Add externally locked streams
* [@http://svn.boost.org/trac/boost/ticket/8274 #8274] Add concurrent queue
* [@http://svn.boost.org/trac/boost/ticket/8518 #8518] Sync: Add a latch class
* [@http://svn.boost.org/trac/boost/ticket/XXXX #XXXX] Sync: Add a completion_latch class
* [@http://svn.boost.org/trac/boost/ticket/8513 #8513] Async: Add a basic thread_pool executor.
* [@http://svn.boost.org/trac/boost/ticket/8514 #8514] Async: Add a thread_pool executor with work stealing.
# Add some of the extension proposed in [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3428.pdf A Standardized Representation of Asynchronous Operations] or extension to them, in particular
* [@http://svn.boost.org/trac/boost/ticket/7446 #7446] Async: Add when_any.
* [@http://svn.boost.org/trac/boost/ticket/7447 #7447] Async: Add when_all.
* [@http://svn.boost.org/trac/boost/ticket/7448 #7448] Async: Add async taking a scheduler parameter.
* [@http://svn.boost.org/trac/boost/ticket/8515 #8515] Async: Add shared_future::then
* [@http://svn.boost.org/trac/boost/ticket/8516 #8516] Async: Add future/shared_future::then taking a scheduler as parameter.
* [@http://svn.boost.org/trac/boost/ticket/8517 #8517] Async: Add a variadic future/shared_future::then
[endsect]

242
doc/compliance.qbk Normal file
View File

@@ -0,0 +1,242 @@
[/
(C) Copyright 2011-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: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 Conformance
[[Section] [Description] [Status] [Comments] [Ticket]]
[[30] [Thread support library] [Yes] [-] [-]]
[[30.1] [General] [-] [-] [-]]
[[30.2] [Requirements] [-] [-] [-]]
[[30.2.1] [Template parameter names] [-] [-] [-]]
[[30.2.2] [Exceptions] [Yes] [-] [-]]
[[30.2.3] [Native handles] [Yes] [-] [-]]
[[30.2.4] [Timing specifications] [Yes] [-] [-]]
[[30.2.5] [Requirements for Lockable types] [Yes] [-] [-]]
[[30.2.5.1] [In general] [-] [-] [-]]
[[30.2.5.2] [BasicLockable requirements] [Yes] [-] [-]]
[[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
[[30.2.5.4] [TimedLockable requirements] [Yes] [-] [-]]
[[30.2.6] [decay_copy] [-] [-] [-]]
[[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] [-] [-]]
[[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] [-] [-]]
[[30.3.2] [Namespace this_thread] [Yes] [-] [-]]
[[30.4] [Mutual exclusion] [Partial] [-] [-]]
[[30.4.1] [Mutex requirements] [Yes] [-] [-]]
[[30.4.1.1] [In general] [Yes] [-] [-]]
[[30.4.1.2] [Mutex types] [Yes] [-] [-]]
[[30.4.1.2.1] [Class mutex] [Yes] [-] [-]]
[[30.4.1.2.2] [Class recursive_mutex] [Yes] [-] [-]]
[[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] [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.3] [Generic locking algorithms] [Partial] [variadic] [#6227]]
[[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] [Yes] [-] [-]]
[[30.6.1] [Overview] [Partial] [-] [-]]
[[30.6.2] [Error handling] [Yes] [-] [-]]
[[30.6.3] [Class future_error] [-] [-] [-]]
[[30.6.4] [Shared state] [-] [-] [-]]
[[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] [-] [-]]
]
[/
[table Extension
[[Section] [Description] [Comments]]
[[30.3.1.5.x] [interrupt] [-]]
[[30.3.2.x] [Interruption] [-]]
[[30.3.2.y] [at_thread_exit] [-]]
[[30.4.3.x] [Generic locking algorithms begin/end] [-]]
[[30.x] [Barriers] [-]]
[[30.y] [Thread Local Storage] [-]]
[[30.z] [Class thread_group] [-]]
]
]
[endsect]
[section:cxx14 C++14 standard Thread library - accepted changes]
[note [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.html C++14 on-going standard]]
[table [@http://isocpp.org/files/papers/N3659.html N3659 Shared locking in C++ revision 2] Conformance
[[Section] [Description] [Status] [Comments]]
[[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]]
[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]]
[table A Standardized Representation of Asynchronous Operations Conformance
[[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] [No] [ #XXXX ]]
[[30.6.6.3] [ready] [yes] [ is_ready ]]
[[30.6.7] [Class template shared_future] [Partial] [ - ]]
[[30.6.7.1] [then] [No] [ #8515 ]]
[[30.6.7.2] [unwrap] [No] [ #XXXX ]]
[[30.6.7.3] [ready] [Yes] [ 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]
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]]
[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] [.]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -1,5 +1,6 @@
[/
(C) Copyright 2007-8 Anthony Williams.
(C) Copyright 2007-11 Anthony Williams.
(C) Copyright 2011-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).
@@ -9,6 +10,18 @@
[heading Synopsis]
namespace boost
{
enum class cv_status;
{
no_timeout,
timeout
};
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
mechanism for one thread to wait for notification from another thread that a
particular condition has become true. The general usage pattern is that one
@@ -74,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
{
@@ -84,31 +97,54 @@ optimizations in some cases, based on the knowledge of the mutex type;
condition_variable();
~condition_variable();
void notify_one();
void notify_all();
void notify_one() noexcept;
void notify_all() noexcept;
void wait(boost::unique_lock<boost::mutex>& lock);
template<typename predicate_type>
void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
template <class Clock, class Duration>
typename cv_status::type
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t);
template <class Clock, class Duration, class Predicate>
bool
wait_until(
unique_lock<mutex>& lock,
const chrono::time_point<Clock, Duration>& t,
Predicate pred);
template <class Rep, class Period>
typename cv_status::type
wait_for(
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d);
template <class Rep, class Period, class Predicate>
bool
wait_for(
unique_lock<mutex>& lock,
const chrono::duration<Rep, Period>& d,
Predicate pred);
#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);
template<typename predicate_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
template<typename duration_type,typename predicate_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
// backwards compatibility
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);
template<typename predicate_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
#endif
};
}
@@ -292,11 +328,112 @@ return true;
[endsect]
[section:wait_until `template <class Clock, class Duration> cv_status wait_until(boost::unique_lock<boost::mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time)`]
[variablelist
[[Precondition:] [`lock` is locked by the current thread, and either no other
thread is currently waiting on `*this`, or the execution of the `mutex()` member
function on the `lock` objects supplied in the calls to `wait` or `wait_for` or `wait_until`
in all the threads currently waiting on `*this` would return the same value as
`lock->mutex()` for this call to `wait`.]]
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, when the time as reported by `Clock::now()`
would be equal to or later than the specified `abs_time`, or spuriously. When
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::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.]]
[[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.]]
]
[endsect]
[section:wait_for `template <class Rep, class Period> cv_status wait_for(boost::unique_lock<boost::mutex>& lock, const chrono::duration<Rep, Period>& rel_time)`]
[variablelist
[[Precondition:] [`lock` is locked by the current thread, and either no other
thread is currently waiting on `*this`, or the execution of the `mutex()` member
function on the `lock` objects supplied in the calls to `wait` or `wait_until` or `wait_for`
in all the threads currently waiting on `*this` would return the same value as
`lock->mutex()` for this call to `wait`.]]
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, after the period of time indicated by the `rel_time`
argument has elapsed, or spuriously. When 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::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.]]
[[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.]]
]
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
[endsect]
[section:wait_until_predicate `template <class Clock, class Duration, class Predicate> bool wait_until(boost::unique_lock<boost::mutex>& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
if(!wait_until(lock,abs_time))
{
return pred();
}
}
return true;
``]]
]
[endsect]
[section:wait_for_predicate `template <class Rep, class Period, class Predicate> bool wait_for(boost::unique_lock<boost::mutex>& lock, const chrono::duration<Rep, Period>& rel_time, Predicate pred)`]
[variablelist
[[Effects:] [As-if ``
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
``]]
]
[endsect]
[endsect]
[section:condition_variable_any Class `condition_variable_any`]
#include <boost/thread/condition_variable.hpp>
//#include <boost/thread/condition_variable.hpp>
namespace boost
{
@@ -315,25 +452,43 @@ return true;
template<typename lock_type,typename predicate_type>
void wait(lock_type& lock,predicate_type predicate);
template <class lock_type, class Clock, class Duration>
cv_status wait_until(
lock_type& lock,
const chrono::time_point<Clock, Duration>& t);
template <class lock_type, class Clock, class Duration, class Predicate>
bool wait_until(
lock_type& lock,
const chrono::time_point<Clock, Duration>& t,
Predicate pred);
template <class lock_type, class Rep, class Period>
cv_status wait_for(
lock_type& lock,
const chrono::duration<Rep, Period>& d);
template <class lock_type, class Rep, class Period, class Predicate>
bool wait_for(
lock_type& lock,
const chrono::duration<Rep, Period>& d,
Predicate pred);
#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>
bool timed_wait(lock_type& lock,duration_type const& rel_time);
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
// backwards compatibility
template<typename lock_type>
bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
#endif
};
}
@@ -498,16 +653,138 @@ return true;
[endsect]
[section:wait_until `template <class lock_type, class Clock, class Duration> cv_status wait_until(lock_type& lock, const chrono::time_point<Clock, Duration>& abs_time)`]
[variablelist
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, when the time as reported by `Clock::now()`
would be equal to or later than the specified `abs_time`, or spuriously. When
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::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.]]
[[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.]]
]
[endsect]
[section:condition Typedef `condition`]
[section:wait_for `template <class lock_type, class Rep, class Period> cv_status wait_for(lock_type& lock, const chrono::duration<Rep, Period>& rel_time)`]
#include <boost/thread/condition.hpp>
[variablelist
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, after the period of time indicated by the `rel_time`
argument has elapsed, or spuriously. When 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::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.]]
[[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.]]
]
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
[endsect]
[section:wait_until_predicate `template <class lock_type, class Clock, class Duration, class Predicate> bool wait_until(lock_type& lock, const chrono::time_point<Clock, Duration>& abs_time, Predicate pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
if(!__cvany_wait_until(lock,abs_time))
{
return pred();
}
}
return true;
``]]
]
[endsect]
[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 ``
return wait_until(lock, chrono::steady_clock::now() + d, boost::move(pred));
``]]
]
[endsect]
[endsect]
[section:condition Typedef `condition` DEPRECATED V3]
// #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]

401
doc/configuration.qbk Normal file
View File

@@ -0,0 +1,401 @@
[/
(C) Copyright 20012 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:configuration Configuration]
[table Default Values for Configurable Features
[[Feature] [Anti-Feature] [V2] [V3] [V4] ]
[[USES_CHRONO] [DONT_USE_CHRONO] [YES] [YES] [YES] ]
[[PROVIDES_INTERRUPTIONS] [DONT_PROVIDE_INTERRUPTIONS] [YES] [YES] [YES] ]
[[THROW_IF_PRECONDITION_NOT_SATISFIED] [-] [NO] [NO] [NO] ]
[[PROVIDES_PROMISE_LAZY] [DONT_PROVIDE_PROMISE_LAZY] [YES] [NO] [NO] ]
[[PROVIDES_BASIC_THREAD_ID] [DONT_PROVIDE_BASIC_THREAD_ID] [NO] [YES] [YES] ]
[[PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN] [DONT_PROVIDE_GENERIC_SHARED_MUTEX_ON_WIN] [NO] [YES] [YES] ]
[[PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSION] [DONT_PROVIDE_SHARED_MUTEX_UPWARDS_CONVERSION] [NO] [YES] [YES] ]
[[PROVIDES_EXPLICIT_LOCK_CONVERSION] [DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION] [NO] [YES] [YES] ]
[[PROVIDES_FUTURE] [DONT_PROVIDE_FUTURE] [NO] [YES] [YES] ]
[[PROVIDES_FUTURE_CTOR_ALLOCATORS] [DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS] [NO] [YES] [YES] ]
[[PROVIDES_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_DESTRUCTOR_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
[[PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [DONT_PROVIDE_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE] [NO] [YES] [YES] ]
[[PROVIDES_ONCE_CXX11] [DONT_PROVIDE_ONCE_CXX11] [NO] [YES] [YES] ]
[[USES_MOVE] [DONT_USE_MOVE] [NO] [YES] [YES] ]
[[USES_DATETIME] [DONT_USE_DATETIME] [YES] [YES] [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 and define `BOOST_THREAD_USES_CHRONO` if `BOOST_THREAD_DONT_USE_CHRONO` is not defined. The user should define `BOOST_THREAD_DONT_USE_CHRONO` for compilers that don't work well with Boost.Chrono.
[endsect]
[section:move Boost.Move]
Boost.Thread uses by default an internal move semantic implementation. Since version 3.0.0 you can use the move emulation emulation provided by Boost.Move.
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_USES_MOVE ` if you want to use Boost.Move interface.
When `BOOST_THREAD_VERSION>=3` define `BOOST_THREAD_DONT_USE_MOVE ` if you don't want to use Boost.Move interface.
[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.
When defined BOOST_THREAD_PLATFORM_WIN32 BOOST_THREAD_USES_DATETIME is defined by default.
[endsect]
[section:thread_eq `boost::thread::oprator==` deprecated]
The following nested typedefs are deprecated:
* `boost::thread::oprator==`
* `boost::thread::oprator!=`
When `BOOST_THREAD_PROVIDES_THREAD_EQ` is defined Boost.Thread provides these deprecated feature.
Use instead
* `boost::thread::id::oprator==`
* `boost::thread::id::oprator!=`
[warning This is a breaking change respect to version 1.x.]
When `BOOST_THREAD_VERSION>=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.
[endsect]
[section:shared_upwards Shared Locking Upwards Conversion]
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.
[endsect]
[section:explicit_cnv Explicit Lock Conversion]
In [@http://home.roadrunner.com/~hinnant/bloomington/shared_mutex.html Shared Locking] the lock conversions are explicit. As this explicit conversion breaks the lock interfaces, it is provided only if the `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION` is defined.
When `BOOST_THREAD_VERSION==2` define `BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION ` if you want these features.
When `BOOST_THREAD_VERSION==3` define `BOOST_THREAD_DONT_PROVIDE_EXPLICIT_LOCK_CONVERSION ` if you don't want these features.
[endsect]
[section:future unique_future versus future]
C++11 uses `std::future`. Versions of Boost.Thread previous to version 3.0.0 uses `boost:unique_future`.
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.
[endsect]
[section:lazy promise lazy initialization]
C++11 promise initialize the associated state at construction time. Versions of Boost.Thread previous to version 3.0.0 initialize it lazily at any point in time in which this associated state is needed.
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.
[endsect]
[section:alloc promise Allocator constructor]
C++11 std::promise provides constructors with allocators.
template <typename R>
class promise
{
public:
template <class Allocator>
explicit promise(allocator_arg_t, Allocator a);
// ...
};
template <class R, class Alloc> struct uses_allocator<promise<R>,Alloc>: true_type {};
where
struct allocator_arg_t { };
constexpr allocator_arg_t allocator_arg = allocator_arg_t();
template <class T, class Alloc> struct uses_allocator;
Since version 3.0.0 Boost.Thread implements this constructor using the following interface
namespace boost
{
typedef container::allocator_arg_t allocator_arg_t;
constexpr allocator_arg_t allocator_arg = {};
namespace container
{
template <class R, class Alloc>
struct uses_allocator<promise<R>,Alloc>: true_type {};
}
template <class T, class Alloc>
struct uses_allocator : public container::uses_allocator<T, Alloc> {};
}
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.
[endsect]
[section:terminate Call to terminate if joinable]
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==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.
[endsect]
[section:once_flag once_flag]
C++11 defines a default constructor for once_flag. When `BOOST_THREAD_PROVIDES_ONCE_CXX11 ` is defined Boost.Thread provides this C++ semantics. In this case, the previous aggregate syntax is not supported.
boost::once_flag once = BOOST_ONCE_INIT;
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.
[endsect]
[section:deprecated Signature parameter for packaged_task]
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 2. In this case the following breaking or extending macros are defined if the opposite is not requested:
* `BOOST_THREAD_PROVIDES_PROMISE_LAZY`
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 `
* 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`
* 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`
[/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]
[endsect]
[section:limitations Limitations]
Some compilers don't work correctly with some of the added features.
[section:sun SunPro]
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__ < 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]

365
doc/emulations.qbk Normal file
View File

@@ -0,0 +1,365 @@
[/
(C) Copyright 20012 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:emulations Emulations]
[section:delete `=delete` emulation]
C++11 allows to delete some implicitly generated functions as constructors and assignment using '= delete' as in
public:
thread(thread const&) = delete;
On compilers not supporting this feature, Boost.Thread relays on a partial simulation, it declares the function as private without definition.
private:
thread(thread &);
The emulation is partial as the private function can be used for overload resolution for some compilers and prefer it to other overloads that need a conversion. See below the consequences on the move semantic emulation.
[endsect]
[section:move Move semantics]
In order to implement Movable classes, move parameters and return types Boost.Thread uses the rvalue reference when the compiler support it.
On compilers not supporting it Boost.Thread uses either the emulation provided by Boost.Move or the emulation provided by the previous versions of Boost.Thread depending whether `BOOST_THREAD_USES_MOVE` is defined or not. This macros is unset by default when `BOOST_THREAD_VERSION` is 2. Since `BOOST_THREAD_VERSION` 3, `BOOST_THREAD_USES_MOVE` is defined.
[section:deprecated Deprecated Version 2 interface]
Previous to version 1.50, Boost.Thread make use of its own move semantic emulation which had more limitations than the provided by Boost.Move. In addition, it is of interest of the whole Boost community that Boost.Thread uses Boost.Move so that boost::thread can be stored on Movable aware containers.
To preserve backward compatibility at least during some releases, Boost.Thread allows the user to use the deprecated move semantic emulation defining BOOST_THREAD_DONT_USE_MOVE.
Many aspects of move semantics can be emulated for compilers not supporting rvalue references and Boost.Thread legacy offers tools for that purpose.
[section:Helper Helpers class and function]
Next follows the interface of the legacy move semantic helper class and function.
namespace boost
{
namespace detail
{
template<typename T>
struct thread_move_t
{
explicit thread_move_t(T& t_);
T& operator*() const;
T* operator->() const;
private:
void operator=(thread_move_t&);
};
}
template<typename T>
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t);
}
[endsect]
[section:movable Movable emulation]
We can write a MovableOny class as follows. You just need to follow these simple steps:
* Add a conversion to the `detail::thread_move_t<classname>`
* Make the copy constructor private.
* Write a constructor taking the parameter as `detail::thread_move_t<classname>`
* Write an assignment taking the parameter as `detail::thread_move_t<classname>`
For example the thread class defines the following:
class thread
{
// ...
private:
thread(thread&);
thread& operator=(thread&);
public:
detail::thread_move_t<thread> move()
{
detail::thread_move_t<thread> x(*this);
return x;
}
operator detail::thread_move_t<thread>()
{
return move();
}
thread(detail::thread_move_t<thread> x)
{
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
// ...
};
[endsect]
[endsect]
[section:portable Portable interface]
In order to make the library code portable Boost.Thread uses some macros that will use either the ones provided by Boost.Move or the deprecated move semantics provided by previous versions of Boost.Thread.
See the Boost.Move documentation for a complete description on how to declare new Movable classes and its limitations.
* `BOOST_THREAD_RV_REF(TYPE)` is the equivalent of `BOOST_RV_REF(TYPE)`
* `BOOST_THREAD_RV_REF_BEG` is the equivalent of `BOOST_RV_REF_BEG(TYPE)`
* `BOOST_THREAD_RV_REF_END` is the equivalent of `BOOST_RV_REF_END(TYPE)`
* `BOOST_THREAD_FWD_REF(TYPE)` is the equivalent of `BOOST_FWD_REF(TYPE)
In addition the following macros are needed to make the code portable:
* `BOOST_THREAD_RV(V)` macro to access the rvalue from a BOOST_THREAD_RV_REF(TYPE),
* `BOOST_THREAD_MAKE_RV_REF(RVALUE)` makes a rvalue.
* `BOOST_THREAD_DCL_MOVABLE(CLASS)` to avoid conflicts with Boost.Move
* `BOOST_THREAD_DCL_MOVABLE_BEG(T1)` and `BOOST_THREAD_DCL_MOVABLE_END` are variant of `BOOST_THREAD_DCL_MOVABLE` when the parameter is a template instantiation.
Other macros are provided and must be included on the public section:
* `BOOST_THREAD_NO_COPYABLE` declares a class no-copyable either deleting the copy constructors and copy assignment or moving them to the private section.
* `BOOST_THREAD_MOVABLE(CLASS)` declares all the implicit conversions to an rvalue-reference.
* `BOOST_THREAD_MOVABLE_ONLY(CLASS)` is the equivalent of `BOOST_MOVABLE_BUT_NOT_COPYABLE(CLASS)`
* `BOOST_THREAD_COPYABLE_AND_MOVABLE(CLASS)` is the equivalent of `BOOST_COPYABLE_AND_MOVABLE(CLASS)`
[section:NO_COPYABLE `BOOST_THREAD_NO_COPYABLE(CLASS)`]
This macro marks a class as no copyable, disabling copy construction and assignment.
[endsect]
[section:MOVABLE `BOOST_THREAD_MOVABLE(CLASS)`]
This macro marks a class as movable, declaring all the implicit conversions to an rvalue-reference.
[endsect]
[section:MOVABLE_ONLY `BOOST_THREAD_MOVABLE_ONLY(CLASS)`]
This macro marks a type as movable but not copyable, disabling copy construction and assignment. The user will need to write a move constructor/assignment to fully write a movable but not copyable class.
[endsect]
[section:COPYABLE_AND_MOVABLE `BOOST_THREAD_COPYABLE_AND_MOVABLE(CLASS)`]
This macro marks a type as copyable and movable. The user will need to write a move constructor/assignment and a copy assignment to fully write a copyable and movable class.
[endsect]
[section:RV_REF `BOOST_THREAD_RV_REF(TYPE)`, `BOOST_THREAD_RV_REF_BEG` and `BOOST_THREAD_RV_REF_END`]
This macro is used to achieve portable syntax in move constructors and assignments for classes marked as `BOOST_THREAD_COPYABLE_AND_MOVABLE` or `BOOST_THREAD_MOVABLE_ONLY`.
`BOOST_THREAD_RV_REF_BEG` and `BOOST_THREAD_RV_REF_END` are used when the parameter end with a `>` to avoid the compiler error.
[endsect]
[section:RV `BOOST_THREAD_RV(V)`]
While Boost.Move emulation allows to access an rvalue reference `BOOST_THREAD_RV_REF(TYPE)` using the dot operator, the legacy defines the `operator->`. We need then a macro `BOOST_THREAD_RV` that mask this difference. E.g.
thread(BOOST_THREAD_RV_REF(thread) x)
{
thread_info=BOOST_THREAD_RV(x).thread_info;
BOOST_THREAD_RV(x).thread_info.reset();
}
The use of this macros has reduced considerably the size of the Boost.Thread move related code.
[endsect]
[section:MAKE_RV_REF `BOOST_THREAD_MAKE_RV_REF(RVALUE)`]
While Boost.Move is the best C++03 move emulation there are some limitations that impact the way the library can be used.
For example, with the following declarations
class thread {
// ...
private:
thread(thread &);
public:
thread(rv<thread>&);
// ...
};
This could not work on some compilers even if thread is convertible to `rv<thread>` because the compiler prefers the private copy constructor.
thread mkth()
{
return thread(f);
}
On these compilers we need to use instead an explicit conversion. The library provides a move member function that allows to workaround the issue.
thread mkth()
{
return thread(f).move();
}
Note that `::boost::move` can not be used in this case as thread is not implicitly convertible to `thread&`.
thread mkth()
{
return ::boost::move(thread(f));
}
To make the code portable Boost.Thread the user needs to use a macro `BOOST_THREAD_MAKE_RV_REF` that can be used as in
thread mkth()
{
return BOOST_THREAD_MAKE_RV_REF(thread(f));
}
Note that this limitation is shared also by the legacy Boost.Thread move emulation.
[endsect]
[section:DCL_MOVABLE `BOOST_THREAD_DCL_MOVABLE`, `BOOST_THREAD_DCL_MOVABLE_BEG(T1)` and `BOOST_THREAD_DCL_MOVABLE_END`]
As Boost.Move defines also the `boost::move` function we need to specialize the `has_move_emulation_enabled_aux` metafunction.
template <>
struct has_move_emulation_enabled_aux<thread>
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
{};
so that the following Boost.Move overload is disabled
template <class T>
inline typename BOOST_MOVE_BOOST_NS::disable_if<has_move_emulation_enabled_aux<T>, T&>::type move(T& x);
The macros `BOOST_THREAD_DCL_MOVABLE(CLASS)`, `BOOST_THREAD_DCL_MOVABLE_BEG(T1)` and `BOOST_THREAD_DCL_MOVABLE_END` are used for this purpose. E.g.
BOOST_THREAD_DCL_MOVABLE(thread)
and
BOOST_THREAD_DCL_MOVABLE_BEG(T) promise<T> BOOST_THREAD_DCL_MOVABLE_END
[endsect]
[endsect]
[endsect]
[section:bool_explicit_conversion Bool explicit conversion]
Locks provide an explicit bool conversion operator when the compiler provides them.
explicit operator bool() const;
The library provides un implicit conversion to an undefined type that can be used as a conditional expression.
#if defined(BOOST_NO_EXPLICIT_CONVERSION_OPERATORS)
operator ``['unspecified-bool-type]``() const;
bool operator!() const;
#else
explicit operator bool() const;
#endif
The user should use the lock.owns_lock() when a explicit conversion is required.
[section:bool_conversion `operator `['unspecified-bool-type]`() const`]
[variablelist
[[Returns:] [If __owns_lock_ref__ would return `true`, a value that evaluates to
`true` in boolean contexts, otherwise a value that evaluates to `false` in
boolean contexts.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:operator_not `bool operator!() const`]
[variablelist
[[Returns:] [`!` __owns_lock_ref__.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:scoped_enums Scoped Enums]
Some of the enumerations defined in the standard library are scoped enums.
On compilers that don't support them, the library uses a class to wrap the underlying type. Instead of
enum class future_errc
{
broken_promise,
future_already_retrieved,
promise_already_satisfied,
no_state
};
the library declare these types as
BOOST_SCOPED_ENUM_DECLARE_BEGIN(future_errc)
{
broken_promise,
future_already_retrieved,
promise_already_satisfied,
no_state
}
BOOST_SCOPED_ENUM_DECLARE_END(future_errc)
These macros allows to use 'future_errc' in almost all the cases as an scoped enum.
There are however some limitations:
* The type is not a C++ enum, so 'is_enum<future_errc>' will be false_type.
* The emulated scoped enum can not be used in switch nor in template arguments. For these cases the user needs to use some macros.
Instead of
switch (ev)
{
case future_errc::broken_promise:
// ...
use
switch (boost::native_value(ev))
{
case future_errc::broken_promise:
And instead of
#ifdef BOOST_NO_SCOPED_ENUMS
template <>
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc> : public true_type { };
#endif
use
#ifdef BOOST_NO_SCOPED_ENUMS
template <>
struct BOOST_SYMBOL_VISIBLE is_error_code_enum<future_errc::enum_type> : public true_type { };
#endif
[endsect]
[endsect]

583
doc/external_locking.qbk Normal file
View File

@@ -0,0 +1,583 @@
[/
/ 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_locerk<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) {
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME // define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME if you don't want to check locker check the same lockable
if (!lock.is_locking(&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> guard(*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 parolle". The advantage is that now we can manage with more than two strict locks without changing our code. Ths 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
{
#ifndef BOOST_THREAD_STRCIT_LOCKER_DONT_CHECK_OWNERSHIP // Define BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_OWNERSHIP if you don't want to check locker ownership
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
}
typedef bool (nested_strict_lock::*bool_type)() const;
operator bool_type() const { return &nested_strict_lock::owns_lock; }
bool operator!() const { return false; }
bool owns_lock() const { return true; }
const lockable_type* mutex() const { return tmp_lock_.mutex(); }
bool is_locking(lockable_type* l) const { return l==mutex(); }
BOOST_ADRESS_OF_DELETE(nested_strict_lock)
BOOST_HEAP_ALLOCATEION_DELETE(nested_strict_lock)
BOOST_DEFAULT_CONSTRUCTOR_DELETE(nested_strict_lock) 8
BOOST_COPY_CONSTRUCTOR_DELETE(nested_strict_lock) 9
BOOST_COPY_ASSIGNEMENT_DELETE(nested_strict_lock) 10
private:
Locker& lock_;
Locker tmp_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 parolle"
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
#ifndef BOOST_THREAD_EXTERNALLY_LOCKED_DONT_CHECK_SAME
if (!lock.is_locking(&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]

1912
doc/future_ref.qbk Normal file

File diff suppressed because it is too large Load Diff

466
doc/futures.qbk Executable file
View File

@@ -0,0 +1,466 @@
[/
(C) Copyright 2008-11 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).
]
[section:futures Futures]
[template future_state_link[link_text] [link thread.synchronization.futures.reference.future_state [link_text]]]
[def __uninitialized__ [future_state_link `boost::future_state::uninitialized`]]
[def __ready__ [future_state_link `boost::future_state::ready`]]
[def __waiting__ [future_state_link `boost::future_state::waiting`]]
[def __future_uninitialized__ `boost::future_uninitialized`]
[def __broken_promise__ `boost::broken_promise`]
[def __future_already_retrieved__ `boost::future_already_retrieved`]
[def __task_moved__ `boost::task_moved`]
[def __task_already_started__ `boost::task_already_started`]
[def __promise_already_satisfied__ `boost::promise_already_satisfied`]
[def __thread_interrupted__ `boost::thread_interrupted`]
[template unique_future_link[link_text] [link thread.synchronization.futures.reference.unique_future [link_text]]]
[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::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::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::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::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::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::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`]]
[template shared_future_get_link[link_text] [link thread.synchronization.futures.reference.shared_future.get [link_text]]]
[def __shared_future_get__ [shared_future_get_link `boost::shared_future<R>::get()`]]
[template shared_future_wait_link[link_text] [link thread.synchronization.futures.reference.shared_future.wait [link_text]]]
[def __shared_future_wait__ [shared_future_wait_link `boost::shared_future<R>::wait()`]]
[template shared_future_is_ready_link[link_text] [link thread.synchronization.futures.reference.shared_future.is_ready [link_text]]]
[def __shared_future_is_ready__ [shared_future_is_ready_link `boost::shared_future<R>::is_ready()`]]
[template shared_future_has_value_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_value [link_text]]]
[def __shared_future_has_value__ [shared_future_has_value_link `boost::shared_future<R>::has_value()`]]
[template shared_future_has_exception_link[link_text] [link thread.synchronization.futures.reference.shared_future.has_exception [link_text]]]
[def __shared_future_has_exception__ [shared_future_has_exception_link `boost::shared_future<R>::has_exception()`]]
[template shared_future_get_state_link[link_text] [link thread.synchronization.futures.reference.shared_future.get_state [link_text]]]
[def __shared_future_get_state__ [shared_future_get_state_link `boost::shared_future<R>::get_state()`]]
[template promise_link[link_text] [link thread.synchronization.futures.reference.promise [link_text]]]
[def __promise__ [promise_link `boost::promise`]]
[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()`]]
[template wait_for_all_link[link_text] [link thread.synchronization.futures.reference.wait_for_all [link_text]]]
[def __wait_for_all__ [wait_for_all_link `boost::wait_for_all()`]]
[section:overview Overview]
The futures library provides a means of handling synchronous future values, whether those values are generated by another thread, or
on a single thread in response to external stimuli, or on-demand.
This is done through the provision of four class templates: __unique_future__ and __shared_future__ which are used to retrieve the
asynchronous results, and __promise__ and __packaged_task__ which are used to generate the asynchronous results.
An instance of __unique_future__ holds the one and only reference to a result. Ownership can be transferred between instances using
the move constructor or move-assignment operator, but at most one instance holds a reference to a given asynchronous result. When
the result is ready, it is returned from __unique_future_get__ by rvalue-reference to allow the result to be moved or copied as
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 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]
[section:creating Creating asynchronous values]
You can set the value in a future with either a __promise__ or a __packaged_task__. A __packaged_task__ is a callable object that
wraps a function or callable object. When the packaged task is invoked, it invokes the contained function in turn, and populates a
future with the return value. This is an answer to the perennial question: "how do I return a value from a thread?": package the
function you wish to run as a __packaged_task__ and pass the packaged task to the thread constructor. The future retrieved from the
packaged task can then be used to obtain the return value. If the function throws an exception, that is stored in the future in
place of the return value.
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
boost::__unique_future__<int> fi=pt.get_future();
boost::thread task(boost::move(pt)); // launch task on a thread
fi.wait(); // wait for it to finish
assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
assert(fi.get()==42);
A __promise__ is a bit more low level: it just provides explicit functions to store a value or an exception in the associated
future. A promise can therefore be used where the value may come from more than one possible source, or where a single operation may
produce multiple values.
boost::promise<int> pi;
boost::__unique_future__<int> fi;
fi=pi.get_future();
pi.set_value(42);
assert(fi.is_ready());
assert(fi.has_value());
assert(!fi.has_exception());
assert(fi.get_state()==boost::future_state::ready);
assert(fi.get()==42);
[endsect]
[section:lazy_futures Wait Callbacks and Lazy Futures]
Both __promise__ and __packaged_task__ support ['wait callbacks] that are invoked when a thread blocks in a call to `wait()` or
`timed_wait()` on a future that is waiting for the result from the __promise__ or __packaged_task__, in the thread that is doing the
waiting. These can be set using the `set_wait_callback()` member function on the __promise__ or __packaged_task__ in question.
This allows ['lazy futures] where the result is not actually computed until it is needed by some thread. In the example below, the
call to `f.get()` invokes the callback `invoke_lazy_task`, which runs the task to set the value. If you remove the call to
`f.get()`, the task is not ever run.
int calculate_the_answer_to_life_the_universe_and_everything()
{
return 42;
}
void invoke_lazy_task(boost::packaged_task<int>& task)
{
try
{
task();
}
catch(boost::task_already_started&)
{}
}
int main()
{
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());
assert(f.get()==42);
}
[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 future
void bad_second_use( type arg ) {
auto ftr = async( [=]{ return work( arg ); } );
if ( cond1 )
{
use1( ftr.get() );
} else
{
use2( ftr.get() );
}
use3( ftr.get() ); // second use is undefined
}
Using a `shared_mutex` solves the issue
void good_second_use( type arg ) {
shared_future<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_future Making immediate futures easier]
Some functions may know the value at the point of construction. In these cases the value is immediately available,
but needs to be returned as a future or shared_future. By using make_future (make_shared_future) a future (shared_future)
can be created which holds a pre-computed result in its shared state.
Without these features it is non-trivial to create a future directly from a value.
First a promise must be created, then the promise is set, and lastly the future is retrieved from the promise.
This can now be done with one operation.
[heading make_future / make_shared_future]
This function creates a future for a given value. If no value is given then a future<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_future(0);
if (x < 0) return boost::make_future(-1);
boost::future<int> f1 = boost::async([]() { return x+1; });
return f1;
}
There are two variations of this function. The first takes a value of any type, and returns a future of that type.
The input value is passed to the shared state of the returned future. The second version takes no input and returns a future<void>.
make_shared_future has the same functionality as make_future, except has a return type of shared_future.
[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 function2: One option which was considered was to follow JavaScript's approach and take two functions, one for
success and one for error handling. However this option is not viable in C++ as there is no single base type for
exceptions as there is in JavaScript. The lambda function takes a future as its input which carries the exception
through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
* Scheduler: Providing an overload to .then, to take a scheduler reference places great flexibility over the execution
of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful
asynchronous operations. The lifetime of the scheduler must outlive the continuation.
* Launch policy: if the additional flexibility that the scheduler provides is not required.
Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using
.then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning
a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A
shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future
to a shared_future when needed using future::share().
[endsect]
[include future_ref.qbk]
[endsect]

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]

396
doc/latch.qbk Normal file
View File

@@ -0,0 +1,396 @@
[/
(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 count);
[variablelist
[[Effects:] [Construct a latch with is initial value for the internal counter.]]
[[Note:] [The counter could be zero and reset later.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section Destructor]
~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

@@ -1,5 +1,6 @@
[/
(C) Copyright 2007-8 Anthony Williams.
(C) Copyright 2007-11 Anthony Williams
(C) Copyright 2011-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).
@@ -75,10 +76,11 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
void lock();
void unlock();
bool try_lock();
bool timed_lock(system_time const & abs_time);
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
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>& t);
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
@@ -86,6 +88,13 @@ __try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef unspecified-type scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
#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);
#endif
};
__timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the
@@ -122,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;
@@ -178,13 +187,14 @@ __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();
bool timed_lock(system_time const & abs_time);
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
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>& t);
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
@@ -192,6 +202,13 @@ __recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for back
typedef unique_lock<recursive_timed_mutex> scoped_lock;
typedef unspecified-type scoped_try_lock;
typedef scoped_lock scoped_timed_lock;
#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);
#endif
};
__recursive_timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one
@@ -222,3 +239,6 @@ implementation. If no such instance exists, `native_handle()` and `native_handle
[include shared_mutex_ref.qbk]
[endsect]

View File

@@ -7,16 +7,42 @@
[section:once One-time Initialization]
#include <boost/thread/once.hpp>
namespace boost
{
struct once_flag;
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);
#endif
}
[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`]
#include <boost/thread/once.hpp>
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
struct once_flag
{
constexprr once_flag() noexcept;
once_flag(const once_flag&) = delete;
once_flag& operator=(const once_flag&) = delete;
};
#else
typedef platform-specific-type once_flag;
#define BOOST_ONCE_INIT platform-specific-initializer
#endif
Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT` if BOOST_THREAD_PROVIDES_ONCE_CXX11 is not defined
boost::once_flag f=BOOST_ONCE_INIT;
@@ -24,32 +50,40 @@ Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
[section:call_once Non-member function `call_once`]
#include <boost/thread/once.hpp>
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
deadlock, or invoking the passed function a second time. The
alternative is to allow the second call to return immediately, but
that assumes the code knows it has been called recursively, and can
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

@@ -1,5 +1,6 @@
[/
(C) Copyright 2007-8 Anthony Williams.
(C) Copyright 2007-12 Anthony Williams.
(C) Copyright 20012 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).
@@ -11,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. This version is 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],
@@ -19,6 +22,9 @@ 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 (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
each class or function, or include the master thread library header:
@@ -28,3 +34,41 @@ each class or function, or include the master thread library header:
which includes all the other headers in turn.
[endsect]
[section:build Using and building the library]
Boost.Thread is configured following the conventions used to build [@http://www.boost.org/doc/libs/1_48_0/libs/config/doc/html/boost_config/boost_macro_reference.html#boost_config.boost_macro_reference.macros_for_libraries_with_separate_source_code libraries with separate source code]. Boost.Thread will import/export the code only if the user has specifically asked for it, by defining either BOOST_ALL_DYN_LINK if they want all boost libraries to be dynamically linked, or BOOST_THREAD_DYN_LINK if they want just this one to be dynamically liked.
The definition of these macros determines whether BOOST_THREAD_USE_DLL is defined. If BOOST_THREAD_USE_DLL is not defined, the library will define BOOST_THREAD_USE_DLL or BOOST_THREAD_USE_LIB depending on whether the platform. On non windows platforms BOOST_THREAD_USE_LIB is defined if is not defined. In windows platforms, BOOST_THREAD_USE_LIB is defined if BOOST_THREAD_USE_DLL and the compiler supports auto-tss cleanup with Boost.Threads (for the time been Msvc and Intel)
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]
[endsect]

502
doc/scoped_thread.qbk Normal file
View File

@@ -0,0 +1,502 @@
[/
(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 strict_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;
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 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]
~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: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,26 +5,37 @@
http://www.boost.org/LICENSE_1_0.txt).
]
[section:shared_mutex Class `shared_mutex`]
[section:shared_mutex Class `shared_mutex` -- EXTENSION]
#include <boost/thread/shared_mutex.hpp>
class shared_mutex
{
public:
shared_mutex(shared_mutex const&) = delete;
shared_mutex& operator=(shared_mutex const&) = delete;
shared_mutex();
~shared_mutex();
void lock_shared();
bool try_lock_shared();
bool timed_lock_shared(system_time const& timeout);
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);
void unlock_shared();
void lock();
bool try_lock();
bool timed_lock(system_time const& timeout);
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);
void unlock();
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
// use upgrade_mutex instead.
void lock_upgrade();
void unlock_upgrade();
@@ -32,13 +43,186 @@
void unlock_and_lock_upgrade();
void unlock_and_lock_shared();
void unlock_upgrade_and_lock_shared();
#endif
#if defined BOOST_THREAD_USES_DATETIME
bool timed_lock_shared(system_time const& timeout);
bool timed_lock(system_time const& timeout);
#endif
};
The class `boost::shared_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
__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` -- EXTENSION]
#include <boost/thread/shared_mutex.hpp>
class upgrade_mutex
{
public:
upgrade_mutex(upgrade_mutex const&) = delete;
upgrade_mutex& operator=(upgrade_mutex const&) = delete;
upgrade_mutex();
~upgrade_mutex();
void lock_shared();
bool try_lock_shared();
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);
void unlock_shared();
void lock();
bool try_lock();
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);
void unlock();
void lock_upgrade();
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);
void unlock_upgrade();
// Shared <-> Exclusive
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
bool try_unlock_shared_and_lock();
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
#ifdef BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
bool try_unlock_shared_and_lock_upgrade();
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();
#if defined(BOOST_THREAD_PLATFORM_PTHREAD)
|| defined(BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN)
bool try_unlock_upgrade_and_lock();
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::upgrade_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
__upgrade_lockable_concept__.
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, __timed_lock_ref__, __lock_shared_ref__, __try_lock_shared_ref__ and
__timed_lock_shared_ref__ shall be permitted.
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.
[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]

547
doc/sync_queues_ref.qbk Normal file
View File

@@ -0,0 +1,547 @@
[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]

190
doc/sync_streams.qbk Normal file
View File

@@ -0,0 +1,190 @@
[/
/ 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_parolle<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();
Stream& bypass() const;
};
}
`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]

44
doc/sync_tutorial.qbk Normal file
View File

@@ -0,0 +1,44 @@
[/
(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).
]
[section:tutorial Tutorial]
[@http://home.roadrunner.com/~hinnant/mutexes/locking.html Handling mutexes in C++] is an excellent tutorial. You need just replace std and ting by boost.
[@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.
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(fn())
{
auto&& _ = boost::make_lock_guard(f);
f();
}
that can be used as
int i = with_lock_guard(mtx, {}() -> bool
{
// access the protected state
return true;
});
[endsect] [/ 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,408 @@
[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

@@ -1,14 +1,17 @@
[/
(C) Copyright 2007-8 Anthony Williams.
(C) Copyright 2008-11 Anthony Williams
(C) Copyright 2011-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).
]
[article Thread
[quickbook 1.4]
[authors [Williams, Anthony]]
[copyright 2007-8 Anthony Williams]
[library Thread
[quickbook 1.5]
[version 4.1.0]
[authors [Williams, Anthony] [Botet Escriba, Vicente J.]]
[copyright 2007-11 Anthony Williams]
[copyright 2011-13 Vicente J. Botet Escriba]
[purpose C++ Library for launching threads and synchronizing data between them]
[category text]
[license
@@ -21,6 +24,11 @@
[template lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.lockable [link_text]]]
[def __lockable_concept__ [lockable_concept_link `Lockable` concept]]
[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`]]
[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]]
@@ -35,8 +43,9 @@
[def __upgrade_lockable_concept_type__ [upgrade_lockable_concept_link `UpgradeLockable`]]
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.lock [link_text]]]
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.basic_lockable.lock [link_text]]]
[def __lock_ref__ [lock_ref_link `lock()`]]
[def __lock [link thread.synchronization.mutex_concepts.basic_lockable.lock `lock`]]
[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]]
[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]]
@@ -44,50 +53,89 @@
[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]]
[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]]
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.unlock [link_text]]]
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.basic_lockable.unlock [link_text]]]
[def __unlock_ref__ [unlock_ref_link `unlock()`]]
[def __unlock [link thread.synchronization.mutex_concepts.basic_lockable.unlock `unlock`]]
[template try_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.try_lock [link_text]]]
[def __try_lock_ref__ [try_lock_ref_link `try_lock()`]]
[def __try_lock [link thread.synchronization.mutex_concepts.lockable.try_lock `try_lock`]]
[template timed_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock [link_text]]]
[def __timed_lock_ref__ [timed_lock_ref_link `timed_lock()`]]
[def __timed_lock [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock `timed_lock`]]
[def __try_lock_for [link thread.synchronization.mutex_concepts.timed_lockable.try_lock_for `try_lock_for`]]
[def __try_lock_until [link thread.synchronization.mutex_concepts.timed_lockable.try_lock_until `try_lock_until`]]
[template timed_lock_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration [link_text]]]
[def __timed_lock_duration_ref__ [timed_lock_duration_ref_link `timed_lock()`]]
[def __timed_lock_duration [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration `timed_lock`]]
[template lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared [link_text]]]
[def __lock_shared_ref__ [lock_shared_ref_link `lock_shared()`]]
[def __lock_shared [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared `lock_shared()`]]
[template unlock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared [link_text]]]
[def __unlock_shared_ref__ [unlock_shared_ref_link `unlock_shared()`]]
[def __unlock_shared [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared `unlock_shared()`]]
[template try_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared [link_text]]]
[def __try_lock_shared_ref__ [try_lock_shared_ref_link `try_lock_shared()`]]
[def __try_lock_shared [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared `try_lock_shared`]]
[template timed_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared [link_text]]]
[def __timed_lock_shared_ref__ [timed_lock_shared_ref_link `timed_lock_shared()`]]
[def __try_lock_shared_for [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_for `try_lock_shared_for`]]
[def __try_lock_shared_for [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_until `try_lock_shared_until`]]
[template timed_lock_shared_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared_duration [link_text]]]
[def __timed_lock_shared_duration_ref__ [timed_lock_shared_duration_ref_link `timed_lock_shared()`]]
[def __try_lock_shared_for [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_for `try_lock_shared_for`]]
[def __try_lock_shared_until [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared_until `try_lock_shared_until`]]
[template lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade [link_text]]]
[def __lock_upgrade_ref__ [lock_upgrade_ref_link `lock_upgrade()`]]
[def __lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade `lock_upgrade`]]
[def __try_lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.try_lock_upgrade `try_lock_upgrade`]]
[def __try_lock_upgrade_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_lock_upgrade_for `try_lock_upgrade_for`]]
[def __try_lock_upgrade_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_lock_upgrade_until `try_lock_upgrade_until`]]
[template unlock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade [link_text]]]
[def __unlock_upgrade_ref__ [unlock_upgrade_ref_link `unlock_upgrade()`]]
[def __unlock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade `unlock_upgrade`]]
[template unlock_upgrade_and_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock [link_text]]]
[def __unlock_upgrade_and_lock_ref__ [unlock_upgrade_and_lock_ref_link `unlock_upgrade_and_lock()`]]
[def __unlock_upgrade_and_lock [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock `unlock_upgrade_and_lock`]]
[template unlock_and_lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade [link_text]]]
[def __unlock_and_lock_upgrade_ref__ [unlock_and_lock_upgrade_ref_link `unlock_and_lock_upgrade()`]]
[def __unlock_and_lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade `unlock_and_lock_upgrade`]]
[template unlock_upgrade_and_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared [link_text]]]
[def __unlock_upgrade_and_lock_shared_ref__ [unlock_upgrade_and_lock_shared_ref_link `unlock_upgrade_and_lock_shared()`]]
[def __unlock_upgrade_and_lock_shared [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared `unlock_upgrade_and_lock_shared`]]
[def __try_unlock_shared_and_lock [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock `try_unlock_shared_and_lock`]]
[def __try_unlock_shared_and_lock_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_for `try_unlock_shared_and_lock_for`]]
[def __try_unlock_shared_and_lock_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_until `try_unlock_shared_and_lock_until`]]
[def __unlock_and_lock_shared [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_shared `unlock_and_lock_shared`]]
[def __try_unlock_shared_and_lock_upgrade [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_upgrade `try_unlock_shared_and_lock_upgrade`]]
[def __try_unlock_shared_and_lock_upgrade_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_upgrade_for `try_unlock_shared_and_lock_upgrade_for`]]
[def __try_unlock_shared_and_lock_upgrade_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_shared_and_lock_upgrade_until `try_unlock_shared_and_lock_upgrade_until`]]
[def __try_unlock_upgrade_and_lock [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_upgrade_and_lock `try_unlock_upgrade_and_lock`]]
[def __try_unlock_upgrade_and_lock_for [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_upgrade_and_lock_for `try_unlock_upgrade_and_lock_for`]]
[def __try_unlock_upgrade_and_lock_until [link thread.synchronization.mutex_concepts.upgrade_lockable.try_unlock_upgrade_and_lock_until `try_unlock_upgrade_and_lock_until`]]
[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()`]]
@@ -98,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`]]
@@ -107,24 +156,43 @@
[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 `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()`]]
[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()`]]
[def __interrupt__ [link thread.thread_management.thread.interrupt `interrupt()`]]
[def __sleep__ [link thread.thread_management.this_thread.sleep `boost::this_thread::sleep()`]]
[def __sleep_for [link thread.thread_management.this_thread.sleep_for `sleep_for`]]
[def __sleep_until [link thread.thread_management.this_thread.sleep_until `sleep_until`]]
[def __yield [link thread.thread_management.this_thread.yield `yield`]]
[def __get_id [link thread.thread_management.thread.get_id `get_id`]]
[def __interruption_enabled__ [link thread.thread_management.this_thread.interruption_enabled `boost::this_thread::interruption_enabled()`]]
[def __interruption_requested__ [link thread.thread_management.this_thread.interruption_requested `boost::this_thread::interruption_requested()`]]
@@ -135,33 +203,60 @@
[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()`]]
[template cond_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.timed_wait [link_text]]]
[def __cond_timed_wait__ [cond_timed_wait_link `timed_wait()`]]
[def __condition_variable [link thread.synchronization.condvar_ref.condition_variable `condition_variable`]]
[def __wait_for [link thread.synchronization.condvar_ref.condition_variable.wait_for `wait_for`]]
[def __wait_until [link thread.synchronization.condvar_ref.condition_variable.wait_until `wait_until`]]
[template cond_any_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.wait [link_text]]]
[def __cond_any_wait__ [cond_any_wait_link `wait()`]]
[template cond_any_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.timed_wait [link_text]]]
[def __cond_any_timed_wait__ [cond_any_timed_wait_link `timed_wait()`]]
[def __condition_variable_any [link thread.synchronization.condvar_ref.condition_variable_any `condition_variable_any`]]
[def __cvany_wait_for [link thread.synchronization.condvar_ref.condition_variable_any.wait_for `wait_for`]]
[def __cvany_wait_until [link thread.synchronization.condvar_ref.condition_variable_any.wait_until `wait_until`]]
[def __blocked__ ['blocked]]
[include overview.qbk]
[include changes.qbk]
[include thread_ref.qbk]
[include scoped_thread.qbk]
[section:synchronization Synchronization]
[include sync_tutorial.qbk]
[include mutex_concepts.qbk]
[include mutexes.qbk]
[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]
[include acknowledgements.qbk]
[include compliance.qbk]

File diff suppressed because it is too large Load Diff

View File

@@ -5,19 +5,33 @@
http://www.boost.org/LICENSE_1_0.txt).
]
[section:time Date and Time Requirements]
[section:time Time Requirements]
As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a
time out. These include (but are not limited to):
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):
* `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):
* __sleep__
* __timed_join__
* __cond_timed_wait__
* __timed_lock_ref__
For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is
For the overloads that accept an absolute time parameter, an object of type [link thread.time.deprecated.system_time `boost::system_time`] is
required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link
thread.time.get_system_time `boost::get_system_time()`]. e.g.
thread.time.deprecated.get_system_time `boost::get_system_time()`]. e.g.
boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500);
@@ -70,6 +84,7 @@ See the documentation for [link date_time.posix_time.ptime_class `boost::posix_t
]
[endsect]
[endsect]
[endsect]

View File

@@ -41,11 +41,22 @@ order. If a cleanup routine sets the value of associated with an instance of `bo
cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of
`boost::thread_specific_ptr` with values.
Note: on some platforms, cleanup of thread-specific data is not
performed for threads created with the platform's native API. On those
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
{
@@ -61,6 +72,7 @@ cleaned up, that value is added to the cleanup list. Cleanup finishes when there
T* release();
void reset(T* new_value=0);
};
}
[section:default_constructor `thread_specific_ptr();`]
@@ -97,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

@@ -1,19 +1,20 @@
// 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 <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) { }
@@ -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;
};
@@ -50,10 +52,11 @@ boost::mutex io_mutex;
void sender() {
int n = 0;
while (n < 100) {
while (n < 1000000) {
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;
@@ -65,18 +68,24 @@ void receiver() {
int n;
do {
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
buf.send(-1);
}
int main(int, char*[])
{
boost::thread thrd1(&sender);
boost::thread thrd2(&receiver);
boost::thread thrd3(&receiver);
boost::thread thrd4(&receiver);
thrd1.join();
thrd2.join();
thrd3.join();
thrd4.join();
return 0;
}

70
example/future_then.cpp Normal file
View File

@@ -0,0 +1,70 @@
// Copyright (C) 2012-2013 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#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 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;
}
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

61
example/make_future.cpp Normal file
View File

@@ -0,0 +1,61 @@
// 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>
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_future());
}
#endif
boost::future<int> compute(int x)
{
if (x == 0) return boost::make_future(0);
if (x < 0) return boost::make_future(-1);
//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_shared_future(0);
if (x < 0) return boost::make_shared_future(-1);
//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

@@ -1,15 +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)
#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;
};
@@ -89,6 +89,7 @@ private:
template <typename M>
void do_test(M* dummy=0)
{
(void)dummy;
typedef buffer_t<M> buffer_type;
buffer_type::get_buffer();
boost::thread thrd1(&buffer_type::do_receiver_thread);

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(thread(use_cerr, boost::ref(mcerr)));
scoped_thread<> t2(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

@@ -1,15 +1,23 @@
// 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)
#define BOOST_THREAD_PROVIDES_ONCE_CXX11
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <cassert>
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
#ifdef BOOST_THREAD_PROVIDES_ONCE_CXX11
static boost::once_flag once;
//static boost::once_flag once2 = BOOST_ONCE_INIT;
#else
static boost::once_flag once = BOOST_ONCE_INIT;
//static boost::once_flag once2 = once;
#endif
void init()
{
@@ -21,7 +29,7 @@ void thread_proc()
boost::call_once(&init, once);
}
int main(int argc, char* argv[])
int main()
{
boost::thread_group threads;
for (int i=0; i<5; ++i)

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();
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(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());
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(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(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
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(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t12(thread(producer, boost::ref(mcerr), boost::ref(sbq)));
scoped_thread<> t2(thread(consumer, boost::ref(mcout), boost::ref(sbq)));
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);
}

87
example/scoped_thread.cpp Normal file
View File

@@ -0,0 +1,87 @@
// (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;
}
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();
}
return 0;
}

144
example/shared_monitor.cpp Normal file
View File

@@ -0,0 +1,144 @@
// 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)
#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.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
#include <cassert>
#include <vector>
#define EXCLUSIVE 1
#define SHARED 2
#define MODE SHARED
class A
{
#if MODE == EXCLUSIVE
typedef boost::mutex mutex_type;
#elif MODE == SHARED
typedef boost::shared_mutex mutex_type;
#else
#error MODE not set
#endif
typedef std::vector<double> C;
mutable mutex_type mut_;
C data_;
public:
A() : data_(10000000) {}
A(const A& a);
A& operator=(const A& a);
void compute(const A& x, const A& y);
};
A::A(const A& a)
{
#if MODE == EXCLUSIVE
boost::unique_lock<mutex_type> lk(a.mut_);
#elif MODE == SHARED
boost::shared_lock<mutex_type> lk(a.mut_);
#else
#error MODE not set
#endif
data_ = a.data_;
}
A&
A::operator=(const A& a)
{
if (this != &a)
{
boost::unique_lock<mutex_type> lk1(mut_, boost::defer_lock);
#if MODE == EXCLUSIVE
boost::unique_lock<mutex_type> lk2(a.mut_, boost::defer_lock);
#elif MODE == SHARED
boost::shared_lock<mutex_type> lk2(a.mut_, boost::defer_lock);
#else
#error MODE not set
#endif
boost::lock(lk1, lk2);
data_ = a.data_;
}
return *this;
}
void
A::compute(const A& x, const A& y)
{
boost::unique_lock<mutex_type> lk1(mut_, boost::defer_lock);
#if MODE == EXCLUSIVE
boost::unique_lock<mutex_type> lk2(x.mut_, boost::defer_lock);
boost::unique_lock<mutex_type> lk3(y.mut_, boost::defer_lock);
#elif MODE == SHARED
boost::shared_lock<mutex_type> lk2(x.mut_, boost::defer_lock);
boost::shared_lock<mutex_type> lk3(y.mut_, boost::defer_lock);
#else
#error MODE not set
#endif
boost::lock(lk1, lk2, lk3);
assert(data_.size() == x.data_.size());
assert(data_.size() == y.data_.size());
for (unsigned i = 0; i < data_.size(); ++i)
data_[i] = (x.data_[i] + y.data_[i]) / 2;
}
A a1;
A a2;
void test_s()
{
A la3 = a1;
for (int i = 0; i < 150; ++i)
{
la3.compute(a1, a2);
}
}
void test_w()
{
A la3 = a1;
for (int i = 0; i < 10; ++i)
{
la3.compute(a1, a2);
a1 = la3;
a2 = la3;
#if defined BOOST_THREAD_DONT_USE_CHRONO
boost::this_thread::sleep_for(boost::chrono::seconds(1));
#endif
}
}
int main()
{
#if defined BOOST_THREAD_DONT_USE_CHRONO
typedef boost::chrono::high_resolution_clock Clock;
typedef boost::chrono::duration<double> sec;
Clock::time_point t0 = Clock::now();
#endif
std::vector<boost::thread*> v;
boost::thread thw(test_w);
v.push_back(&thw);
boost::thread thr0(test_w);
v.push_back(&thr0);
boost::thread thr1(test_w);
v.push_back(&thr1);
boost::thread thr2(test_w);
v.push_back(&thr2);
boost::thread thr3(test_w);
v.push_back(&thr3);
for (std::size_t i = 0; i < v.size(); ++i)
v[i]->join();
#if defined BOOST_THREAD_DONT_USE_CHRONO
Clock::time_point t1 = Clock::now();
std::cout << sec(t1-t0) << '\n';
#endif
return 0;
}

746
example/shared_mutex.cpp Normal file
View File

@@ -0,0 +1,746 @@
// 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)
#define BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
#define BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#include <iostream>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.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>
enum {reading, writing};
int state = reading;
#if 1
boost::mutex&
cout_mut()
{
static boost::mutex m;
return m;
}
void
print(const char* tag, unsigned count, char ch)
{
boost::lock_guard<boost::mutex> _(cout_mut());
std::cout << tag << count << ch;
}
#elif 0
boost::recursive_mutex&
cout_mut()
{
static boost::recursive_mutex m;
return m;
}
void print() {}
template <class A0, class ...Args>
void
print(const A0& a0, const Args& ...args)
{
boost::lock_guard<boost::recursive_mutex> _(cout_mut());
std::cout << a0;
print(args...);
}
#else
template <class A0, class A1, class A2>
void
print(const A0&, const A1& a1, const A2&)
{
assert(a1 > 10000);
}
#endif
namespace S
{
boost::shared_mutex mut;
void reader()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock_shared();
assert(state == reading);
++count;
mut.unlock_shared();
}
print("reader = ", count, '\n');
}
void writer()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock();
state = writing;
assert(state == writing);
state = reading;
++count;
mut.unlock();
}
print("writer = ", count, '\n');
}
void try_reader()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_shared())
{
assert(state == reading);
++count;
mut.unlock_shared();
}
}
print("try_reader = ", count, '\n');
}
void try_writer()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock())
{
state = writing;
assert(state == writing);
state = reading;
++count;
mut.unlock();
}
}
print("try_writer = ", count, '\n');
}
void try_for_reader()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
++count;
mut.unlock_shared();
}
}
print("try_for_reader = ", count, '\n');
}
void try_for_writer()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_for(boost::chrono::microseconds(5)))
{
state = writing;
assert(state == writing);
state = reading;
++count;
mut.unlock();
}
}
print("try_for_writer = ", count, '\n');
}
void
test_shared_mutex()
{
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(reader);
boost::thread t2(writer);
boost::thread t3(reader);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(try_reader);
boost::thread t2(try_writer);
boost::thread t3(try_reader);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(try_for_reader);
boost::thread t2(try_for_writer);
boost::thread t3(try_for_reader);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
}
}
namespace U
{
boost::upgrade_mutex mut;
void reader()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock_shared();
assert(state == reading);
++count;
mut.unlock_shared();
}
print("reader = ", count, '\n');
}
void writer()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock();
state = writing;
assert(state == writing);
state = reading;
++count;
mut.unlock();
}
print("writer = ", count, '\n');
}
void try_reader()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_shared())
{
assert(state == reading);
++count;
mut.unlock_shared();
}
}
print("try_reader = ", count, '\n');
}
void try_writer()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock())
{
state = writing;
assert(state == writing);
state = reading;
++count;
mut.unlock();
}
}
print("try_writer = ", count, '\n');
}
void try_for_reader()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
++count;
mut.unlock_shared();
}
}
print("try_for_reader = ", count, '\n');
}
void try_for_writer()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_for(boost::chrono::microseconds(5)))
{
state = writing;
assert(state == writing);
state = reading;
++count;
mut.unlock();
}
}
print("try_for_writer = ", count, '\n');
}
void upgradable()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock_upgrade();
assert(state == reading);
++count;
mut.unlock_upgrade();
}
print("upgradable = ", count, '\n');
}
void try_upgradable()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_upgrade())
{
assert(state == reading);
++count;
mut.unlock_upgrade();
}
}
print("try_upgradable = ", count, '\n');
}
void try_for_upgradable()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
++count;
mut.unlock_upgrade();
}
}
print("try_for_upgradable = ", count, '\n');
}
void clockwise()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock_shared();
assert(state == reading);
if (mut.try_unlock_shared_and_lock())
{
state = writing;
}
else if (mut.try_unlock_shared_and_lock_upgrade())
{
assert(state == reading);
mut.unlock_upgrade_and_lock();
state = writing;
}
else
{
mut.unlock_shared();
continue;
}
assert(state == writing);
state = reading;
mut.unlock_and_lock_upgrade();
assert(state == reading);
mut.unlock_upgrade_and_lock_shared();
assert(state == reading);
mut.unlock_shared();
++count;
}
print("clockwise = ", count, '\n');
}
void counter_clockwise()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
mut.lock_upgrade();
assert(state == reading);
mut.unlock_upgrade_and_lock();
assert(state == reading);
state = writing;
assert(state == writing);
state = reading;
mut.unlock_and_lock_shared();
assert(state == reading);
mut.unlock_shared();
++count;
}
print("counter_clockwise = ", count, '\n');
}
void try_clockwise()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_shared())
{
assert(state == reading);
if (mut.try_unlock_shared_and_lock())
{
state = writing;
}
else if (mut.try_unlock_shared_and_lock_upgrade())
{
assert(state == reading);
mut.unlock_upgrade_and_lock();
state = writing;
}
else
{
mut.unlock_shared();
continue;
}
assert(state == writing);
state = reading;
mut.unlock_and_lock_upgrade();
assert(state == reading);
mut.unlock_upgrade_and_lock_shared();
assert(state == reading);
mut.unlock_shared();
++count;
}
}
print("try_clockwise = ", count, '\n');
}
void try_for_clockwise()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_shared_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
if (mut.try_unlock_shared_and_lock_for(boost::chrono::microseconds(5)))
{
state = writing;
}
else if (mut.try_unlock_shared_and_lock_upgrade_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
mut.unlock_upgrade_and_lock();
state = writing;
}
else
{
mut.unlock_shared();
continue;
}
assert(state == writing);
state = reading;
mut.unlock_and_lock_upgrade();
assert(state == reading);
mut.unlock_upgrade_and_lock_shared();
assert(state == reading);
mut.unlock_shared();
++count;
}
}
print("try_for_clockwise = ", count, '\n');
}
void try_counter_clockwise()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_upgrade())
{
assert(state == reading);
if (mut.try_unlock_upgrade_and_lock())
{
assert(state == reading);
state = writing;
assert(state == writing);
state = reading;
mut.unlock_and_lock_shared();
assert(state == reading);
mut.unlock_shared();
++count;
}
else
{
mut.unlock_upgrade();
}
}
}
print("try_counter_clockwise = ", count, '\n');
}
void try_for_counter_clockwise()
{
typedef boost::chrono::steady_clock Clock;
unsigned count = 0;
Clock::time_point until = Clock::now() + boost::chrono::seconds(3);
while (Clock::now() < until)
{
if (mut.try_lock_upgrade_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
if (mut.try_unlock_upgrade_and_lock_for(boost::chrono::microseconds(5)))
{
assert(state == reading);
state = writing;
assert(state == writing);
state = reading;
mut.unlock_and_lock_shared();
assert(state == reading);
mut.unlock_shared();
++count;
}
else
{
mut.unlock_upgrade();
}
}
}
print("try_for_counter_clockwise = ", count, '\n');
}
void
test_upgrade_mutex()
{
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(reader);
boost::thread t2(writer);
boost::thread t3(reader);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(try_reader);
boost::thread t2(try_writer);
boost::thread t3(try_reader);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(try_for_reader);
boost::thread t2(try_for_writer);
boost::thread t3(try_for_reader);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(reader);
boost::thread t2(writer);
boost::thread t3(upgradable);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(reader);
boost::thread t2(writer);
boost::thread t3(try_upgradable);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
boost::thread t1(reader);
boost::thread t2(writer);
boost::thread t3(try_for_upgradable);
t1.join();
t2.join();
t3.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
state = reading;
boost::thread t1(clockwise);
boost::thread t2(counter_clockwise);
boost::thread t3(clockwise);
boost::thread t4(counter_clockwise);
t1.join();
t2.join();
t3.join();
t4.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
{
state = reading;
boost::thread t1(try_clockwise);
boost::thread t2(try_counter_clockwise);
t1.join();
t2.join();
}
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
// {
// state = reading;
// boost::thread t1(try_for_clockwise);
// boost::thread t2(try_for_counter_clockwise);
// t1.join();
// t2.join();
// }
// std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
}
}
namespace Assignment
{
class A
{
typedef boost::upgrade_mutex mutex_type;
typedef boost::shared_lock<mutex_type> SharedLock;
typedef boost::upgrade_lock<mutex_type> UpgradeLock;
typedef boost::unique_lock<mutex_type> Lock;
mutable mutex_type mut_;
std::vector<double> data_;
public:
A(const A& a)
{
SharedLock _(a.mut_);
data_ = a.data_;
}
A& operator=(const A& a)
{
if (this != &a)
{
Lock this_lock(mut_, boost::defer_lock);
SharedLock that_lock(a.mut_, boost::defer_lock);
boost::lock(this_lock, that_lock);
data_ = a.data_;
}
return *this;
}
void swap(A& a)
{
Lock this_lock(mut_, boost::defer_lock);
Lock that_lock(a.mut_, boost::defer_lock);
boost::lock(this_lock, that_lock);
data_.swap(a.data_);
}
void average(A& a)
{
assert(data_.size() == a.data_.size());
assert(this != &a);
Lock this_lock(mut_, boost::defer_lock);
UpgradeLock share_that_lock(a.mut_, boost::defer_lock);
boost::lock(this_lock, share_that_lock);
for (unsigned i = 0; i < data_.size(); ++i)
data_[i] = (data_[i] + a.data_[i]) / 2;
SharedLock share_this_lock(boost::move(this_lock));
Lock that_lock(boost::move(share_that_lock));
a.data_ = data_;
}
};
} // Assignment
void temp()
{
using namespace boost;
static upgrade_mutex mut;
unique_lock<upgrade_mutex> ul(mut);
shared_lock<upgrade_mutex> sl;
sl = BOOST_THREAD_MAKE_RV_REF(shared_lock<upgrade_mutex>(boost::move(ul)));
}
int main()
{
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
typedef boost::chrono::high_resolution_clock Clock;
typedef boost::chrono::duration<double> sec;
Clock::time_point t0 = Clock::now();
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
S::test_shared_mutex();
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
U::test_upgrade_mutex();
std::cout << __FILE__ << "[" <<__LINE__ << "]" << std::endl;
Clock::time_point t1 = Clock::now();
std::cout << sec(t1 - t0) << '\n';
return 0;
}
#else
#error "This platform doesn't support Boost.Chrono"
#endif

View File

@@ -1,12 +1,14 @@
// 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)
#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;
}
@@ -164,7 +166,7 @@ private:
void* _param;
};
int main(int argc, char* argv[])
int main()
{
boost::thread thrd_chef(&chef);
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };

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,12 @@
// 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>
#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 +29,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 +39,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 +95,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 < 1000000; ++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

@@ -1,10 +1,12 @@
// 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/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);
@@ -25,7 +27,7 @@ struct thread_alarm
int m_secs;
};
int main(int argc, char* argv[])
int main()
{
int secs = 5;
std::cout << "setting alarm for 5 seconds..." << std::endl;

View File

@@ -1,25 +1,72 @@
// 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/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;
}
int main(int argc, char* argv[])
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;
}

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/thread.hpp>
@@ -27,7 +27,7 @@ void thread_proc()
}
}
int main(int argc, char* argv[])
int main()
{
boost::thread_group threads;
for (int i=0; i<5; ++i)

View File

@@ -1,16 +1,18 @@
// 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/thread.hpp>
#define BOOST_THREAD_VERSION 2
#include <boost/thread/thread_only.hpp>
#include <boost/thread/xtime.hpp>
int main(int argc, char* argv[])
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

@@ -1,6 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// (C) Copyright 2008 Anthony Williams
// (C) Copyright 2008-9 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)
@@ -21,5 +21,6 @@
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/barrier.hpp>
#include <boost/thread/future.hpp>
#endif

View File

@@ -2,15 +2,18 @@
// David Moore, William E. Kempf
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_BARRIER_JDM030602_HPP
#define BOOST_BARRIER_JDM030602_HPP
#include <boost/thread/detail/config.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>
@@ -23,18 +26,20 @@ namespace boost
class barrier
{
public:
BOOST_THREAD_NO_COPYABLE( barrier )
barrier(unsigned int count)
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
boost::throw_exception(thread_exception(system::errc::invalid_argument, "barrier constructor: count cannot be zero."));
}
bool wait()
{
boost::mutex::scoped_lock lock(m_mutex);
boost::unique_lock<boost::mutex> lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;

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,26 @@
// cv_status.hpp
//
// Copyright (C) 2011 Vicente J. Botet Escriba
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_THREAD_CV_STATUS_HPP
#define BOOST_THREAD_CV_STATUS_HPP
#include <boost/detail/scoped_enum_emulation.hpp>
namespace boost
{
// enum class cv_status;
BOOST_SCOPED_ENUM_DECLARE_BEGIN(cv_status)
{
no_timeout,
timeout
}
BOOST_SCOPED_ENUM_DECLARE_END(cv_status)
}
#endif // header

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,7 +1,8 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2011-2013 Vicente J. Botet Escriba
//
// 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)
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
@@ -9,6 +10,323 @@
#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) \
&& ! 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) \
&& ! defined BOOST_THREAD_DONT_USE_MOVE
#define BOOST_THREAD_DONT_USE_MOVE
#endif
// This compiler doesn't support Boost.Container Allocators files
#if defined __SUNPRO_CC \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_CTOR_ALLOCATORS
#endif
#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_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
/// 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 && BOOST_THREAD_VERSION!=4
#error "BOOST_THREAD_VERSION must be 2, 3 or 4"
#endif
#endif
// CHRONO
// Uses Boost.Chrono by default if not stated the opposite defining BOOST_THREAD_DONT_USE_CHRONO
#if ! defined BOOST_THREAD_DONT_USE_CHRONO \
&& ! defined BOOST_THREAD_USES_CHRONO
#define BOOST_THREAD_USES_CHRONO
#endif
#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
// FUTURE_INVALID_AFTER_GET
#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
#define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
#endif
// NESTED_LOCKS
#if ! defined BOOST_THREAD_PROVIDES_NESTED_LOCKS \
&& ! defined BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS
#define BOOST_THREAD_DONT_PROVIDE_NESTED_LOCKS
#endif
// CONDITION
#if ! defined BOOST_THREAD_PROVIDES_CONDITION \
&& ! defined BOOST_THREAD_DONT_PROVIDE_CONDITION
#define BOOST_THREAD_DONT_PROVIDE_CONDITION
#endif
#endif // BOOST_THREAD_VERSION>=4
// INTERRUPTIONS
#if ! defined BOOST_THREAD_PROVIDES_INTERRUPTIONS \
&& ! defined BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
#define BOOST_THREAD_PROVIDES_INTERRUPTIONS
#endif
// CORRELATIONS
// EXPLICIT_LOCK_CONVERSION.
#if defined BOOST_THREAD_PROVIDES_EXPLICIT_LOCK_CONVERSION
#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION explicit
#else
#define BOOST_THREAD_EXPLICIT_LOCK_CONVERSION
#endif
// BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \
&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#endif
// 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
// 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_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)
# pragma warn -8008 // Condition always true/false
@@ -17,10 +335,23 @@
# 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) && ! defined BOOST_THREAD_DYN_LINK
# define BOOST_THREAD_DYN_LINK
#endif
// compatibility with the rest of Boost's auto-linking code:
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
#if defined(BOOST_THREAD_DYN_LINK) || defined(BOOST_ALL_DYN_LINK)
# undef BOOST_THREAD_USE_LIB
# define BOOST_THREAD_USE_DLL
#endif
@@ -31,8 +362,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
@@ -47,12 +379,18 @@
#if defined(BOOST_HAS_DECLSPEC)
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
# define BOOST_THREAD_DECL __declspec(dllexport)
# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT
//# define BOOST_THREAD_DECL __declspec(dllexport)
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
# define BOOST_THREAD_DECL __declspec(dllimport)
# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT
//# define BOOST_THREAD_DECL __declspec(dllimport)
# else
# define BOOST_THREAD_DECL
# endif
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
# define BOOST_THREAD_DECL BOOST_SYMBOL_VISIBLE
#else
# define BOOST_THREAD_DECL
#endif // BOOST_HAS_DECLSPEC
@@ -63,7 +401,7 @@
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
//
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
// once it's done with it:
// once it's done with it:
//
#if defined(BOOST_THREAD_USE_DLL)
# define BOOST_DYN_LINK

View File

@@ -0,0 +1,93 @@
// Distributed under the 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(const counter& count) : count_(count) {}
bool operator()() const { return count_ != 0; }
const counter& count_;
};
struct counter_is_zero
{
counter_is_zero(const counter& count) : count_(count) {}
bool operator()() const { return count_ == 0; }
const counter& count_;
};
}
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,45 @@
// 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_DELETE_HPP
#define BOOST_THREAD_DETAIL_DELETE_HPP
#include <boost/config.hpp>
/**
* 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_CXX11_DELETED_FUNCTIONS
#define BOOST_THREAD_DELETE_COPY_CTOR(CLASS) \
private: \
CLASS(CLASS&); \
public:
#define BOOST_THREAD_DELETE_COPY_ASSIGN(CLASS) \
private: \
CLASS& operator=(CLASS&); \
public:
#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)
#endif // BOOST_THREAD_DETAIL_DELETE_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,48 @@
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP
#define BOOST_THREAD_DETAIL_IS_CONVERTIBLE_HPP
#include <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

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

View File

@@ -2,21 +2,32 @@
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_MOVE_HPP
#define BOOST_THREAD_MOVE_HPP
#include <boost/thread/detail/config.hpp>
#ifndef BOOST_NO_SFINAE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/remove_cv.hpp>
#include <boost/type_traits/decay.hpp>
#endif
#include <boost/thread/detail/delete.hpp>
#include <boost/move/utility.hpp>
#include <boost/move/traits.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
template <typename T>
struct enable_move_utility_emulation_dummy_specialization;
template<typename T>
struct thread_move_t
{
@@ -39,20 +50,211 @@ namespace boost
};
}
#if !defined BOOST_THREAD_USES_MOVE
#ifndef BOOST_NO_SFINAE
template<typename T>
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, T >::type move(T& t)
typename enable_if<boost::is_convertible<T&,boost::detail::thread_move_t<T> >, boost::detail::thread_move_t<T> >::type move(T& t)
{
return T(detail::thread_move_t<T>(t));
return boost::detail::thread_move_t<T>(t);
}
#endif
template<typename T>
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t)
{
return t;
}
#endif //#if !defined BOOST_THREAD_USES_MOVE
}
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
#define BOOST_THREAD_RV_REF(TYPE) BOOST_RV_REF(TYPE)
#define BOOST_THREAD_RV_REF_2_TEMPL_ARGS(TYPE) BOOST_RV_REF_2_TEMPL_ARGS(TYPE)
#define BOOST_THREAD_RV_REF_BEG BOOST_RV_REF_BEG
#define BOOST_THREAD_RV_REF_END BOOST_RV_REF_END
#define BOOST_THREAD_RV(V) V
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
#define BOOST_THREAD_DCL_MOVABLE(TYPE)
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
namespace detail { \
template <typename T> \
struct enable_move_utility_emulation_dummy_specialization<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: integral_constant<bool, false> \
{}; \
}
#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
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
#define BOOST_THREAD_DCL_MOVABLE(TYPE)
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
namespace detail { \
template <typename T> \
struct enable_move_utility_emulation_dummy_specialization<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: integral_constant<bool, false> \
{}; \
}
#else
#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
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
#define BOOST_THREAD_DCL_MOVABLE(TYPE)
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
namespace detail { \
template <typename T> \
struct enable_move_utility_emulation_dummy_specialization<
#define BOOST_THREAD_DCL_MOVABLE_END > \
: integral_constant<bool, false> \
{}; \
}
#else
#define BOOST_THREAD_RV_REF(TYPE) boost::detail::thread_move_t< TYPE >
#define BOOST_THREAD_RV_REF_BEG boost::detail::thread_move_t<
#define BOOST_THREAD_RV_REF_END >
#define BOOST_THREAD_RV(V) (*V)
#define BOOST_THREAD_FWD_REF(TYPE) BOOST_FWD_REF(TYPE)
#define BOOST_THREAD_DCL_MOVABLE(TYPE) \
template <> \
struct enable_move_utility_emulation< TYPE > \
{ \
static const bool value = false; \
};
#define BOOST_THREAD_DCL_MOVABLE_BEG(T) \
template <typename T> \
struct enable_move_utility_emulation<
#define BOOST_THREAD_DCL_MOVABLE_END > \
{ \
static const bool value = false; \
};
#endif
namespace boost
{
namespace detail
{
template <typename T>
BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type)
make_rv_ref(T v) BOOST_NOEXCEPT
{
return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v);
}
// template <typename T>
// BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type)
// make_rv_ref(T &v) BOOST_NOEXCEPT
// {
// return (BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v);
// }
// template <typename T>
// const BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type)
// make_rv_ref(T const&v) BOOST_NOEXCEPT
// {
// return (const BOOST_THREAD_RV_REF(typename ::boost::remove_cv<typename ::boost::remove_reference<T>::type>::type))(v);
// }
}
}
#define BOOST_THREAD_MAKE_RV_REF(RVALUE) RVALUE.move()
//#define BOOST_THREAD_MAKE_RV_REF(RVALUE) boost::detail::make_rv_ref(RVALUE)
#endif
#if ! defined BOOST_NO_CXX11_RVALUE_REFERENCES
#define BOOST_THREAD_MOVABLE(TYPE)
#else
#if defined BOOST_THREAD_USES_MOVE
#define BOOST_THREAD_MOVABLE(TYPE) \
::boost::rv<TYPE>& move() BOOST_NOEXCEPT \
{ \
return *static_cast< ::boost::rv<TYPE>* >(this); \
} \
const ::boost::rv<TYPE>& move() const BOOST_NOEXCEPT \
{ \
return *static_cast<const ::boost::rv<TYPE>* >(this); \
} \
operator ::boost::rv<TYPE>&() \
{ \
return *static_cast< ::boost::rv<TYPE>* >(this); \
} \
operator const ::boost::rv<TYPE>&() const \
{ \
return *static_cast<const ::boost::rv<TYPE>* >(this); \
}\
#else
#define BOOST_THREAD_MOVABLE(TYPE) \
operator ::boost::detail::thread_move_t<TYPE>() BOOST_NOEXCEPT \
{ \
return move(); \
} \
::boost::detail::thread_move_t<TYPE> move() BOOST_NOEXCEPT \
{ \
::boost::detail::thread_move_t<TYPE> x(*this); \
return x; \
} \
#endif
#endif
#define BOOST_THREAD_MOVABLE_ONLY(TYPE) \
BOOST_THREAD_NO_COPYABLE(TYPE) \
BOOST_THREAD_MOVABLE(TYPE) \
#define BOOST_THREAD_COPYABLE_AND_MOVABLE(TYPE) \
BOOST_THREAD_MOVABLE(TYPE) \
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
}
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -19,6 +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)
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
# define BOOST_THREAD_BSD
#elif defined(sun) || defined(__sun)
@@ -29,12 +30,13 @@
# define BOOST_THREAD_HPUX
#elif defined(__CYGWIN__)
# define BOOST_THREAD_CYGWIN
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
#elif (defined(_WIN32) || defined(__WIN32__) || defined(WIN32)) && !defined(BOOST_DISABLE_WIN32)
# define BOOST_THREAD_WIN32
#elif defined(__BEOS__)
# 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)
#elif defined(__IBMCPP__) || defined(_AIX)
# define BOOST_THREAD_AIX
#elif defined(__amigaos__)
@@ -55,7 +57,7 @@
// dispatcher table. If there is no entry for a platform but pthreads is
// available on the platform, pthread is choosen as default. If nothing is
// available the preprocessor will fail with a diagnostic message.
#if defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_PLATFORM_PTHREAD
#else

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,154 @@
#ifndef BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
#define BOOST_THREAD_DETAIL_THREAD_GROUP_HPP
// Distributed under the 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-9 Anthony Williams
#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>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4251)
#endif
namespace boost
{
class thread_group
{
private:
thread_group(thread_group const&);
thread_group& operator=(thread_group const&);
public:
thread_group() {}
~thread_group()
{
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
delete *it;
}
}
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)
{
boost::lock_guard<shared_mutex> guard(m);
std::auto_ptr<thread> new_thread(new thread(threadfunc));
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);
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
if(it!=threads.end())
{
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)
{
(*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;
};
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,39 @@
#ifndef BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
#define BOOST_THREAD_DETAIL_THREAD_INTERRUPTION_HPP
// Distributed under the 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-9 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
#include <boost/thread/detail/config.hpp>
#include <boost/thread/detail/delete.hpp>
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
namespace boost
{
namespace this_thread
{
class BOOST_THREAD_DECL disable_interruption
{
bool interruption_was_enabled;
friend class restore_interruption;
public:
BOOST_THREAD_NO_COPYABLE(disable_interruption)
disable_interruption() BOOST_NOEXCEPT;
~disable_interruption() BOOST_NOEXCEPT;
};
class BOOST_THREAD_DECL restore_interruption
{
public:
BOOST_THREAD_NO_COPYABLE(restore_interruption)
explicit restore_interruption(disable_interruption& d) BOOST_NOEXCEPT;
~restore_interruption() BOOST_NOEXCEPT;
};
}
}
#endif // BOOST_THREAD_PROVIDES_INTERRUPTIONS
#endif // header

View File

@@ -12,27 +12,9 @@
#if defined(BOOST_HAS_WINTHREADS)
typedef void (__cdecl *thread_exit_handler)(void);
extern "C" BOOST_THREAD_DECL int at_thread_exit(
thread_exit_handler exit_handler
);
//Add a function to the list of functions that will
//be called when a thread is about to exit.
//Currently only implemented for Win32, but should
//later be implemented for all platforms.
//Used by Win32 implementation of Boost.Threads
//tss to perform cleanup.
//Like the C runtime library atexit() function,
//which it mimics, at_thread_exit() returns
//zero if successful and a nonzero
//value if an error occurs.
#endif //defined(BOOST_HAS_WINTHREADS)
#if defined(BOOST_HAS_WINTHREADS)
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
namespace boost
{
BOOST_THREAD_DECL void __cdecl on_process_enter(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
@@ -42,7 +24,7 @@
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
BOOST_THREAD_DECL void __cdecl on_process_exit(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
@@ -52,7 +34,7 @@
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_thread_enter(void);
BOOST_THREAD_DECL void __cdecl on_thread_enter(void);
//Function to be called just after a thread starts
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
@@ -61,7 +43,7 @@
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
//Function to be called just be fore a thread ends
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
@@ -70,10 +52,11 @@
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" void tss_cleanup_implemented(void);
void tss_cleanup_implemented();
//Dummy function used both to detect whether tss cleanup
//cleanup has been implemented and to force
//it to be linked into the Boost.Threads library.
}
#endif //defined(BOOST_HAS_WINTHREADS)

View File

@@ -1,8 +1,9 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007-8 Anthony Williams
// Copyright (C) 2007-9 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
//
// 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)
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
@@ -18,97 +19,207 @@
#include <string>
#include <stdexcept>
#include <boost/system/system_error.hpp>
#include <boost/system/error_code.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class BOOST_THREAD_DECL thread_interrupted
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
class BOOST_SYMBOL_VISIBLE thread_interrupted
{};
#endif
class BOOST_THREAD_DECL thread_exception : public std::exception
{
protected:
thread_exception();
thread_exception(int sys_err_code);
public:
~thread_exception() throw();
int native_error() const;
private:
int m_sys_err;
};
class condition_error:
public std::exception
class BOOST_SYMBOL_VISIBLE thread_exception:
public system::system_error
//public std::exception
{
typedef system::system_error base_type;
public:
const char* what() const throw()
thread_exception()
: base_type(0,system::system_category())
{}
thread_exception(int sys_error_code)
: base_type(sys_error_code, system::system_category())
{}
thread_exception( int ev, const char * what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
{
return "Condition error";
}
thread_exception( int ev, const std::string & what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
{
}
~thread_exception() throw()
{}
int native_error() const
{
return code().value();
}
};
class BOOST_THREAD_DECL lock_error : public thread_exception
{
public:
lock_error();
lock_error(int sys_err_code);
~lock_error() throw();
class BOOST_SYMBOL_VISIBLE condition_error:
public system::system_error
//public std::exception
{
typedef system::system_error base_type;
public:
condition_error()
: base_type(system::error_code(0, system::system_category()), "Condition error")
{}
condition_error( int ev )
: base_type(system::error_code(ev, system::system_category()), "Condition error")
{
}
condition_error( int ev, const char * what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
{
}
condition_error( int ev, const std::string & what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
{
}
};
virtual const char* what() const throw();
};
class BOOST_THREAD_DECL thread_resource_error : public thread_exception
{
public:
thread_resource_error();
thread_resource_error(int sys_err_code);
~thread_resource_error() throw();
class BOOST_SYMBOL_VISIBLE lock_error:
public thread_exception
{
typedef thread_exception base_type;
public:
lock_error()
: base_type(0, "boost::lock_error")
{}
virtual const char* what() const throw();
};
lock_error( int ev )
: base_type(ev, "boost::lock_error")
{
}
lock_error( int ev, const char * what_arg )
: base_type(ev, what_arg)
{
}
lock_error( int ev, const std::string & what_arg )
: base_type(ev, what_arg)
{
}
class BOOST_THREAD_DECL unsupported_thread_option : public thread_exception
{
public:
unsupported_thread_option();
unsupported_thread_option(int sys_err_code);
~unsupported_thread_option() throw();
~lock_error() throw()
{}
virtual const char* what() const throw();
};
};
class BOOST_THREAD_DECL invalid_thread_argument : public thread_exception
{
public:
invalid_thread_argument();
invalid_thread_argument(int sys_err_code);
~invalid_thread_argument() throw();
class BOOST_SYMBOL_VISIBLE thread_resource_error:
public thread_exception
{
typedef thread_exception base_type;
public:
thread_resource_error()
: base_type(system::errc::resource_unavailable_try_again, "boost::thread_resource_error")
{}
virtual const char* what() const throw();
};
thread_resource_error( int ev )
: base_type(ev, "boost::thread_resource_error")
{
}
thread_resource_error( int ev, const char * what_arg )
: base_type(ev, what_arg)
{
}
thread_resource_error( int ev, const std::string & what_arg )
: base_type(ev, what_arg)
{
}
class BOOST_THREAD_DECL thread_permission_error : public thread_exception
{
public:
thread_permission_error();
thread_permission_error(int sys_err_code);
~thread_permission_error() throw();
virtual const char* what() const throw();
};
~thread_resource_error() throw()
{}
};
class BOOST_SYMBOL_VISIBLE unsupported_thread_option:
public thread_exception
{
typedef thread_exception base_type;
public:
unsupported_thread_option()
: base_type(system::errc::invalid_argument, "boost::unsupported_thread_option")
{}
unsupported_thread_option( int ev )
: base_type(ev, "boost::unsupported_thread_option")
{
}
unsupported_thread_option( int ev, const char * what_arg )
: base_type(ev, what_arg)
{
}
unsupported_thread_option( int ev, const std::string & what_arg )
: base_type(ev, what_arg)
{
}
};
class BOOST_SYMBOL_VISIBLE invalid_thread_argument:
public thread_exception
{
typedef thread_exception base_type;
public:
invalid_thread_argument()
: base_type(system::errc::invalid_argument, "boost::invalid_thread_argument")
{}
invalid_thread_argument( int ev )
: base_type(ev, "boost::invalid_thread_argument")
{
}
invalid_thread_argument( int ev, const char * what_arg )
: base_type(ev, what_arg)
{
}
invalid_thread_argument( int ev, const std::string & what_arg )
: base_type(ev, what_arg)
{
}
};
class BOOST_SYMBOL_VISIBLE thread_permission_error:
public thread_exception
{
typedef thread_exception base_type;
public:
thread_permission_error()
: base_type(system::errc::permission_denied, "boost::thread_permission_error")
{}
thread_permission_error( int ev )
: base_type(ev, "boost::thread_permission_error")
{
}
thread_permission_error( int ev, const char * what_arg )
: base_type(ev, what_arg)
{
}
thread_permission_error( int ev, const std::string & what_arg )
: base_type(ev, what_arg)
{
}
};
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_THREAD_CONFIG_PDM070801_H
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif

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_parolle<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,142 @@
// Distributed under the 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_.value_ must be greater than 0
/// Effect: Decrement the count. Unlocks the lock notify anyone waiting if we reached zero.
/// Returns: true if count_.value_ reached the value 0.
/// @ThreadSafe ensured by the @c lk parameter
bool count_down(unique_lock<mutex> &lk)
/// pre_condition (count_.value_ > 0)
{
BOOST_ASSERT(count_.value_ > 0);
if (--count_.value_ == 0)
{
count_.cond_.notify_all();
lk.unlock();
return true;
}
return false;
}
public:
BOOST_THREAD_NO_COPYABLE( latch)
/// Constructs a latch with a given count.
latch(std::size_t count) :
count_(count)
{
}
/// 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_);
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_);
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_);
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 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_);
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()
{
boost::unique_lock<boost::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;
}
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;
}
private:
mutex mutex_;
detail::counter count_;
};
} // 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,42 @@
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2009-2012 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_LOCK_TRAITS_HPP
#define BOOST_THREAD_LOCK_TRAITS_HPP
#include <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 parolle".
*/
template <typename Lock>
struct is_strict_lock_sur_parolle : false_type {};
template <typename Lock>
struct is_strict_lock : is_strict_lock_sur_parolle<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,202 @@
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2011-2012 Vicente J. Botet Escriba
#ifndef BOOST_THREAD_LOCKABLE_TRAITS_HPP
#define BOOST_THREAD_LOCKABLE_TRAITS_HPP
#include <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_parolle
{
BOOST_STATIC_CONSTANT(bool, value = false);
};
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