2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-03 21:52:07 +00:00

Compare commits

...

199 Commits

Author SHA1 Message Date
Michael Glassford
9f9292e2e3 Fix compile errors: some compilers don't like an enum and the namespace it is in to have the same name; missing typename; _sntprintf not in namespace std for cw. Fix warnings on some compilers. Clean up scheduling algorithms to pass unit tests and hopefully eliminate reported deadlocks. Still needs work, but should be better than before.
[SVN r23859]
2004-07-20 21:33:13 +00:00
Michael Glassford
0a88a53a33 Fix compile errors: some compilers don't like an enum and the namespace it is in to have the same name.
[SVN r23858]
2004-07-20 21:29:39 +00:00
Michael Glassford
0bce1befd9 Remove line-continuation inside #if (cwpro8 seemed not to like it).
[SVN r23857]
2004-07-20 21:24:00 +00:00
Michael Glassford
9f354c98ab Renamed add_thread_exit() to at_thread_exit(), a better name.
[SVN r23856]
2004-07-20 21:22:55 +00:00
Michael Glassford
274b04bcf7 Add hooks for users to provide their own tss cleanup in win32 statically linked builds.
[SVN r23586]
2004-07-15 15:19:08 +00:00
Michael Glassford
539d19468d Add try_lock() method to scoped_timed_lock.
[SVN r23585]
2004-07-15 14:30:42 +00:00
Michael Glassford
fff6d9eddd Changes for WinCE.
[SVN r23584]
2004-07-15 14:27:50 +00:00
Michael Glassford
5472ebdfde Add hooks for users to provide their own tss cleanup in win32 statically linked builds.
[SVN r23583]
2004-07-15 14:26:10 +00:00
Michael Glassford
50c034f650 Fix enum definition.
[SVN r23582]
2004-07-15 14:23:19 +00:00
Michael Glassford
2a5e1a36b5 Add read_lock and write_lock and related classes; modify lock constructors; add promote() that throws exception if it fails; fix enum definition.
[SVN r23581]
2004-07-15 14:21:37 +00:00
Michael Glassford
2e10da00ba Add cancellation guard.
[SVN r23417]
2004-07-09 09:52:39 +00:00
Michael Glassford
af4b2d5d2a Changes for WinCE.
[SVN r23416]
2004-07-09 09:50:44 +00:00
Michael Glassford
a89ec945c0 Apply patch for SGI MIPSpro compiler.
[SVN r23406]
2004-07-08 14:42:04 +00:00
Michael Glassford
08eb9eed48 Add title.
[SVN r23405]
2004-07-08 13:52:15 +00:00
Michael Glassford
7ed1a79ab8 Apply min/max fixes from main branch.
[SVN r23196]
2004-06-25 20:45:38 +00:00
Michael Glassford
18974b3cb4 Remove rw* files that have been renamed to read_write_*
[SVN r23195]
2004-06-25 20:41:54 +00:00
Michael Glassford
c973faf627 Fix enums, constructors; TimedReadWriteLock concept refines TryReadWriteLock; cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23194]
2004-06-25 20:40:34 +00:00
Michael Glassford
6ffcde749a Remove HTML files that have been converted to BoostBook format.
[SVN r23193]
2004-06-25 20:40:21 +00:00
Michael Glassford
42840199aa Update release notes.
[SVN r23192]
2004-06-25 20:33:13 +00:00
Michael Glassford
1addb6ad9b Cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23188]
2004-06-25 20:04:34 +00:00
Michael Glassford
1dbdb77ed7 Add option to build as static library.
[SVN r23187]
2004-06-25 19:52:44 +00:00
Michael Glassford
430ebf66f9 Apply min/max fixes from main branch.
[SVN r23186]
2004-06-25 19:49:44 +00:00
Michael Glassford
97562928a8 Cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23185]
2004-06-25 19:36:47 +00:00
Michael Glassford
45aabefb4d Cleanup: always #include <boost/thread/detail/config.hpp> first.
[SVN r23184]
2004-06-25 19:22:18 +00:00
Michael Glassford
b0e970863b Proofreeding changes.
[SVN r23183]
2004-06-25 19:19:17 +00:00
Michael Glassford
3468fb61bc Convert documentation to BoostBook format.
[SVN r23182]
2004-06-25 19:17:49 +00:00
Michael Glassford
5982a97bdf Renamed from rw_* to read_write*.
[SVN r23161]
2004-06-22 22:17:17 +00:00
Michael Glassford
ffef009696 Renamed from test_rw_mutex.cpp.
[SVN r23160]
2004-06-22 22:16:47 +00:00
Michael Glassford
c8f181e461 Renamed from rw_mutex.cpp.
[SVN r23159]
2004-06-22 22:14:45 +00:00
Michael Glassford
7b84d69915 Renamed from rw_mutex-ref.xml.
[SVN r23158]
2004-06-22 22:06:21 +00:00
Michael Glassford
bbb8efe58f Renamed from rw_lock.hpp.
[SVN r23157]
2004-06-22 21:59:09 +00:00
Michael Glassford
63209e3c69 Renamed from rw_mutex.hpp.
[SVN r23156]
2004-06-22 21:57:38 +00:00
Michael Glassford
2272c322f9 Proofreeding changes.
[SVN r23155]
2004-06-22 21:37:24 +00:00
Michael Glassford
36acb80412 Add read/write mutex and related concepts.
[SVN r23154]
2004-06-22 21:36:32 +00:00
Michael Glassford
b72142cef7 Add entry for "undefined behavior".
[SVN r23153]
2004-06-22 21:35:11 +00:00
Michael Glassford
6dd6f51faa Remove documentation for unreleased thread pool.
[SVN r23152]
2004-06-22 21:33:55 +00:00
Michael Glassford
82630dc9bb Fix inconsistencies found while working on documentation.
[SVN r23151]
2004-06-22 21:28:53 +00:00
Michael Glassford
3402aea7c1 Change enumeration from anonymous to xtime_clock_types and remove unused clock types.
[SVN r23150]
2004-06-22 21:25:58 +00:00
Michael Glassford
5c4bd8e9c9 Finish conversion of documentation to BoostBook format.
[SVN r23122]
2004-06-18 21:30:19 +00:00
Michael Glassford
a11748d187 Finish conversion of documentation to BoostBook format.
[SVN r23048]
2004-06-07 21:45:26 +00:00
Michael Glassford
dc906613dc Finish conversion of documentation to BoostBook format.
[SVN r23047]
2004-06-07 19:04:02 +00:00
Michael Glassford
b69bdd3918 Finish conversion of documentation to BoostBook format.
[SVN r23046]
2004-06-07 16:01:05 +00:00
Michael Glassford
d90ef5eeef Finish conversion of documentation to BoostBook format.
[SVN r23045]
2004-06-07 14:42:24 +00:00
Michael Glassford
641d658a10 Finish conversion of documentation to BoostBook format.
[SVN r23044]
2004-06-07 14:30:36 +00:00
Michael Glassford
fef99d3db2 Finish conversion of documentation to BoostBook format.
[SVN r23021]
2004-06-03 16:36:57 +00:00
Michael Glassford
0fc8d8897d Finish conversion of documentation to BoostBook format.
[SVN r23011]
2004-06-02 19:38:15 +00:00
Michael Glassford
ad9f6244b0 Finish conversion of documentation to BoostBook format.
[SVN r23010]
2004-06-02 19:29:37 +00:00
Michael Glassford
59d082202c Finish conversion of documentation to BoostBook format.
[SVN r23009]
2004-06-02 19:24:03 +00:00
Michael Glassford
b7549a5bae Finish conversion of documentation to BoostBook format.
[SVN r23008]
2004-06-02 19:12:58 +00:00
Michael Glassford
f0dce755bb Finish conversion of documentation to BoostBook format.
[SVN r22957]
2004-05-27 19:43:24 +00:00
Michael Glassford
c1261d6df3 Proofreeding changes.
[SVN r22956]
2004-05-27 19:42:22 +00:00
Michael Glassford
1fb0dac16d Proofreeding changes.
[SVN r22955]
2004-05-27 19:34:39 +00:00
Michael Glassford
424d02fafa Proofreeding changes.
[SVN r22954]
2004-05-27 19:21:12 +00:00
Michael Glassford
52717aaa75 Finish conversion of documentation to BoostBook format.
[SVN r22953]
2004-05-27 15:49:50 +00:00
Michael Glassford
335f85ad5b Allow a mutex to be named, which allows it to be shared between two or more processes; currently implemented only for Win32.
Win32: use critical section instead of mutex whenever possible; abstract common code into functions.


[SVN r22827]
2004-05-15 02:02:43 +00:00
Michael Glassford
7da456edca Restore unintentionallly deleted BOOST_THREAD_DECL.
[SVN r22742]
2004-05-05 02:27:45 +00:00
Michael Glassford
f50176946d * Add lock promotion and demotion.
* Rename to improve consistency and eliminate abbreviations:
* Change try lock & timed lock constructor parameters for consistency.
* Add many assertions to test validity of mutex state and operations.
See change log in file for more details.


[SVN r22741]
2004-05-05 02:17:29 +00:00
Michael Glassford
aeafcbb822 Added MPTasks implementation; added comments to change log.
[SVN r22545]
2004-03-23 17:55:16 +00:00
Michael Glassford
171b890972 Added change log, fixed errors in comments, removed "unused parameter" warning.
[SVN r22544]
2004-03-23 17:47:29 +00:00
Michael Glassford
89a9531d34 Add missing pthread_mutexattr_destroy() to recursive_mutex::recursive_mutex() and recursive_try_mutex::recursive_try_mutex().
[SVN r22527]
2004-03-19 21:24:50 +00:00
Michael Glassford
3259f681a4 Merge fixes from main branch.
[SVN r22321]
2004-02-19 01:10:56 +00:00
Michael Glassford
17f72cf580 Merge minor changes from main branch.
[SVN r22320]
2004-02-19 01:10:07 +00:00
Michael Glassford
e03f0ed008 Merge minor changes from main branch.
[SVN r22319]
2004-02-19 01:00:42 +00:00
Michael Glassford
0804944002 Merge auto link changes from main branch.
[SVN r22318]
2004-02-19 00:57:36 +00:00
Michael Glassford
8e5d5002cd Merge fixes from main branch into thread_dev branch.
[SVN r22306]
2004-02-18 00:45:51 +00:00
Michael Glassford
008aaeaeee Merge fixes from HEAD into thread_dev branch.
[SVN r22238]
2004-02-11 16:02:52 +00:00
William E. Kempf
c1283bb731 Fixed thread join bugs. Fixed mutex creation bugs.
[SVN r18176]
2003-04-03 22:56:50 +00:00
William E. Kempf
46b1a4d1e3 Documented conditions with BoostBook
[SVN r18159]
2003-04-02 21:37:26 +00:00
William E. Kempf
ff6e0df2bc Removed <a> link.
[SVN r18150]
2003-04-01 15:41:51 +00:00
William E. Kempf
9cb9224b3c More BoostBook changes.
[SVN r18149]
2003-04-01 15:29:55 +00:00
William E. Kempf
5ea5494172 Added catalog.xml to .cvsignore.
[SVN r18145]
2003-04-01 01:46:42 +00:00
William E. Kempf
e4c27981d0 Added .cvsignore in doc directory.
[SVN r18144]
2003-04-01 01:45:24 +00:00
William E. Kempf
fe61772d47 Further conversions to DocBook.
[SVN r18143]
2003-04-01 01:44:32 +00:00
William E. Kempf
a437d6d7f6 Started migrating to Boost.Book.
[SVN r18117]
2003-03-27 23:24:44 +00:00
William E. Kempf
c9f52098b9 More changes for named mutexes.
[SVN r18063]
2003-03-22 22:28:57 +00:00
William E. Kempf
a15a35a4b6 Factored out named object support and made mutex a named object.
[SVN r17981]
2003-03-18 23:30:51 +00:00
William E. Kempf
14c8137ba6 Fixed name encoding algorithm.
[SVN r17929]
2003-03-14 22:56:29 +00:00
William E. Kempf
5caf9ed169 Further changes for name mapping in shared_memory.
[SVN r17896]
2003-03-13 18:43:55 +00:00
William E. Kempf
5da4a7b105 Added portable name mapping.
[SVN r17868]
2003-03-12 23:47:36 +00:00
William E. Kempf
91c4af37ad Fixed POSIX issues for shared_memory.
[SVN r17817]
2003-03-11 16:08:51 +00:00
William E. Kempf
5848dc2f56 More shared_memory changes.
[SVN r17816]
2003-03-11 15:47:22 +00:00
William E. Kempf
efa12b1db9 More shared_memory changes.
[SVN r17802]
2003-03-10 23:10:13 +00:00
William E. Kempf
58b6eba0ea Updated shared_memory to compile on Linux.
[SVN r17801]
2003-03-10 20:55:29 +00:00
William E. Kempf
f73253fcf5 Udpated shared_memory.
[SVN r17800]
2003-03-10 20:14:12 +00:00
William E. Kempf
3627dfc3b7 Removed warnings.
[SVN r17606]
2003-02-23 18:09:27 +00:00
William E. Kempf
f8ebb9a127 Added timed_join() and cancelled()
[SVN r17309]
2003-02-10 17:08:04 +00:00
William E. Kempf
2a0f57a8de Reformatted code and updated copyrights
[SVN r17274]
2003-02-07 22:50:55 +00:00
William E. Kempf
da7278acef Removed obsolete files.
[SVN r17273]
2003-02-07 22:22:35 +00:00
William E. Kempf
b17eb23f2e Updated thread_group to use the new thread reference implementation
[SVN r17135]
2003-01-31 21:23:11 +00:00
William E. Kempf
8e01ac5d04 Updated Jamfile
[SVN r17133]
2003-01-31 20:00:27 +00:00
William E. Kempf
5d6a1633e0 merged with thread_bae
[SVN r17100]
2003-01-30 23:05:44 +00:00
William E. Kempf
2e6f9a785e Updated Jamfile
[SVN r17098]
2003-01-30 21:20:28 +00:00
William E. Kempf
4e1acef27e Merged thread_base
[SVN r17096]
2003-01-30 20:51:12 +00:00
William E. Kempf
73e482832d Added bjam.log to .cvsignore
[SVN r17092]
2003-01-30 16:44:15 +00:00
William E. Kempf
949b332337 Removed warning messages
[SVN r17091]
2003-01-30 16:42:39 +00:00
nobody
244cfd3f01 This commit was manufactured by cvs2svn to create branch 'thread_dev'.
[SVN r17055]
2003-01-27 22:44:08 +00:00
William E. Kempf
3239fe0c22 Updated test cases for thread::attributes.
[SVN r17001]
2003-01-22 23:08:26 +00:00
William E. Kempf
ca10110aa7 Updated tests for new thread design
[SVN r16984]
2003-01-21 22:57:30 +00:00
William E. Kempf
fd4c76c7a5 Add cancellation_guard and test cases.
[SVN r16964]
2003-01-20 20:20:21 +00:00
William E. Kempf
60d7c84aa2 Fixed creation bug.
[SVN r16925]
2003-01-17 23:17:54 +00:00
William E. Kempf
c043efa346 Updated exceptions and removed conditional compilation.
[SVN r16897]
2003-01-13 23:05:14 +00:00
William E. Kempf
dab1961b5a Fixed bug in internal id() when pthread_t isn't a pointer type.
[SVN r16844]
2003-01-09 22:51:24 +00:00
William E. Kempf
6f94d26c50 Added full support for 'id' semantics.
[SVN r16842]
2003-01-09 21:17:39 +00:00
William E. Kempf
83baf142f2 Added thread::attributes.
[SVN r16808]
2003-01-08 22:25:15 +00:00
William E. Kempf
88bb39e3ce Fixed bug with cleanup_slots definition order on POSIX implementations.
[SVN r16807]
2003-01-08 22:22:54 +00:00
William E. Kempf
48ad27558a Updated new classes to DLL implementation. Worked out tss issues. Started thread implementation.
[SVN r16791]
2003-01-07 23:16:54 +00:00
William E. Kempf
a0ba7f174c Updated new classes to DLL implementation. Worked out tss issues. Started thread implementation.
[SVN r16789]
2003-01-07 23:08:51 +00:00
William E. Kempf
6e60d33181 Merged thread_development with thread_dev
[SVN r16776]
2003-01-06 23:24:59 +00:00
William E. Kempf
bc69926604 Merged thread_development with thread_dev
[SVN r16775]
2003-01-06 22:47:51 +00:00
nobody
d90825f7f9 This commit was manufactured by cvs2svn to create branch 'thread_dev'.
[SVN r16771]
2003-01-06 16:06:38 +00:00
William E. Kempf
d33e0c8ee1 Fixed Unicode problem (CreateMutex - CreateMutexA)
[SVN r16770]
2003-01-06 16:06:37 +00:00
William E. Kempf
3332649480 Fixed bug in to_duration.
[SVN r16769]
2003-01-06 15:55:57 +00:00
William E. Kempf
c918b66199 Switched to a DLL implementation
[SVN r16742]
2003-01-03 21:03:43 +00:00
William E. Kempf
dbbf56e17a Updated to new test library name
[SVN r16732]
2003-01-02 16:26:03 +00:00
William E. Kempf
c77500c15a Updated Jamfile to remove unused code
[SVN r16725]
2002-12-30 23:14:30 +00:00
Dave Abrahams
75084aaa96 HP aCC workarounds
[SVN r16518]
2002-12-04 17:56:59 +00:00
William E. Kempf
35714c8f1c Added new tutorials
[SVN r16007]
2002-10-28 14:17:49 +00:00
William E. Kempf
3699cc97a6 Added new tutorial files
[SVN r16005]
2002-10-28 14:10:14 +00:00
Vladimir Prus
5a7377acda Made Boost.Thread compile with V2.
[SVN r15969]
2002-10-23 13:22:56 +00:00
Beman Dawes
6aaee629b5 Fix acknowledgements and copyright
[SVN r15759]
2002-10-07 00:07:46 +00:00
Björn Karlsson
b465fe569c Merged from branch to trunk
[SVN r15613]
2002-10-01 15:00:37 +00:00
Björn Karlsson
5e6f72a688 Merged from branch to trunk
[SVN r15524]
2002-09-26 09:17:19 +00:00
William E. Kempf
51f80f6c15 Removed incorrect usages of typename
[SVN r15185]
2002-09-06 19:49:10 +00:00
William E. Kempf
45c314e594 Changed tabs to spaces.
[SVN r15180]
2002-09-06 15:35:39 +00:00
William E. Kempf
cfce0892e0 Added tutorial sources. Changed tabs to spaces.
[SVN r15179]
2002-09-06 15:34:48 +00:00
William E. Kempf
05d1abf030 Added build documentation. Changed tabs to spaces.
[SVN r15178]
2002-09-06 15:33:54 +00:00
Dave Abrahams
6c24a2626b Fix stupid mistake
[SVN r15058]
2002-08-22 16:13:59 +00:00
Dave Abrahams
870c75bd12 Stop using unit-test since it has problems with JAMSHELL setting with gcc
[SVN r15033]
2002-08-21 15:29:18 +00:00
William E. Kempf
5fdd771708 Fixed some bugs and warnings produced by borland and gcc
[SVN r14944]
2002-08-17 16:34:23 +00:00
William E. Kempf
06f39ac409 Changed examples in documents to links to actual code
[SVN r14939]
2002-08-16 21:43:31 +00:00
William E. Kempf
c92b0a2fb7 An attempt to make InterlockedCompareExchange more portable
[SVN r14938]
2002-08-16 21:19:48 +00:00
William E. Kempf
8a8d0e05ca Added pre-Win64 support for InterlockedCompareExchange
[SVN r14937]
2002-08-16 20:16:03 +00:00
William E. Kempf
74bae2baac Added library-root level index.html for Boost.Threads
[SVN r14914]
2002-08-15 23:37:20 +00:00
William E. Kempf
4ba48676bd Fixed some warnings produced by Borland in the regression test
[SVN r14875]
2002-08-15 03:39:24 +00:00
William E. Kempf
78480e7951 Removed subdirectories
[SVN r14870]
2002-08-15 01:39:07 +00:00
William E. Kempf
4cb9c412e8 Added examples from documentation
[SVN r14869]
2002-08-15 01:22:29 +00:00
William E. Kempf
75c83fed96 Fixed time precision bugs. Switched to Interlocked* methods for once.
[SVN r14867]
2002-08-15 00:05:54 +00:00
William E. Kempf
391de20ae0 Added test_xtime.cpp
[SVN r14852]
2002-08-14 20:39:32 +00:00
William E. Kempf
1e2a9e8971 Fixed Jamfile issues with tests
[SVN r14818]
2002-08-13 19:19:09 +00:00
William E. Kempf
43cbd3a283 Split up tests into seperate files and switched fully to unit test framework
[SVN r14780]
2002-08-12 05:43:10 +00:00
William E. Kempf
31cf6b5e64 Initial switch to Boost.Test unit test framework
[SVN r14779]
2002-08-12 00:09:33 +00:00
Dave Abrahams
99109ab78b respect <sysinclude>
[SVN r13995]
2002-05-21 16:24:07 +00:00
William E. Kempf
a80d5f159d Merged from RC_1_28_0 branch
[SVN r13905]
2002-05-15 14:35:39 +00:00
William E. Kempf
7ba4fc4aed Changed logic_error to runtime_error for thread_resource_error
[SVN r13644]
2002-05-03 16:19:13 +00:00
William E. Kempf
9fb31e9868 Updated documentation for pending release
[SVN r13606]
2002-05-01 15:37:25 +00:00
William E. Kempf
3a2246de5b Fixed broken links
[SVN r13570]
2002-04-26 21:15:40 +00:00
William E. Kempf
e7c4e2fa57 Removed boost/thread/config.hpp and changed Boost.Threads exceptions to derive from logic_error
[SVN r13568]
2002-04-26 20:56:49 +00:00
William E. Kempf
724ab285f0 Updated the rest of the documentation to the new templates.
[SVN r13567]
2002-04-26 20:41:25 +00:00
William E. Kempf
d60e66fb00 More Boost.Threads doc changes
[SVN r13453]
2002-04-11 22:15:26 +00:00
William E. Kempf
97cdaca028 Boost.Threads documentation updates.
[SVN r13439]
2002-04-10 22:08:15 +00:00
Dave Abrahams
3044c8f905 Bug fix
[SVN r13341]
2002-04-01 20:13:43 +00:00
William E. Kempf
2775a2a945 Updated <runtime-link> info in Jamfile
[SVN r13198]
2002-03-14 23:29:18 +00:00
William E. Kempf
c43c1febba Fixed bug in example in mutex.html
[SVN r13197]
2002-03-14 23:24:16 +00:00
William E. Kempf
ceb6471d57 Updated thread.html for new documentation style.
[SVN r13196]
2002-03-14 23:23:48 +00:00
William E. Kempf
b99cc044f3 Updated Jamfile
[SVN r13095]
2002-03-05 16:27:46 +00:00
Rene Rivera
d91429dcec Moved the <runtime-link> to the build request.
[SVN r13018]
2002-03-02 18:41:22 +00:00
William E. Kempf
b1d1f7d8f1 Jamfile modifications
[SVN r13001]
2002-03-01 23:10:11 +00:00
Dave Abrahams
86b608cf41 Updates to work on Linux
[SVN r12981]
2002-02-28 12:35:05 +00:00
Dave Abrahams
f263f75751 Killed bogus runtime-link specification
[SVN r12946]
2002-02-27 02:11:12 +00:00
William E. Kempf
24bec05b86 Added .cvsignore and updated Jam stuff
[SVN r12944]
2002-02-26 21:02:13 +00:00
William E. Kempf
ce1a5e9359 fixed missing } bug
[SVN r12903]
2002-02-22 18:32:08 +00:00
William E. Kempf
311525bc06 replaced <dll>thread_mon with $(THREADMON_DLL)
[SVN r12902]
2002-02-22 18:31:20 +00:00
William E. Kempf
ecdfd96529 fixed typename warnings
[SVN r12901]
2002-02-22 18:30:34 +00:00
William E. Kempf
5aab32bc1a More Jamfile changes.
[SVN r12857]
2002-02-18 23:04:25 +00:00
William E. Kempf
e152a1c6f2 Updated Jamfiles for new Boost.Build system
[SVN r12856]
2002-02-18 23:02:38 +00:00
Rene Rivera
e84fde78ec Updated the basic Jamfiles for the new Boost.Build changes.
[SVN r12798]
2002-02-14 04:08:20 +00:00
William E. Kempf
6ec4652bcf Updated thread documentation to use new templates.
[SVN r12785]
2002-02-11 23:13:04 +00:00
William E. Kempf
a5239c820b Fixed tabs in files
[SVN r12622]
2002-02-01 17:31:46 +00:00
William E. Kempf
41b001b22c Removed warnings reported by gcc.
[SVN r12492]
2002-01-24 19:17:36 +00:00
William E. Kempf
34e903b8b0 Fixed bug in example.
[SVN r12489]
2002-01-24 19:13:19 +00:00
Mac Murrett
2b67e953fd Changed prefix file to debug_prefix.hpp
[SVN r12487]
2002-01-24 17:33:03 +00:00
Mac Murrett
aa0d3adf1d *** empty log message ***
[SVN r12486]
2002-01-24 17:26:13 +00:00
Mac Murrett
a1f57a8a80 *** empty log message ***
[SVN r12485]
2002-01-24 17:19:44 +00:00
William E. Kempf
6bc82a8580 Added Mac Carbon implementation to Boost.Threads.
[SVN r12480]
2002-01-24 16:32:23 +00:00
William E. Kempf
c4c2e5d3a2 Fixed bug in notify_one that caused deadlock.
[SVN r12178]
2001-12-31 17:18:46 +00:00
Dave Abrahams
dd7d4b2173 Metrowerks needs BOOST_NO_STD_LOCALE in config to be able to compile regex
regex test Jamfile updates so that some tests will actually run
warning suppression for condition.cpp

unit-test rule now accepts input files
updated metrowerks and borland to properly set up path for running tests

----------------------------------------------------------------------
Modified Files:
	boost/config/compiler/metrowerks.hpp
	libs/python/src/gen_function.py libs/regex/test/Jamfile
 Tag: thread-initial
	libs/thread/src/condition.cpp
 No tag
	tools/build/boost-base.jam tools/build/borland-tools.jam
	tools/build/metrowerks-tools.jam
----------------------------------------------------------------------


[SVN r11853]
2001-12-02 17:43:45 +00:00
Beman Dawes
2719c4d545 Try to get the date stamps in sync
[SVN r11618]
2001-11-07 00:37:59 +00:00
Beman Dawes
33c1e36b54 Add "Why has semaphore disappeared" FAQ
[SVN r11586]
2001-11-05 15:42:10 +00:00
William E. Kempf
e7e46e185e Fixed bug found compiling with gcc.
[SVN r11584]
2001-11-05 15:13:57 +00:00
William E. Kempf
9200d48873 Added lock_ops<> detail concept.
[SVN r11540]
2001-11-02 23:34:50 +00:00
William E. Kempf
831d054d24 Added exceptions.cpp.
[SVN r11502]
2001-11-01 16:19:44 +00:00
William E. Kempf
f3af804ddb Removed semaphores. Fixed some reported bugs. Switched to CRITICAL_SECTION implementations.
[SVN r11501]
2001-11-01 16:18:57 +00:00
John Maddock
1f35149ef0 Added code to normalise timespec structures.
[SVN r11500]
2001-11-01 12:56:57 +00:00
William E. Kempf
554a18842f Switched to void* for HANDLE types. Changed boost::once_init to the macro BOOST_ONCE_INIT.
[SVN r11475]
2001-10-30 22:12:37 +00:00
William E. Kempf
869243b6d1 Updated Jamfiles for PTW32, removed _atomic.cpp and added Win32 conditional compilation blocks for threadmon files.
[SVN r11468]
2001-10-29 22:20:50 +00:00
William E. Kempf
c0da02326a Fixed reported documentation bugs.
[SVN r11462]
2001-10-29 16:58:17 +00:00
William E. Kempf
9b5f666fc5 Removed tabs and trailing white space.
[SVN r11403]
2001-10-18 19:56:32 +00:00
William E. Kempf
1ce93426a4 Fixed Jamfile.
[SVN r11396]
2001-10-16 22:10:45 +00:00
William E. Kempf
6dacf3478b Fixed sprintf bugs in once.cpp.
[SVN r11395]
2001-10-16 19:32:20 +00:00
William E. Kempf
dff91699c3 Fixed more warnings and errors found when compiling with gcc.
[SVN r11388]
2001-10-15 21:28:11 +00:00
William E. Kempf
9f83e8c1fc Modified Jamfile to allow for building using pthreads-win32 (code is commented out).
[SVN r11387]
2001-10-15 18:34:01 +00:00
William E. Kempf
7b07cb0759 Fixed errors and warnings for gcc. Still some outstanding issues for gcc on Win32.
[SVN r11386]
2001-10-15 18:32:21 +00:00
William E. Kempf
c2e7091632 Fixed reported warnings. Fixed once bug with void* and function pointer conversion.
[SVN r11385]
2001-10-15 00:48:51 +00:00
Beman Dawes
1ab320042e Minor typo fix and wording improvements
[SVN r11365]
2001-10-08 20:20:07 +00:00
William E. Kempf
b0cd307eaf Ran "tidy" against documentation.
[SVN r11329]
2001-10-02 16:13:25 +00:00
Beman Dawes
ca2cf20cf3 1.25.0 Final runup
[SVN r11315]
2001-10-01 15:54:23 +00:00
Beman Dawes
b3acba1d2d commit after merging thread-initial into main trunk
[SVN r11258]
2001-09-25 19:20:11 +00:00
Beman Dawes
6d2731c463 commit after merging thread-initial into main trunk
[SVN r11250]
2001-09-25 16:57:26 +00:00
Beman Dawes
b7f8f8867c merge branch "thread-initial" into main trunk
[SVN r11243]
2001-09-25 00:04:45 +00:00
145 changed files with 21702 additions and 0 deletions

3
build/.cvsignore Normal file
View File

@@ -0,0 +1,3 @@
bin*
*.pdb
bjam.log

132
build/Jamfile Normal file
View File

@@ -0,0 +1,132 @@
# Copyright (C) 2001-2003
# William E. Kempf
#
# Permission to use, copy, modify, distribute and sell this software
# and its documentation for any purpose is hereby granted without fee,
# provided that the above copyright notice appear in all copies and
# that both that copyright notice and this permission notice appear
# in supporting documentation. William E. Kempf makes no representations
# about the suitability of this software for any purpose.
# It is provided "as is" without express or implied warranty.
#
# Boost.Threads build Jamfile
#
# Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is
# mostly used for testing and it's generally recommended you use the
# native threading libraries instead. PTW32 should be set to be a list
# of two strings, the first specifying the installation path of the
# pthreads-win32 library and the second specifying which library
# variant to link against (see the pthreads-win32 documentation).
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
# Declare the location of this subproject relative to the root.
subproject libs/thread/build ;
# Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types.
import ./threads ;
{
CPP_SOURCES =
barrier
condition
exceptions
mutex
named
once
recursive_mutex
read_write_mutex
shared_memory
thread
threadmon
thread_pool
tss
xtime
;
template boost_thread_lib_base
: ## sources ##
<template>thread_base
../src/$(CPP_SOURCES).cpp
: ## requirements ##
<define>BOOST_THREAD_BUILD_LIB=1
<runtime-link>static
# the common names rule ensures that the library will
# be named according to the rules used by the install
# and auto-link features:
common-variant-tag
: ## default build ##
;
template thread_dll_base
: ## sources ##
<template>thread_base
../src/$(CPP_SOURCES).cpp
: ## requirements ##
<define>BOOST_THREAD_BUILD_DLL=1
<runtime-link>dynamic
# the common names rule ensures that the library will
# be named according to the rules used by the install
# and auto-link features:
common-variant-tag
: ## default build ##
;
lib $(boost_thread_lib_name)
: ## sources ##
<template>boost_thread_lib_base
: ## requirements ##
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name)
: ## default build ##
;
dll $(boost_thread_lib_name)
: ## sources ##
<template>thread_dll_base
: ## requirements ##
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name)
: ## default build ##
;
stage bin-stage
: <dll>$(boost_thread_lib_name)
<lib>$(boost_thread_lib_name)
;
install thread lib
: <dll>$(boost_thread_lib_name)
<lib>$(boost_thread_lib_name)
;
if $(boost_thread_lib_settings_ptw32)
{
lib $(boost_thread_lib_name_ptw32)
: ## sources ##
<template>boost_thread_lib_base
: ## requirements ##
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
$(pthreads-win32)
;
dll $(boost_thread_lib_name_ptw32)
: ## sources ##
<template>thread_dll_base
: ## requirements ##
<define>BOOST_THREAD_LIB_NAME=$(boost_thread_lib_name_ptw32)
$(pthreads-win32)
;
stage bin-stage
: <dll>$(boost_thread_lib_name_ptw32)
<lib>$(boost_thread_lib_name_ptw32)
;
install thread lib
: <dll>$(boost_thread_lib_name_ptw32)
<lib>$(boost_thread_lib_name_ptw32)
;
}
}

12
build/Jamfile.v2 Normal file
View File

@@ -0,0 +1,12 @@
# Declare the uses system library
lib pthread : : <name>pthread ;
project boost/thread
: source-location ../src
: usage-requirements <library>pthread
;
CPP_SOURCES = condition mutex recursive_mutex thread tss xtime once exceptions ;
lib boost_thread : $(CPP_SOURCES).cpp ;

45
build/threads.jam Normal file
View File

@@ -0,0 +1,45 @@
# Copyright (C) 2001-2003
# William E. Kempf
#
# Permission to use, copy, modify, distribute and sell this software
# and its documentation for any purpose is hereby granted without fee,
# provided that the above copyright notice appear in all copies and
# that both that copyright notice and this permission notice appear
# in supporting documentation. William E. Kempf makes no representations
# about the suitability of this software for any purpose.
# It is provided "as is" without express or implied warranty.
# Do some OS-specific setup
{
#thread library name
boost_thread_lib_name = boost_thread ;
#thread library name with "pthreads-win32" library
boost_thread_lib_name_ptw32 = boost_thread_ptw32 ;
if $(NT)
{
if $(PTW32_DIR)
{
if $(PTW32_LIB)
{
boost_thread_lib_settings_ptw32 =
<define>BOOST_HAS_PTHREADS
<define>PtW32NoCatchWarn
<include>$(PTW32_DIR)/pre-built/include
<library-file>$(PTW32_DIR)/pre-built/lib/$(PTW32_LIB)
;
}
}
}
template thread_base
: ## sources ##
: ## requirements ##
<sysinclude>$(BOOST_ROOT)
<threading>multi
<borland><*><cxxflags>-w-8004
<borland><*><cxxflags>-w-8057
: ## default build ##
;
}

BIN
build/threads.mcp Normal file

Binary file not shown.

3
doc/.cvsignore Normal file
View File

@@ -0,0 +1,3 @@
bin
html
catalog.xml

5
doc/Jamfile.v2 Normal file
View File

@@ -0,0 +1,5 @@
project boost/doc ;
import boostbook : boostbook ;
boostbook doc : thread.xml ;

64
doc/acknowledgements.xml Normal file
View File

@@ -0,0 +1,64 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="thread.acknowledgements"
last-revision="$Date$">
<title>Acknowledgements</title>
<para>William E. Kempf was the architect, designer, and implementor of
&Boost.Threads;.</para>
<para>Mac OS Carbon implementation written by Mac Murrett.</para>
<para>Dave Moore provided initial submissions and further comments on the
<code>barrier</code>
,
<code>thread_pool</code>
,
<code>read_write_mutex</code>
,
<code>read_write_try_mutex</code>
and
<code>read_write_timed_mutex</code>
classes.</para>
<para>Important contributions were also made by Jeremy Siek (lots of input
on the design and on the implementation), Alexander Terekhov (lots of input
on the Win32 implementation, especially in regards to boost::condition, as
well as a lot of explanation of POSIX behavior), Greg Colvin (lots of input
on the design), Paul Mclachlan, Thomas Matelich and Iain Hanson (for help
in trying to get the build to work on other platforms), and Kevin S. Van
Horn (for several updates/corrections to the documentation).</para>
<para>Mike Glassford finished changes to &Boost.Threads; that were begun
by William Kempf and moved them into the main CVS branch.
He also addressed a number of issues that were brought up on the Boost
developer's mailing list and provided some additions and changes to the
read_write_mutex and related classes.</para>
<para>The documentation was written by William E. Kempf. Beman Dawes
provided additional documentation material and editing.
Mike Glassford finished William Kempf's conversion of the documentation to
BoostBook format and added a number of new sections.</para>
<para>Discussions on the boost.org mailing list were essential in the
development of &Boost.Threads;
. As of August 1, 2001, participants included Alan Griffiths, Albrecht
Fritzsche, Aleksey Gurtovoy, Alexander Terekhov, Andrew Green, Andy Sawyer,
Asger Alstrup Nielsen, Beman Dawes, Bill Klein, Bill Rutiser, Bill Wade,
Branko &egrave;ibej, Brent Verner, Craig Henderson, Csaba Szepesvari,
Dale Peakall, Damian Dixon, Dan Nuffer, Darryl Green, Daryle Walker, David
Abrahams, David Allan Finch, Dejan Jelovic, Dietmar Kuehl, Douglas Gregor,
Duncan Harris, Ed Brey, Eric Swanson, Eugene Karpachov, Fabrice Truillot,
Frank Gerlach, Gary Powell, Gernot Neppert, Geurt Vos, Ghazi Ramadan, Greg
Colvin, Gregory Seidman, HYS, Iain Hanson, Ian Bruntlett, J Panzer, Jeff
Garland, Jeff Paquette, Jens Maurer, Jeremy Siek, Jesse Jones, Joe Gottman,
John (EBo) David, John Bandela, John Maddock, John Max Skaller, John
Panzer, Jon Jagger , Karl Nelson, Kevlin Henney, KG Chandrasekhar, Levente
Farkas, Lie-Quan Lee, Lois Goldthwaite, Luis Pedro Coelho, Marc Girod, Mark
A. Borgerding, Mark Rodgers, Marshall Clow, Matthew Austern, Matthew Hurd,
Michael D. Crawford, Michael H. Cox , Mike Haller, Miki Jovanovic, Nathan
Myers, Paul Moore, Pavel Cisler, Peter Dimov, Petr Kocmid, Philip Nash,
Rainer Deyke, Reid Sweatman, Ross Smith, Scott McCaskill, Shalom Reich,
Steve Cleary, Steven Kirk, Thomas Holenstein, Thomas Matelich, Trevor
Perrin, Valentin Bonnard, Vesa Karvonen, Wayne Miller, and William
Kempf.</para>
<para>Apologies for anyone inadvertently missed.</para>
</section>

78
doc/barrier-ref.xml Normal file
View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/barrier.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="barrier">
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<purpose>
<para>An object of class <classname>barrier</classname> is a synchronization
primitive used to cause a set of threads to wait until they each perform a
certain function or each reach a particular point in their execution.</para>
</purpose>
<description>
<para>When a barrier is created, it is initialized with a thread count N.
The first N-1 calls to <code>wait()</code> will all cause their threads to be blocked.
The Nth call to <code>wait()</code> will allow all of the waiting threads, including
the Nth thread, to be placed in a ready state. The Nth call will also "reset"
the barrier such that, if an additional N+1th call is made to <code>wait()</code>,
it will be as though this were the first call to <code>wait()</code>; in other
words, the N+1th to 2N-1th calls to <code>wait()</code> will cause their
threads to be blocked, and the 2Nth call to <code>wait()</code> will allow all of
the waiting threads, including the 2Nth thread, to be placed in a ready state
and reset the barrier. This functionality allows the same set of N threads to re-use
a barrier object to synchronize their execution at multiple points during their
execution.</para>
<para>See <xref linkend="threads.glossary"/> for definitions of thread
states <link linkend="threads.glossary.thread-state">blocked</link>
and <link linkend="threads.glossary.thread-state">ready</link>.
Note that "waiting" is a synonym for blocked.</para>
</description>
<constructor>
<parameter name="count">
<paramtype>size_t</paramtype>
</parameter>
<effects><simpara>Constructs a <classname>barrier</classname> object that
will cause <code>count</code> threads to block on a call to <code>wait()</code>.
</simpara></effects>
</constructor>
<destructor>
<effects><simpara>Destroys <code>*this</code>. If threads are still executing
their <code>wait()</code> operations, the behavior for these threads is undefined.
</simpara></effects>
</destructor>
<method-group name="waiting">
<method name="wait">
<type>bool</type>
<effects><simpara>Wait until N threads call <code>wait()</code>, where
N equals the <code>count</code> provided to the constructor for the
barrier object.</simpara>
<simpara><emphasis role="bold">Note</emphasis> that if the barrier is
destroyed before <code>wait()</code> can return, the behavior is
undefined.</simpara></effects>
<returns>Exactly one of the N threads will receive a return value
of <code>true</code>, the others will receive a value of <code>false</code>.
Precisely which thread receives the return value of <code>true</code> will
be implementation-defined. Applications can use this value to designate one
thread as a leader that will take a certain action, and the other threads
emerging from the barrier can wait for that action to take place.</returns>
</method>
</method-group>
</class>
</namespace>
</header>

230
doc/bibliography.xml Normal file
View File

@@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<bibliography id="threads.bibliography"
last-revision="$Date$">
<title>Bibliography</title>
<biblioentry id="threads.bib.AndrewsSchneider83">
<abbrev id="threads.bib.AndrewsSchneider83.abbrev">AndrewsSchnieder83</abbrev>
<biblioset relation="journal">
<title>ACM Computing Surveys</title>
<volumenum>Vol. 15</volumenum>
<issuenum>No. 1</issuenum>
<date>March, 1983</date>
</biblioset>
<biblioset relation="article">
<authorgroup>
<author>
<firstname>Gregory</firstname>
<othername>R.</othername>
<surname>Andrews</surname>
</author>
<author>
<firstname>Fred</firstname>
<othername>B.</othername>
<surname>Schneider</surname>
</author>
</authorgroup>
<title>
<ulink
url="http://www.acm.org/pubs/citations/journals/surveys/1983-15-1/p3-andrews/"
>Concepts and Notations for Concurrent Programming</ulink>
</title>
</biblioset>
<para>Good general background reading. Includes descriptions of Path
Expressions, Message Passing, and Remote Procedure Call in addition to the
basics</para>
</biblioentry>
<biblioentry id="threads.bib.Boost">
<abbrev id="threads.bib.Boost.abbrev">Boost</abbrev>
<bibliomisc>The <emphasis>Boost</emphasis> world wide web site.
<ulink url="http:/www.boost.org">http://www.boost.org</ulink></bibliomisc>
<para>&Boost.Threads; is one of many Boost libraries. The Boost web
site includes a great deal of documentation and general information which
applies to all Boost libraries. Current copies of the libraries including
documentation and test programs may be downloaded from the web
site.</para>
</biblioentry>
<biblioentry id="threads.bib.Hansen73">
<abbrev id="threads.bib.Hansen73.abbrev">Hansen73</abbrev>
<biblioset relation="journal">
<title>ACM Computing Surveys</title>
<volumenum>Vol. 5</volumenum>
<issuenum>No. 4</issuenum>
<date>December, 1983</date>
</biblioset>
<biblioset relation="article">
<author>0-201-63392-2
<firstname>Per Brinch</firstname>
<lastname>Hansen</lastname>
</author>
<title>
<ulink
url="http://www.acm.org/pubs/articles/journals/surveys/1973-5-4/p223-hansen/"
>Concurrent Programming Concepts</ulink>
</title>
</biblioset>
<para>"This paper describes the evolution of language features for
multiprogramming from event queues and semaphores to critical regions and
monitors." Includes analysis of why events are considered error-prone. Also
noteworthy because of an introductory quotation from Christopher Alexander;
Brinch Hansen was years ahead of others in recognizing pattern concepts
applied to software, too.</para>
</biblioentry>
<biblioentry id="threads.bib.Butenhof97">
<abbrev id="threads.bib.Butenhof97.abbrev">Butenhof97</abbrev>
<title>
<ulink url="http://cseng.aw.com/book/0,3828,0201633922,00.html"
>Programming with POSIX Threads </ulink>
</title>
<author>
<firstname>David</firstname>
<othername>R.</othername>
<surname>Butenhof</surname>
</author>
<publisher>Addison-Wesley</publisher>
<copyright><year>1997</year></copyright>
<isbn>ISNB: 0-201-63392-2</isbn>
<para>This is a very readable explanation of threads and how to use
them. Many of the insights given apply to all multithreaded programming, not
just POSIX Threads</para>
</biblioentry>
<biblioentry id="threads.bib.Hoare74">
<abbrev id="threads.bib.Hoare74.abbrev">Hoare74</abbrev>
<biblioset relation="journal">
<title>Communications of the ACM</title>
<volumenum>Vol. 17</volumenum>
<issuenum>No. 10</issuenum>
<date>October, 1974</date>
</biblioset>
<biblioset relation="article">
<title>
<ulink url=" http://www.acm.org/classics/feb96/"
>Monitors: An Operating System Structuring Concept</ulink>
</title>
<author>
<firstname>C.A.R.</firstname>
<surname>Hoare</surname>
</author>
<pagenums>549-557</pagenums>
</biblioset>
<para>Hoare and Brinch Hansen's work on Monitors is the basis for reliable
multithreading patterns. This is one of the most often referenced papers in
all of computer science, and with good reason.</para>
</biblioentry>
<biblioentry id="threads.bib.ISO98">
<abbrev id="threads.bib.ISO98.abbrev">ISO98</abbrev>
<title>
<ulink url="http://www.ansi.org">Programming Language C++</ulink>
</title>
<orgname>ISO/IEC</orgname>
<releaseinfo>14882:1998(E)</releaseinfo>
<para>This is the official C++ Standards document. Available from the ANSI
(American National Standards Institute) Electronic Standards Store.</para>
</biblioentry>
<biblioentry id="threads.bib.McDowellHelmbold89">
<abbrev id="threads.bib.McDowellHelmbold89.abbrev">McDowellHelmbold89</abbrev>
<biblioset relation="journal">
<title>Communications of the ACM</title>
<volumenum>Vol. 21</volumenum>
<issuenum>No. 2</issuenum>
<date>December, 1989</date>
</biblioset>
<biblioset>
<author>
<firstname>Charles</firstname>
<othername>E.</othername>
<surname>McDowell</surname>
</author>
<author>
<firstname>David</firstname>
<othername>P.</othername>
<surname>Helmbold</surname>
</author>
<title>
<ulink
url="http://www.acm.org/pubs/citations/journals/surveys/1989-21-4/p593-mcdowell/"
>Debugging Concurrent Programs</ulink>
</title>
</biblioset>
<para>Identifies many of the unique failure modes and debugging difficulties
associated with concurrent programs.</para>
</biblioentry>
<biblioentry id="threads.bib.SchmidtPyarali">
<abbrev id="threads.bib.SchmidtPyarali.abbrev">SchmidtPyarali</abbrev>
<title>
<ulink url="http://www.cs.wustl.edu/~schmidt/win32-cv-1.html8"
>Strategies for Implementing POSIX Condition Variables on Win32</ulink>
</title>
<authorgroup>
<author>
<firstname>Douglas</firstname>
<othername>C.</othername>
<surname>Schmidt</surname>
</author>
<author>
<firstname>Irfan</firstname>
<surname>Pyarali</surname>
</author>
</authorgroup>
<orgname>Department of Computer Science, Washington University, St. Louis,
Missouri</orgname>
<para>Rationale for understanding &Boost.Threads; condition
variables. Note that Alexander Terekhov found some bugs in the
implementation given in this article, so pthreads-win32 and &Boost.Threads;
are even more complicated yet.</para>
</biblioentry>
<biblioentry id="threads.bib.SchmidtStalRohnertBuschmann">
<abbrev
id="threads.bib.SchmidtStalRohnertBuschmann.abbrev">SchmidtStalRohnertBuschmann</abbrev>
<title>
<ulink
url="http://www.wiley.com/Corporate/Website/Objects/Products/0,9049,104671,00.html"
>Pattern-Oriented Architecture Volume 2</ulink>
</title>
<subtitle>Patterns for Concurrent and Networked Objects</subtitle>
<titleabbrev>POSA2</titleabbrev>
<authorgroup>
<author>
<firstname>Douglas</firstname>
<othername>C.</othername>
<surname>Schmidt</surname>
</author>
<author>
<firstname>Michael</firstname>
<lastname>Stal</lastname>
</author>
<author>
<firstname>Hans</firstname>
<surname>Rohnert</surname>
</author>
<author>
<firstname>Frank</firstname>
<surname>Buschmann</surname>
</author>
</authorgroup>
<publisher>Wiley</publisher>
<copyright><year>2000</year></copyright>
<para>This is a very good explanation of how to apply several patterns
useful for concurrent programming. Among the patterns documented is the
Monitor Pattern mentioned frequently in the &Boost.Threads;
documentation.</para>
</biblioentry>
<biblioentry id="threads.bib.Stroustrup">
<abbrev id="threads.bib.Stroustrup.abbrev">Stroustrup</abbrev>
<title>
<ulink url="http://cseng.aw.com/book/0,3828,0201700735,00.html"
>The C++ Programming Language</ulink>
</title>
<edition>Special Edition</edition>
<publisher>Addison-Wesley</publisher>
<copyright><year>2000</year></copyright>
<isbn>ISBN: 0-201-70073-5</isbn>
<para>The first book a C++ programmer should own. Note that the 3rd edition
(and subsequent editions like the Special Edition) has been rewritten to
cover the ISO standard language and library.</para>
</biblioentry>
</bibliography>

58
doc/build.xml Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="thread.build" last-revision="$Date$">
<title>Build</title>
<para>
How you build the &Boost.Threads; libraries, and how you build your own applications
that use those libraries, are some of the most frequently asked questions. Build
processes are difficult to deal with in a portable manner. That's one reason
why &Boost.Threads; makes use of &Boost.Build;.
In general you should refer to the documentation for &Boost.Build;.
This document will only supply you with some simple usage examples for how to
use <emphasis>bjam</emphasis> to build and test &Boost.Threads;. In addition, this document
will try to explain the build requirements so that users may create their own
build processes (for instance, create an IDE specific project), both for building
and testing &Boost.Threads;, as well as for building their own projects using
&Boost.Threads;.
</para>
<section id="thread.build.building">
<title>Building the &Boost.Threads; Libraries</title>
<para>
To build the &Boost.Threads; libraries using &Boost.Build;, simply change to the
directory <emphasis>boost_root</emphasis>/libs/thread/build and execute the command:
<programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis></programlisting>
This will create the debug and the release builds of the &Boost.Threads; library.
<note>Invoking the above command in <emphasis>boost_root</emphasis> will build all of
the Boost distribution, including &Boost.Threads;.</note>
</para>
<para>
The Jamfile supplied with &Boost.Threads; produces a dynamic link library named
<emphasis>boost_thread{build-specific-tags}.{extension}</emphasis>, where the build-specific
tags indicate the toolset used to build the library, whether it's a debug or release
build, what version of Boost was used, etc.; and the extension is the appropriate extension
for a dynamic link library for the platform for which &Boost.Threads; is being built.
For instance, a debug library built for Win32 with VC++ 7.1 using Boost 1.31 would
be named <emphasis>boost_thread-vc71-mt-gd-1_31.dll</emphasis>.
</para>
<para>
The source files that are used to create the &Boost.Threads; library
are all of the *.cpp files found in <emphasis>boost_root</emphasis>/libs/thread/src.
These need to be built with the compiler's and linker's multi-threading support enabled.
If you want to create your own build solution you'll have to follow these same
guidelines. One of the most frequently reported problems when trying to do this
occurs from not enabling the compiler's and linker's support for multi-threading.
</para>
</section>
<section id="thread.build.testing">
<title>Testing the &Boost.Threads; Libraries</title>
<para>
To test the &Boost.Threads; libraries using &Boost.Build;, simply change to the
directory <emphasis>boost_root</emphasis>/libs/thread/test and execute the command:
<programlisting>bjam -sTOOLS=<emphasis>toolset</emphasis> test</programlisting>
</para>
</section>
</section>

2229
doc/concepts.xml Normal file

File diff suppressed because it is too large Load Diff

188
doc/condition-ref.xml Normal file
View File

@@ -0,0 +1,188 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/condition.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="condition">
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<purpose>
<para>An object of class <classname>condition</classname> is a
synchronization primitive used to cause a thread to wait until a
particular shared-data condition (or time) is met.</para>
</purpose>
<description>
<para>A <classname>condition</classname> object is always used in
conjunction with a <link linkend="threads.concepts.mutexes">mutex</link>
object (an object whose type is a model of a <link
linkend="threads.concepts.Mutex">Mutex</link> or one of its
refinements). The mutex object must be locked prior to waiting on the
condition, which is verified by passing a lock object (an object whose
type is a model of <link linkend="threads.concepts.Lock">Lock</link> or
one of its refinements) to the <classname>condition</classname> object's
wait functions. Upon blocking on the <classname>condition</classname>
object, the thread unlocks the mutex object. When the thread returns
from a call to one of the <classname>condition</classname> object's wait
functions the mutex object is again locked. The tricky unlock/lock
sequence is performed automatically by the
<classname>condition</classname> object's wait functions.</para>
<para>The <classname>condition</classname> type is often used to
implement the Monitor Object and other important patterns (see
&cite.SchmidtStalRohnertBuschmann; and &cite.Hoare74;). Monitors are one
of the most important patterns for creating reliable multithreaded
programs.</para>
<para>See <xref linkend="threads.glossary"/> for definitions of <link
linkend="threads.glossary.thread-state">thread states</link>
blocked and ready. Note that "waiting" is a synonym for blocked.</para>
</description>
<constructor>
<effects><simpara>Constructs a <classname>condition</classname>
object.</simpara></effects>
</constructor>
<destructor>
<effects><simpara>Destroys <code>*this</code>.</simpara></effects>
</destructor>
<method-group name="notification">
<method name="notify_one">
<type>void</type>
<effects><simpara>If there is a thread waiting on <code>*this</code>,
change that thread's state to ready. Otherwise there is no
effect.</simpara></effects>
<notes><simpara>If more than one thread is waiting on <code>*this</code>,
it is unspecified which is made ready. After returning to a ready
state the notified thread must still acquire the mutex again (which
occurs within the call to one of the <classname>condition</classname>
object's wait functions.)</simpara></notes>
</method>
<method name="notify_all">
<type>void</type>
<effects><simpara>Change the state of all threads waiting on
<code>*this</code> to ready. If there are no waiting threads,
<code>notify_all()</code> has no effect.</simpara></effects>
</method>
</method-group>
<method-group name="waiting">
<method name="wait">
<template>
<template-type-parameter name="ScopedLock"/>
</template>
<type>void</type>
<parameter name="lock">
<paramtype>ScopedLock&amp;</paramtype>
</parameter>
<requires><simpara><code>ScopedLock</code> meets the <link
linkend="threads.concepts.ScopedLock">ScopedLock</link>
requirements.</simpara></requires>
<effects><simpara>Releases the lock on the <link
linkend="threads.concepts.mutexes">mutex object</link>
associated with <code>lock</code>, blocks the current thread of execution
until readied by a call to <code>this->notify_one()</code>
or<code> this->notify_all()</code>, and then reacquires the
lock.</simpara></effects>
<throws><simpara><classname>lock_error</classname> if
<code>!lock.locked()</code></simpara></throws>
</method>
<method name="wait">
<template>
<template-type-parameter name="ScopedLock"/>
<template-type-parameter name="Pred"/>
</template>
<type>void</type>
<parameter name="lock">
<paramtype>ScopedLock&amp;</paramtype>
</parameter>
<parameter name="pred">
<paramtype>Pred</paramtype>
</parameter>
<requires><simpara><code>ScopedLock</code> meets the <link
linkend="threads.concepts.ScopedLock">ScopedLock</link>
requirements and the return from <code>pred()</code> is
convertible to <code>bool</code>.</simpara></requires>
<effects><simpara>As if: <code>while (!pred())
wait(lock)</code></simpara></effects>
<throws><simpara><classname>lock_error</classname> if
<code>!lock.locked()</code></simpara></throws>
</method>
<method name="timed_wait">
<template>
<template-type-parameter name="ScopedLock"/>
</template>
<type>bool</type>
<parameter name="lock">
<paramtype>ScopedLock&amp;</paramtype>
</parameter>
<parameter name="xt">
<paramtype>const <classname>boost::xtime</classname>&amp;</paramtype>
</parameter>
<requires><simpara><code>ScopedLock</code> meets the <link
linkend="threads.concepts.ScopedLock">ScopedLock</link>
requirements.</simpara></requires>
<effects><simpara>Releases the lock on the <link
linkend="threads.concepts.mutexes">mutex object</link>
associated with <code>lock</code>, blocks the current thread of execution
until readied by a call to <code>this->notify_one()</code>
or<code> this->notify_all()</code>, or until time <code>xt</code>
is reached, and then reacquires the lock.</simpara></effects>
<returns><simpara><code>false</code> if time <code>xt</code> is reached,
otherwise <code>true</code>.</simpara></returns>
<throws><simpara><classname>lock_error</classname> if
<code>!lock.locked()</code></simpara></throws>
</method>
<method name="timed_wait">
<template>
<template-type-parameter name="ScopedLock"/>
<template-type-parameter name="Pred"/>
</template>
<type>bool</type>
<parameter name="lock">
<paramtype>ScopedLock&amp;</paramtype>
</parameter>
<parameter name="pred">
<paramtype>Pred</paramtype>
</parameter>
<requires><simpara><code>ScopedLock</code> meets the <link
linkend="threads.concepts.ScopedLock">ScopedLock</link>
requirements and the return from <code>pred()</code> is
convertible to <code>bool</code>.</simpara></requires>
<effects><simpara>As if: <code>while (!pred()) { if (!timed_wait(lock,
xt)) return false; } return true;</code></simpara></effects>
<returns><simpara><code>false</code> if <code>xt</code> is reached,
otherwise <code>true</code>.</simpara></returns>
<throws><simpara><classname>lock_error</classname> if
<code>!lock.locked()</code></simpara></throws>
</method>
</method-group>
</class>
</namespace>
</header>

92
doc/configuration.xml Normal file
View File

@@ -0,0 +1,92 @@
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="thread.configuration" last-revision="$Date$">
<title>Configuration</title>
<para>&Boost.Threads; uses several configuration macros in &lt;boost/config.hpp&gt;,
as well as configuration macros meant to be supplied by the application. These
macros are documented here.
</para>
<section id="thread.configuration.public">
<title>Library Defined Public Macros</title>
<para>
These macros are defined by &Boost.Threads; but are expected to be used
by application code.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Macro</entry>
<entry>Meaning</entry>
</row>
</thead>
<tbody>
<row>
<entry>BOOST_HAS_THREADS</entry>
<entry>
Indicates that threading support is available. This means both that there
is a platform specific implementation for &Boost.Threads; and that
threading support has been enabled in a platform specific manner. For instance,
on the Win32 platform there&#39;s an implementation for &Boost.Threads;
but unless the program is compiled against one of the multithreading runtimes
(often determined by the compiler predefining the macro _MT) the BOOST_HAS_THREADS
macro remains undefined.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section id="thread.configuration.implementation">
<title>Library Defined Implementation Macros</title>
<para>
These macros are defined by &Boost.Threads; and are implementation details
of interest only to implementors.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Macro</entry>
<entry>Meaning</entry>
</row>
</thead>
<tbody>
<row>
<entry>BOOST_HAS_WINTHREADS</entry>
<entry>
Indicates that the platform has the Microsoft Win32 threading libraries,
and that they should be used to implement &Boost.Threads;.
</entry>
</row>
<row>
<entry>BOOST_HAS_PTHREADS</entry>
<entry>
Indicates that the platform has the POSIX pthreads libraries, and that
they should be used to implement &Boost.Threads;.
</entry>
</row>
<row>
<entry>BOOST_HAS_FTIME</entry>
<entry>
Indicates that the implementation should use GetSystemTimeAsFileTime()
and the FILETIME type to calculate the current time. This is an implementation
detail used by boost::detail::getcurtime().
</entry>
</row>
<row>
<entry>BOOST_HAS_GETTTIMEOFDAY</entry>
<entry>
Indicates that the implementation should use gettimeofday() to calculate
the current time. This is an implementation detail used by boost::detail::getcurtime().
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
</section>

155
doc/design.xml Normal file
View File

@@ -0,0 +1,155 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="threads.design" last-revision="$Date$">
<title>Design</title>
<para>With client/server and three-tier architectures becoming common place
in today's world, it's becoming increasingly important for programs to be
able to handle parallel processing. Modern day operating systems usually
provide some support for this through native thread APIs. Unfortunately,
writing portable code that makes use of parallel processing in C++ is made
very difficult by a lack of a standard interface for these native APIs.
Further, these APIs are almost universally C APIs and fail to take
advantage of C++'s strengths, or to address concepts unique to C++, such as
exceptions.</para>
<para>The &Boost.Threads; library is an attempt to define a portable interface
for writing parallel processes in C++.</para>
<section id="threads.design.goals">
<title>Goals</title>
<para>The &Boost.Threads; library has several goals that should help to set
it apart from other solutions. These goals are listed in order of precedence
with full descriptions below.
<variablelist>
<varlistentry>
<term>Portability</term>
<listitem>
<para>&Boost.Threads; was designed to be highly portable. The goal is
for the interface to be easily implemented on any platform that
supports threads, and possibly even on platforms without native thread
support.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Safety</term>
<listitem>
<para>&Boost.Threads; was designed to be as safe as possible. Writing
<link linkend="threads.glossary.thread-safe">thread-safe</link>
code is very difficult and successful libraries must strive to
insulate the programmer from dangerous constructs as much as
possible. This is accomplished in several ways:
<itemizedlist>
<listitem>
<para>C++ language features are used to make correct usage easy
(if possible) and error-prone usage impossible or at least more
difficult. For example, see the <link
linkend="threads.concepts.Mutex">Mutex</link> and <link
linkend="threads.concepts.Lock">Lock</link> designs, and note
how they interact.</para>
</listitem>
<listitem>
<para>Certain traditional concurrent programming features are
considered so error-prone that they are not provided at all. For
example, see <xref linkend="threads.rationale.events" />.</para>
</listitem>
<listitem>
<para>Dangerous features, or features which may be misused, are
identified as such in the documentation to make users aware of
potential pitfalls.</para>
</listitem>
</itemizedlist></para>
</listitem>
</varlistentry>
<varlistentry>
<term>Flexibility</term>
<listitem>
<para>&Boost.Threads; was designed to be flexible. This goal is often
at odds with <emphasis>safety</emphasis>. When functionality might be
compromised by the desire to keep the interface safe, &Boost.Threads;
has been designed to provide the functionality, but to make it's use
prohibitive for general use. In other words, the interfaces have been
designed such that it's usually obvious when something is unsafe, and
the documentation is written to explain why.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Efficiency</term>
<listitem>
<para>&Boost.Threads; was designed to be as efficient as
possible. When building a library on top of another library there is
always a danger that the result will be so much slower than the
"native" API that programmers are inclined to ignore the higher level
API. &Boost.Threads; was designed to minimize the chances of this
occurring. The interfaces have been crafted to allow an implementation
the greatest chance of being as efficient as possible. This goal is
often at odds with the goal for <emphasis>safety</emphasis>. Every
effort was made to ensure efficient implementations, but when in
conflict <emphasis>safety</emphasis> has always taken
precedence.</para>
</listitem>
</varlistentry>
</variablelist></para>
</section>
<section>
<title>Iterative Phases</title>
<para>Another goal of &Boost.Threads; was to take a dynamic, iterative
approach in its development. The computing industry is still exploring the
concepts of parallel programming. Most thread libraries supply only simple
primitive concepts for thread synchronization. These concepts are very
simple, but it is very difficult to use them safely or to provide formal
proofs for constructs built on top of them. There has been a lot of research
into other concepts, such as in "Communicating Sequential Processes."
&Boost.Threads; was designed in iterative steps, with each step providing
the building blocks necessary for the next step and giving the researcher
the tools necessary to explore new concepts in a portable manner.</para>
<para>Given the goal of following a dynamic, iterative approach
&Boost.Threads; shall go through several growth cycles. Each phase in its
development shall be roughly documented here.</para>
</section>
<section>
<title>Phase 1, Synchronization Primitives</title>
<para>Boost is all about providing high quality libraries with
implementations for many platforms. Unfortunately, there's a big problem
faced by developers wishing to supply such high quality libraries, namely
thread-safety. The C++ standard doesn't address threads at all, but real
world programs often make use of native threading support. A portable
library that doesn't address the issue of thread-safety is therefore not
much help to a programmer who wants to use the library in his multithreaded
application. So there's a very great need for portable primitives that will
allow the library developer to create <link
linkend="threads.glossary.thread-safe">thread-safe</link>
implementations. This need far out weighs the need for portable methods to
create and manage threads.</para>
<para>Because of this need, the first phase of &Boost.Threads; focuses
solely on providing portable primitive concepts for thread
synchronization. Types provided in this phase include the
<classname>boost::mutex</classname>,
<classname>boost::try_mutex</classname>,
<classname>boost::timed_mutex</classname>,
<classname>boost::recursive_mutex</classname>,
<classname>boost::recursive_try_mutex</classname>,
<classname>boost::recursive_timed_mutex</classname>, and
<classname>boost::lock_error</classname>. These are considered the "core"
synchronization primitives, though there are others that will be added in
later phases.</para>
</section>
<section id="threads.design.phase2">
<title>Phase 2, Thread Management and Thread Specific Storage</title>
<para>This phase addresses the creation and management of threads and
provides a mechanism for thread specific storage (data associated with a
thread instance). Thread management is a tricky issue in C++, so this
phase addresses only the basic needs of multithreaded program. Later
phases are likely to add additional functionality in this area. This
phase of &Boost.Threads; adds the <classname>boost::thread</classname> and
<classname>boost::thread_specific_ptr</classname> types. With these
additions the &Boost.Threads; library can be considered minimal but
complete.</para>
</section>
<section>
<title>The Next Phase</title>
<para>The next phase will address more advanced synchronization concepts,
such as read/write mutexes and barriers.</para>
</section>
</section>

26
doc/entities.xml Normal file
View File

@@ -0,0 +1,26 @@
<!ENTITY Boost.Threads "<emphasis role='bold'>Boost.Threads</emphasis>">
<!ENTITY Boost.Build "<emphasis role='bold'>Boost.Build</emphasis>">
<!ENTITY cite.AndrewsSchneider83 "<citation><xref
linkend='threads.bib.AndrewsSchneider83'
endterm='threads.bib.AndrewsSchneider83.abbrev'/></citation>">
<!ENTITY cite.Boost "<citation><xref linkend='threads.bib.Boost'
endterm='threads.bib.Boost.abbrev'/></citation>">
<!ENTITY cite.Hansen73 "<citation><xref linkend='threads.bib.Hansen73'
endterm='threads.bib.Hansen73.abbrev'/></citation>">
<!ENTITY cite.Butenhof97 "<citation><xref linkend='threads.bib.Butenhof97'
endterm='threads.bib.Butenhof97.abbrev'/></citation>">
<!ENTITY cite.Hoare74 "<citation><xref linkend='threads.bib.Hoare74'
endterm='threads.bib.Hoare74.abbrev'/></citation>">
<!ENTITY cite.ISO98 "<citation><xref linkend='threads.bib.ISO98'
endterm='threads.bib.ISO98.abbrev'/></citation>">
<!ENTITY cite.McDowellHelmbold89 "<citation><xref
linkend='threads.bib.McDowellHelmbold89'
endterm='threads.bib.McDowellHelmbold89.abbrev'/></citation>">
<!ENTITY cite.SchmidtPyarali "<citation><xref
linkend='threads.bib.SchmidtPyarali'
endterm='threads.bib.SchmidtPyarali.abbrev'/></citation>">
<!ENTITY cite.SchmidtStalRohnertBuschmann "<citation><xref
linkend='threads.bib.SchmidtStalRohnertBuschmann'
endterm='threads.bib.SchmidtStalRohnertBuschmann.abbrev'/></citation>">
<!ENTITY cite.Stroustrup "<citation><xref linkend='threads.bib.Stroustrup'
endterm='threads.bib.Stroustrup.abbrev'/></citation>">

58
doc/exceptions-ref.xml Normal file
View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/exceptions.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="lock_error">
<purpose>
<simpara>The lock_error class defines an exception type thrown
to indicate a locking related error has been detected.</simpara>
</purpose>
<description>
<simpara>Examples of errors indicated by a lock_error exception
include a lock operation which can be determined to result in a
deadlock, or unlock operations attempted by a thread that does
not own the lock.</simpara>
</description>
<inherit access="public">
<type><classname>std::logical_error</classname></type>
</inherit>
<constructor>
<effects><simpara>Constructs a <code>lock_error</code> object.
</simpara></effects>
</constructor>
</class>
<class name="thread_resource_error">
<purpose>
<simpara>The <classname>thread_resource_error</classname> class
defines an exception type that is thrown by constructors in the
&Boost.Threads; library when thread-related resources can not be
acquired.</simpara>
</purpose>
<description>
<simpara><classname>thread_resource_error</classname> is used
only when thread-related resources cannot be acquired; memory
allocation failures are indicated by
<classname>std::bad_alloc</classname>.</simpara>
</description>
<inherit access="public">
<type><classname>std::runtime_error</classname></type>
</inherit>
<constructor>
<effects><simpara>Constructs a <code>thread_resource_error</code>
object.</simpara></effects>
</constructor>
</class>
</namespace>
</header>

210
doc/faq.xml Normal file
View File

@@ -0,0 +1,210 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="threads.faq" last-revision="$Date$">
<title>Frequently Asked Questions</title>
<qandaset>
<qandaentry>
<question>
<para>Are lock objects <link
linkend="threads.glossary.thread-safe">thread safe</link>?</para>
</question>
<answer>
<para><emphasis role="bold">No!</emphasis> Lock objects are not meant to
be shared between threads. They are meant to be short-lived objects
created on automatic storage within a code block. Any other usage is
just likely to lead to errors and won't really be of actual benefit anyway.
Share <link linkend="threads.concepts.mutexes">Mutexes</link>, not
Locks. For more information see the <link
linkend="threads.rationale.locks">rationale</link> behind the
design for lock objects.</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Why was &Boost.Threads; modeled after (specific library
name)?</para>
</question>
<answer>
<para>It wasn't. &Boost.Threads; was designed from scratch. Extensive
design discussions involved numerous people representing a wide range of
experience across many platforms. To ensure portability, the initial
implements were done in parallel using POSIX Threads and the Win32
threading API. But the &Boost.Threads; design is very much in the spirit
of C++, and thus doesn't model such C based APIs.</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Why wasn't &Boost.Threads; modeled after (specific library
name)?</para>
</question>
<answer>
<para>Existing C++ libraries either seemed dangerous (often failing to
take advantage of prior art to reduce errors) or had excessive
dependencies on library components unrelated to threading. Existing C
libraries couldn't meet our C++ requirements, and were also missing
certain features. For instance, the WIN32 thread API lacks condition
variables, even though these are critical for the important Monitor
pattern &cite.SchmidtStalRohnertBuschmann;.</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Why do <link linkend="threads.concepts.mutexes">Mutexes</link>
have noncopyable semantics?</para>
</question>
<answer>
<para>To ensure that <link
linkend="threads.glossary.deadlock">deadlocks</link> don't occur. The
only logical form of copy would be to use some sort of shallow copy
semantics in which multiple mutex objects could refer to the same mutex
state. This means that if ObjA has a mutex object as part of its state
and ObjB is copy constructed from it, then when ObjB::foo() locks the
mutex it has effectively locked ObjA as well. This behavior can result
in deadlock. Other copy semantics result in similar problems (if you
think you can prove this to be wrong then supply us with an alternative
and we'll reconsider).</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>How can you prevent <link
linkend="threads.glossary.deadlock">deadlock</link> from occurring when
a thread must lock multiple mutexes?</para>
</question>
<answer>
<para>Always lock them in the same order. One easy way of doing this is
to use each mutex's address to determine the order in which they are
locked. A future &Boost.Threads; concept may wrap this pattern up in a
reusable class.</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Don't noncopyable <link
linkend="threads.concepts.mutexes">Mutex</link> semantics mean that a
class with a mutex member will be noncopyable as well?</para>
</question>
<answer>
<para>No, but what it does mean is that the compiler can't generate a
copy constructor and assignment operator, so they will have to be coded
explicitly. This is a <emphasis role="bold">good thing</emphasis>,
however, since the compiler generated operations would not be <link
linkend="threads.glossary.thread-safe">thread-safe</link>. The following
is a simple example of a class with copyable semantics and internal
synchronization through a mutex member.</para>
<programlisting>
class counter
{
public:
// Doesn't need synchronization since there can be no references to *this
// until after it's constructed!
explicit counter(int initial_value)
: m_value(initial_value)
{
}
// We only need to synchronize other for the same reason we don't have to
// synchronize on construction!
counter(const counter&amp; other)
{
boost::mutex::scoped_lock scoped_lock(other.m_mutex);
m_value = other.m_value;
}
// For assignment we need to synchronize both objects!
const counter&amp; operator=(const counter&amp; other)
{
if (this == &amp;other)
return *this;
boost::mutex::scoped_lock lock1(&amp;m_mutex &lt; &amp;other.m_mutex ? m_mutex : other.m_mutex);
boost::mutex::scoped_lock lock2(&amp;m_mutex &gt; &amp;other.m_mutex ? m_mutex : other.m_mutex);
m_value = other.m_value;
return *this;
}
int value() const
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
return m_value;
}
int increment()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
return ++m_value;
}
private:
mutable boost::mutex m_mutex;
int m_value;
};
</programlisting>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>How can you lock a <link
linkend="threads.concepts.mutexes">Mutex</link> member in a const member
function, in order to implement the Monitor Pattern?</para>
</question>
<answer>
<para>The Monitor Pattern &cite.SchmidtStalRohnertBuschmann; mutex
should simply be declared as mutable. See the example code above. The
internal state of mutex types could have been made mutable, with all
lock calls made via const functions, but this does a poor job of
documenting the actual semantics (and in fact would be incorrect since
the logical state of a locked mutex clearly differs from the logical
state of an unlocked mutex). Declaring a mutex member as mutable clearly
documents the intended semantics.</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Why supply <classname>boost::condition</classname> variables rather than
event variables?</para>
</question>
<answer>
<para>Condition variables result in user code much less prone to <link
linkend="threads.glossary.race-condition">race conditions</link> than
event variables. See <xref linkend="threads.rationale.events" />
for analysis. Also see &cite.Hoare74; and &cite.SchmidtStalRohnertBuschmann;.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Why isn't thread cancellation or termination provided?</para>
</question>
<answer>
<para>There's a valid need for thread termination, so at some point
&Boost.Threads; probably will include it, but only after we can find a
truly safe (and portable) mechanism for this concept.</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Is it safe for threads to share automatic storage duration (stack)
objects via pointers or references?</para>
</question>
<answer>
<para>Only if you can guarantee that the lifetime of the stack object
will not end while other threads might still access the object. Thus the
safest practice is to avoid sharing stack objects, particularly in
designs where threads are created and destroyed dynamically. Restrict
sharing of stack objects to simple designs with very clear and
unchanging function and thread lifetimes. (Suggested by Darryl
Green).</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>Why has class semaphore disappeared?</para>
</question>
<answer>
<para>Semaphore was removed as too error prone. The same effect can be
achieved with greater safety by the combination of a mutex and a
condition variable.</para>
</answer>
</qandaentry>
</qandaset>
</section>

300
doc/glossary.xml Normal file
View File

@@ -0,0 +1,300 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<glossary id="threads.glossary" last-revision="$Date$">
<title>Glossary</title>
<para>Definitions are given in terms of the C++ Standard
&cite.ISO98;. References to the standard are in the form [1.2.3/4], which
represents the section number, with the paragraph number following the
"/".</para>
<para>Because the definitions are written in something akin to "standardese",
they can be difficult to understand. The intent isn't to confuse, but rather
to clarify the additional requirements &Boost.Threads; places on a C++
implementation as defined by the C++ Standard.</para>
<glossentry id="threads.glossary.thread">
<glossterm>Thread</glossterm>
<glossdef>
<para>Thread is short for "thread of execution". A thread of execution is
an execution environment [1.9/7] within the execution environment of a C++
program [1.9]. The main() function [3.6.1] of the program is the initial
function of the initial thread. A program in a multithreading environment
always has an initial thread even if the program explicitly creates no
additional threads.</para>
<para>Unless otherwise specified, each thread shares all aspects of its
execution environment with other threads in the program. Shared aspects of
the execution environment include, but are not limited to, the
following:</para>
<itemizedlist>
<listitem><para>Static storage duration (static, extern) objects
[3.7.1].</para></listitem>
<listitem><para>Dynamic storage duration (heap) objects [3.7.3]. Thus
each memory allocation will return a unique addresses, regardless of the
thread making the allocation request.</para></listitem>
<listitem><para>Automatic storage duration (stack) objects [3.7.2]
accessed via pointer or reference from another thread.</para></listitem>
<listitem><para>Resources provided by the operating system. For example,
files.</para></listitem>
<listitem><para>The program itself. In other words, each thread is
executing some function of the same program, not a totally different
program.</para></listitem>
</itemizedlist>
<para>Each thread has its own:</para>
<itemizedlist>
<listitem><para>Registers and current execution sequence (program
counter) [1.9/5].</para></listitem>
<listitem><para>Automatic storage duration (stack) objects
[3.7.2].</para></listitem>
</itemizedlist>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.thread-safe">
<glossterm>Thread-safe</glossterm>
<glossdef>
<para>A program is thread-safe if it has no <link
linkend="threads.glossary.race-condition">race conditions</link>, does
not <link linkend="threads.glossary.deadlock">deadlock</link>, and has
no <link linkend="threads.glossary.priority-failure">priority
failures</link>.</para>
<para>Note that thread-safety does not necessarily imply efficiency, and
than while some thread-safety violations can be determined statically at
compile time, many thread-safety errors can only only be detected at
runtime.</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.thread-state">
<glossterm>Thread State</glossterm>
<glossdef>
<para>During the lifetime of a thread, it shall be in one of the following
states:</para>
<table>
<title>Thread States</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>State</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>Ready</entry>
<entry>Ready to run, but waiting for a processor.</entry>
</row>
<row>
<entry>Running</entry>
<entry>Currently executing on a processor. Zero or more threads
may be running at any time, with a maximum equal to the number of
processors.</entry>
</row>
<row>
<entry>Blocked</entry>
<entry>Waiting for some resource other than a processor which is
not currently available, or for the completion of calls to library
functions [1.9/6]. The term "waiting" is synonymous with
"blocked"</entry>
</row>
<row>
<entry>Terminated</entry>
<entry>Finished execution but not yet detached or joined.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>Thread state transitions shall occur only as specified:</para>
<table>
<title>Thread States Transitions</title>
<tgroup cols="3" align="left">
<thead>
<row>
<entry>From</entry>
<entry>To</entry>
<entry>Cause</entry>
</row>
</thead>
<tbody>
<row>
<entry>[none]</entry>
<entry>Ready</entry>
<entry><para>Thread is created by a call to a library function.
In the case of the initial thread, creation is implicit and
occurs during the startup of the main() function [3.6.1].</para></entry>
</row>
<row>
<entry>Ready</entry>
<entry>Running</entry>
<entry><para>Processor becomes available.</para></entry>
</row>
<row>
<entry>Running</entry>
<entry>Ready</entry>
<entry>Thread preempted.</entry>
</row>
<row>
<entry>Running</entry>
<entry>Blocked</entry>
<entry>Thread calls a library function which waits for a resource or
for the completion of I/O.</entry>
</row>
<row>
<entry>Running</entry>
<entry>Terminated</entry>
<entry>Thread returns from its initial function, calls a thread
termination library function, or is canceled by some other thread
calling a thread termination library function.</entry>
</row>
<row>
<entry>Blocked</entry>
<entry>Ready</entry>
<entry>The resource being waited for becomes available, or the
blocking library function completes.</entry>
</row>
<row>
<entry>Terminated</entry>
<entry>[none]</entry>
<entry>Thread is detached or joined by some other thread calling the
appropriate library function, or by program termination
[3.6.3].</entry>
</row>
</tbody>
</tgroup>
</table>
<para>[Note: if a suspend() function is added to the threading library,
additional transitions to the blocked state will have to be added to the
above table.]</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.race-condition">
<glossterm>Race Condition</glossterm>
<glossdef>
<para>A race condition is what occurs when multiple threads read from and write
to the same memory without proper synchronization, resulting in an incorrect
value being read or written. The result of a race condition may be a bit
pattern which isn't even a valid value for the data type. A race condition
results in undefined behavior [1.3.12].</para>
<para>Race conditions can be prevented by serializing memory access using
the tools provided by &Boost.Threads;.</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.deadlock">
<glossterm>Deadlock</glossterm>
<glossdef>
<para>Deadlock is an execution state where for some set of threads, each
thread in the set is blocked waiting for some action by one of the other
threads in the set. Since each is waiting on the others, none will ever
become ready again.</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.starvation">
<glossterm>Starvation</glossterm>
<glossdef>
<para>The condition in which a thread is not making sufficient progress in
its work during a given time interval.</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.priority-failure">
<glossterm>Priority Failure</glossterm>
<glossdef>
<para>A priority failure (such as priority inversion or infinite overtaking)
occurs when threads are executed in such a sequence that required work is not
performed in time to be useful.</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.undefined-behavior">
<glossterm>Undefined Behavior</glossterm>
<glossdef>
<para>The result of certain operations in &Boost.Threads; is undefined;
this means that those operations can invoke almost any behavior when
they are executed.</para>
<para>An operation whose behavior is undefined can work "correctly"
in some implementations (i.e., do what the programmer thought it
would do), while in other implementations it may exhibit almost
any "incorrect" behavior--such as returning an invalid value,
throwing an exception, generating an access violation, or terminating
the process.</para>
<para>Executing a statement whose behavior is undefined is a
programming error.</para>
</glossdef>
</glossentry>
<glossentry id="threads.glossary.memory-visibility">
<glossterm>Memory Visibility</glossterm>
<glossdef>
<para>An address [1.7] shall always point to the same memory byte,
regardless of the thread or processor dereferencing the address.</para>
<para>An object [1.8, 1.9] is accessible from multiple threads if it is of
static storage duration (static, extern) [3.7.1], or if a pointer or
reference to it is explicitly or implicitly dereferenced in multiple
threads.</para>
<para>For an object accessible from multiple threads, the value of the
object accessed from one thread may be indeterminate or different from the
value accessed from another thread, except under the conditions specified in
the following table. For the same row of the table, the value of an object
accessible at the indicated sequence point in thread A will be determinate
and the same if accessed at or after the indicated sequence point in thread
B, provided the object is not otherwise modified. In the table, the
"sequence point at a call" is the sequence point after the evaluation of all
function arguments [1.9/17], while the "sequence point after a call" is the
sequence point after the copying of the returned value... [1.9/17].</para>
<table>
<title>Memory Visibility</title>
<tgroup cols="2">
<thead>
<row>
<entry>Thread A</entry>
<entry>Thread B</entry>
</row>
</thead>
<tbody>
<row>
<entry>The sequence point at a call to a library thread-creation
function.</entry>
<entry>The first sequence point of the initial function in the new
thread created by the Thread A call.</entry>
</row>
<row>
<entry>The sequence point at a call to a library function which
locks a mutex, directly or by waiting for a condition
variable.</entry>
<entry>The sequence point after a call to a library function which
unlocks the same mutex.</entry>
</row>
<row>
<entry>The last sequence point before thread termination.</entry>
<entry>The sequence point after a call to a library function which
joins the terminated thread.</entry>
</row>
<row>
<entry>The sequence point at a call to a library function which
signals or broadcasts a condition variable.</entry>
<entry>The sequence point after the call to the library function
which was waiting on that same condition variable or signal.</entry>
</row>
</tbody>
</tgroup>
</table>
<para>The architecture of the execution environment and the observable
behavior of the abstract machine [1.9] shall be the same on all
processors.</para>
<para>The latitude granted by the C++ standard for an implementation to
alter the definition of observable behavior of the abstract machine to
include additional library I/O functions [1.9/6] is extended to include
threading library functions.</para>
<para>When an exception is thrown and there is no matching exception handler
in the same thread, behavior is undefined. The preferred behavior is the
same as when there is no matching exception handler in a program
[15.3/9]. That is, terminate() is called, and it is implementation-defined
whether or not the stack is unwound.</para>
</glossdef>
</glossentry>
<section>
<title>Acknowledgements</title>
<para>This document was originally written by Beman Dawes, and then much
improved by the incorporation of comments from William Kempf, who now
maintains the contents.</para>
<para>The visibility rules are based on &cite.Butenhof97;.</para>
</section>
</glossary>

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="threads.implementation_notes" last-revision="$Date$">
<title>Implementation Notes</title>
<section id="threads.implementation_notes.win32">
<title>Win32</title>
<para>
In the current Win32 implementation, creating a boost::thread object
during dll initialization will result in deadlock because the thread
class constructor causes the current thread to wait on the thread that
is being created until it signals that it has finished its initialization,
and, as stated in the
<ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/dllmain.asp">MSDN Library, "DllMain" article, "Remarks" section</ulink>,
"Because DLL notifications are serialized, entry-point functions should not
attempt to communicate with other threads or processes. Deadlocks may occur as a result."
(Also see <ulink url="http://www.microsoft.com/msj/archive/S220.aspx">"Under the Hood", January 1996</ulink>
for a more detailed discussion of this issue).
</para>
<para>
The following non-exhaustive list details some of the situations that
should be avoided until this issue can be addressed:
<itemizedlist>
<listitem>Creating a boost::thread object in DllMain() or in any function called by it.</listitem>
<listitem>Creating a boost::thread object in the constructor of a global static object or in any function called by one.</listitem>
<listitem>Creating a boost::thread object in MFC's CWinApp::InitInstance() function or in any function called by it.</listitem>
<listitem>Creating a boost::thread object in the function pointed to by MFC's _pRawDllMain function pointer or in any function called by it.</listitem>
</itemizedlist>
</para>
</section>
</section>

308
doc/mutex-ref.xml Normal file
View File

@@ -0,0 +1,308 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/mutex.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="mutex">
<purpose>
<para>The <classname>mutex</classname> class is a model of the
<link linkend="threads.concepts.Mutex">Mutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>mutex</classname> class is a model of the
<link linkend="threads.concepts.Mutex">Mutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>try_mutex</classname> and <classname>timed_mutex</classname>.</para>
<para>For <link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking mechanics, see <classname>recursive_mutex</classname>,
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
</para>
<para>The <classname>mutex</classname> class supplies the following typedef,
which <link linkend="threads.concepts.lock-models">models</link>
the specified locking strategy:
<informaltable>
<title>Supported Lock Types</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>The <classname>mutex</classname> class uses an
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking strategy, so attempts to recursively lock a <classname>mutex</classname>
object or attempts to unlock one by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.
This strategy allows implementations to be as efficient as possible
on any given platform. It is, however, recommended that
implementations include debugging support to detect misuse when
<code>NDEBUG</code> is not defined.</para>
<para>Like all
<link linkend="threads.concepts.mutex-models">mutex models</link>
in &Boost.Threads;, <classname>mutex</classname> leaves the
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
Programmers should make no assumptions about the order in which
waiting threads acquire a lock.</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<effects>Constructs a <classname>mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
<class name="try_mutex">
<purpose>
<para>The <classname>try_mutex</classname> class is a model of the
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>try_mutex</classname> class is a model of the
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>mutex</classname> and <classname>timed_mutex</classname>.</para>
<para>For <link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking mechanics, see <classname>recursive_mutex</classname>,
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
</para>
<para>The <classname>try_mutex</classname> class supplies the following typedefs,
which <link linkend="threads.concepts.lock-models">model</link>
the specified locking strategies:
<informaltable>
<title>Supported Lock Types</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>The <classname>try_mutex</classname> class uses an
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking strategy, so attempts to recursively lock a <classname>try_mutex</classname>
object or attempts to unlock one by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.
This strategy allows implementations to be as efficient as possible
on any given platform. It is, however, recommended that
implementations include debugging support to detect misuse when
<code>NDEBUG</code> is not defined.</para>
<para>Like all
<link linkend="threads.concepts.mutex-models">mutex models</link>
in &Boost.Threads;, <classname>try_mutex</classname> leaves the
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
Programmers should make no assumptions about the order in which
waiting threads acquire a lock.</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<effects>Constructs a <classname>try_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>try_mutex</classname> object.
</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
<class name="timed_mutex">
<purpose>
<para>The <classname>timed_mutex</classname> class is a model of the
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>timed_mutex</classname> class is a model of the
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>mutex</classname> and <classname>try_mutex</classname>.</para>
<para>For <link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking mechanics, see <classname>recursive_mutex</classname>,
<classname>recursive_try_mutex</classname>, and <classname>recursive_timed_mutex</classname>.
</para>
<para>The <classname>timed_mutex</classname> class supplies the following typedefs,
which <link linkend="threads.concepts.lock-models">model</link>
the specified locking strategies:
<informaltable>
<title>Supported Lock Types</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
<row>
<entry>scoped_timed_lock</entry>
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>The <classname>timed_mutex</classname> class uses an
<link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking strategy, so attempts to recursively lock a <classname>timed_mutex</classname>
object or attempts to unlock one by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.
This strategy allows implementations to be as efficient as possible
on any given platform. It is, however, recommended that
implementations include debugging support to detect misuse when
<code>NDEBUG</code> is not defined.</para>
<para>Like all
<link linkend="threads.concepts.mutex-models">mutex models</link>
in &Boost.Threads;, <classname>timed_mutex</classname> leaves the
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
Programmers should make no assumptions about the order in which
waiting threads acquire a lock.</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_timed_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<effects>Constructs a <classname>timed_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>timed_mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
</namespace>
</header>

86
doc/once-ref.xml Normal file
View File

@@ -0,0 +1,86 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/once.hpp"
last-revision="$Date$">
<macro name="BOOST_ONCE_INIT">
<purpose>The <functionname>call_once</functionname> function and
<code>once_flag</code> type (statically initialized to
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
routine exactly once. This can be used to initialize data in a
<link linkend="threads.glossary.thread-safe">thread-safe</link>
manner.</purpose>
<description>The implementation-defined macro
<macroname>BOOST_ONCE_INIT</macroname> is a constant value used to
initialize <code>once_flag</code> instances to indicate that the
logically associated routine has not been run yet. See
<functionname>call_once</functionname> for more details.</description>
</macro>
<namespace name="boost">
<typedef name="once_flag">
<purpose>The <functionname>call_once</functionname> function and
<code>once_flag</code> type (statically initialized to
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
routine exactly once. This can be used to initialize data in a
<link linkend="threads.glossary.thread-safe">thread-safe</link>
manner.</purpose>
<description>The implementation-defined type <code>once_flag</code>
is used as a flag to insure a routine is called only once.
Instances of this type should be statically initialized to
<macroname>BOOST_ONCE_INIT</macroname>. See
<functionname>call_once</functionname> for more details.
</description>
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<function name="call_once">
<purpose>The <functionname>call_once</functionname> function and
<code>once_flag</code> type (statically initialized to
<macroname>BOOST_ONCE_INIT</macroname>) can be used to run a
routine exactly once. This can be used to initialize data in a
<link linkend="threads.glossary.thread-safe">thread-safe</link>
manner.</purpose>
<description>
<para>Example usage is as follows:</para>
<para>
<programlisting>//Example usage:
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
//...
}
void thread_proc()
{
boost::call_once(&amp;init, once);
}</programlisting>
</para></description>
<parameter name="func">
<paramtype>void (*func)()</paramtype>
</parameter>
<parameter name="flag">
<paramtype>once_flag&amp;</paramtype>
</parameter>
<requires>The function <code>func</code> shall not throw
exceptions.</requires>
<effects>As if (in an atomic fashion):
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
<postconditions><code>flag != BOOST_ONCE_INIT</code>
</postconditions>
</function>
</namespace>
</header>

202
doc/overview.xml Normal file
View File

@@ -0,0 +1,202 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="threads.overview" last-revision="$Date$">
<title>Overview</title>
<section id="threads.introduction">
<title>Introduction</title>
<para>&Boost.Threads; allows C++ programs to execute as multiple,
asynchronous, independent threads-of-execution. Each thread has its own
machine state including program instruction counter and registers. Programs
which execute as multiple threads are called multithreaded programs to
distinguish them from traditional single-threaded programs. The <link
linkend="threads.glossary">glossary</link> gives a more complete description
of the multithreading execution environment.</para>
<para>Multithreading provides several advantages:
<itemizedlist>
<listitem>
<para>Programs which would otherwise block waiting for some external
event can continue to respond if the blocking operation is placed in a
separate thread. Multithreading is usually an absolute requirement for
these programs.</para>
</listitem>
<listitem>
<para>Well-designed multithreaded programs may execute faster than
single-threaded programs, particularly on multiprocessor hardware.
Note, however, that poorly-designed multithreaded programs are often
slower than single-threaded programs.</para>
</listitem>
<listitem>
<para>Some program designs may be easier to formulate using a
multithreaded approach. After all, the real world is
asynchronous!</para>
</listitem>
</itemizedlist></para>
</section>
<section>
<title>Dangers</title>
<section>
<title>General considerations</title>
<para>Beyond the errors which can occur in single-threaded programs,
multithreaded programs are subject to additional errors:
<itemizedlist>
<listitem>
<para><link linkend="threads.glossary.race-condition">Race
conditions</link></para>
</listitem>
<listitem>
<para><link linkend="threads.glossary.deadlock">Deadlock</link>
(sometimes called "deadly embrace")</para>
</listitem>
<listitem>
<para><link linkend="threads.glossary.priority-failure">Priority
failures</link> (priority inversion, infinite overtaking, starvation,
etc.)</para>
</listitem>
</itemizedlist></para>
<para>Every multithreaded program must be designed carefully to avoid these
errors. These aren't rare or exotic failures - they are virtually guaranteed
to occur unless multithreaded code is designed to avoid them. Priority
failures are somewhat less common, but are nonetheless serious.</para>
<para>The <link linkend="threads.design">&Boost.Threads; design</link>
attempts to minimize these errors, but they will still occur unless the
programmer proactively designs to avoid them.</para>
<note>Please also see <xref linkend="threads.implementation_notes"/>
for additional, implementation-specific considerations.</note>
</section>
<section>
<title>Testing and debugging considerations</title>
<para>Multithreaded programs are non-deterministic. In other words, the
same program with the same input data may follow different execution
paths each time it is invoked. That can make testing and debugging a
nightmare:
<itemizedlist>
<listitem>
<para>Failures are often not repeatable.</para>
</listitem>
<listitem>
<para>Probe effect causes debuggers to produce very different results
from non-debug uses.</para>
</listitem>
<listitem>
<para>Debuggers require special support to show thread state.</para>
</listitem>
<listitem>
<para>Tests on a single processor system may give no indication of
serious errors which would appear on multiprocessor systems, and visa
versa. Thus test cases should include a varying number of
processors.</para>
</listitem>
<listitem>
<para>For programs which create a varying number of threads according
to workload, tests which don't span the full range of possibilities
may miss serious errors.</para>
</listitem>
</itemizedlist></para>
</section>
<section>
<title>Getting a head start</title>
<para>Although it might appear that multithreaded programs are inherently
unreliable, many reliable multithreaded programs do exist. Multithreading
techniques are known which lead to reliable programs.</para>
<para>Design patterns for reliable multithreaded programs, including the
important <emphasis>monitor</emphasis> pattern, are presented in
<emphasis>Pattern-Oriented Software Architecture Volume 2 - Patterns for
Concurrent and Networked Objects</emphasis>
&cite.SchmidtStalRohnertBuschmann;. Many important multithreading programming
considerations (independent of threading library) are discussed in
<emphasis>Programming with POSIX Threads</emphasis> &cite.Butenhof97;.</para>
<para>Doing some reading before attempting multithreaded designs will
give you a head start toward reliable multithreaded programs.</para>
</section>
</section>
<section>
<title>C++ Standard Library usage in multithreaded programs</title>
<section>
<title>Runtime libraries</title>
<para>
<emphasis role="bold">Warning:</emphasis> Multithreaded programs such as
those using &Boost.Threads; must link to <link
linkend="threads.glossary.thread-safe">thread-safe</link> versions of
all runtime libraries used by the program, including the runtime library
for the C++ Standard Library. Failure to do so will cause <link
linkend="threads.glossary.race-condition">race conditions</link> to occur
when multiple threads simultaneously execute runtime library functions for
<code>new</code>, <code>delete</code>, or other language features which
imply shared state.</para>
</section>
<section>
<title>Potentially non-thread-safe functions</title>
<para>Certain C++ Standard Library functions inherited from C are
particular problems because they hold internal state between
calls:
<itemizedlist>
<listitem>
<para><code>rand</code></para>
</listitem>
<listitem>
<para><code>strtok</code></para>
</listitem>
<listitem>
<para><code>asctime</code></para>
</listitem>
<listitem>
<para><code>ctime</code></para>
</listitem>
<listitem>
<para><code>gmtime</code></para>
</listitem>
<listitem>
<para><code>localtime</code></para>
</listitem>
</itemizedlist></para>
<para>It is possible to write thread-safe implementations of these by
using thread specific storage (see
<classname>boost::thread_specific_ptr</classname>), and several C++
compiler vendors do just that. The technique is well-know and is explained
in &cite.Butenhof97;.</para>
<para>But at least one vendor (HP-UX) does not provide thread-safe
implementations of the above functions in their otherwise thread-safe
runtime library. Instead they provide replacement functions with
different names and arguments.</para>
<para><emphasis role="bold">Recommendation:</emphasis> For the most
portable, yet thread-safe code, use Boost replacements for the problem
functions. See the <libraryname>Boost Random Number Library</libraryname>
and <libraryname>Boost Tokenizer Library</libraryname>.</para>
</section>
</section>
<section>
<title>Common guarantees for all &Boost.Threads; components</title>
<section>
<title>Exceptions</title>
<para>&Boost.Threads; destructors never
throw exceptions. Unless otherwise specified, other
&Boost.Threads; functions that do not have
an exception-specification may throw implementation-defined
exceptions.</para>
<para>In particular, &Boost.Threads;
reports failure to allocate storage by throwing an exception of type
<code>std::bad_alloc</code> or a class derived from
<code>std::bad_alloc</code>, failure to obtain thread resources other than
memory by throwing an exception of type
<classname>boost::thread_resource_error</classname>, and certain lock
related failures by throwing an exception of type
<classname>boost::lock_error</classname>.</para>
<para><emphasis role="bold">Rationale:</emphasis> Follows the C++ Standard
Library practice of allowing all functions except destructors or other
specified functions to throw exceptions on errors.</para>
</section>
<section>
<title>NonCopyable requirement</title>
<para>&Boost.Threads; classes documented as
meeting the NonCopyable requirement disallow copy construction and copy
assignment. For the sake of exposition, the synopsis of such classes show
private derivation from <classname>boost::noncopyable</classname>. Users
should not depend on this derivation, however, as implementations are free
to meet the NonCopyable requirement in other ways.</para>
</section>
</section>
</section>

434
doc/rationale.xml Normal file
View File

@@ -0,0 +1,434 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="threads.rationale" last-revision="$Date$">
<title>Rationale</title>
<para>This page explains the rationale behind various design decisions in the
&Boost.Threads; library. Having the rationale documented here should explain
how we arrived at the current design as well as prevent future rehashing of
discussions and thought processes that have already occurred. It can also give
users a lot of insight into the design process required for this
library.</para>
<section id="threads.rationale.Boost.Threads">
<title>Rationale for the Creation of &Boost.Threads;</title>
<para>Processes often have a degree of "potential parallelism" and it can
often be more intuitive to design systems with this in mind. Further, these
parallel processes can result in more responsive programs. The benefits for
multithreaded programming are quite well known to most modern programmers,
yet the C++ language doesn't directly support this concept.</para>
<para>Many platforms support multithreaded programming despite the fact that
the language doesn't support it. They do this through external libraries,
which are, unfortunately, platform specific. POSIX has tried to address this
problem through the standardization of a "pthread" library. However, this is
a standard only on POSIX platforms, so its portability is limited.</para>
<para>Another problem with POSIX and other platform specific thread
libraries is that they are almost universally C based libraries. This leaves
several C++ specific issues unresolved, such as what happens when an
exception is thrown in a thread. Further, there are some C++ concepts, such
as destructors, that can make usage much easier than what's available in a C
library.</para>
<para>What's truly needed is C++ language support for threads. However, the
C++ standards committee needs existing practice or a good proposal as a
starting point for adding this to the standard.</para>
<para>The &Boost.Threads; library was developed to provide a C++ developer
with a portable interface for writing multithreaded programs on numerous
platforms. There's a hope that the library can be the basis for a more
detailed proposal for the C++ standards committee to consider for inclusion
in the next C++ standard.</para>
</section>
<section id="threads.rationale.primitives">
<title>Rationale for the Low Level Primitives Supported in &Boost.Threads;</title>
<para>The &Boost.Threads; library supplies a set of low level primitives for
writing multithreaded programs, such as mutexes and condition variables. In
fact, the first release of &Boost.Threads; supports only these low level
primitives. However, computer science research has shown that use of these
primitives is difficult since it's difficult to mathematically prove that a
usage pattern is correct, meaning it doesn't result in race conditions or
deadlocks. There are several algebras (such as CSP, CCS and Join calculus)
that have been developed to help write provably correct parallel
processes. In order to prove the correctness these processes must be coded
using higher level abstractions. So why does &Boost.Threads; support the
lower level concepts?</para>
<para>The reason is simple: the higher level concepts need to be implemented
using at least some of the lower level concepts. So having portable lower
level concepts makes it easier to develop the higher level concepts and will
allow researchers to experiment with various techniques.</para>
<para>Beyond this theoretical application of higher level concepts, however,
the fact remains that many multithreaded programs are written using only the
lower level concepts, so they are useful in and of themselves, even if it's
hard to prove that their usage is correct. Since many users will be familiar
with these lower level concepts but unfamiliar with any of the higher
level concepts, supporting the lower level concepts provides
greater accessibility.</para>
</section>
<section id="threads.rationale.locks">
<title>Rationale for the Lock Design</title>
<para>Programmers who are used to multithreaded programming issues will
quickly note that the &Boost.Threads; design for mutex lock concepts is not
<link linkend="threads.glossary.thread-safe">thread-safe</link> (this is
clearly documented as well). At first this may seem like a serious design
flaw. Why have a multithreading primitive that's not thread-safe
itself?</para>
<para>A lock object is not a synchronization primitive. A lock object's sole
responsibility is to ensure that a mutex is both locked and unlocked in a
manner that won't result in the common error of locking a mutex and then
forgetting to unlock it. This means that instances of a lock object are only
going to be created, at least in theory, within block scope and won't be
shared between threads. Only the mutex objects will be created outside of
block scope and/or shared between threads. Though it's possible to create a
lock object outside of block scope and to share it between threads, to do so
would not be a typical usage (in fact, to do so would likely be an
error). Nor are there any cases when such usage would be required.</para>
<para>Lock objects must maintain some state information. In order to allow a
program to determine if a try_lock or timed_lock was successful the lock
object must retain state indicating the success or failure of the call made
in its constructor. If a lock object were to have such state and remain
thread-safe it would need to synchronize access to the state information
which would result in roughly doubling the time of most operations. Worse,
since checking the state can occur only by a call after construction, we'd
have a race condition if the lock object were shared between threads.</para>
<para>So, to avoid the overhead of synchronizing access to the state
information and to avoid the race condition, the &Boost.Threads; library
simply does nothing to make lock objects thread-safe. Instead, sharing a
lock object between threads results in undefined behavior. Since the only
proper usage of lock objects is within block scope this isn't a problem, and
so long as the lock object is properly used there's no danger of any
multithreading issues.</para>
</section>
<section id="threads.rationale.non-copyable">
<title>Rationale for NonCopyable Thread Type</title>
<para>Programmers who are used to C libraries for multithreaded programming
are likely to wonder why &Boost.Threads; uses a noncopyable design for
<classname>boost::thread</classname>. After all, the C thread types are
copyable, and you often have a need for copying them within user
code. However, careful comparison of C designs to C++ designs shows a flaw
in this logic.</para>
<para>All C types are copyable. It is, in fact, not possible to make a
noncopyable type in C. For this reason types that represent system resources
in C are often designed to behave very similarly to a pointer to dynamic
memory. There's an API for acquiring the resource and an API for releasing
the resource. For memory we have pointers as the type and alloc/free for
the acquisition and release APIs. For files we have FILE* as the type and
fopen/fclose for the acquisition and release APIs. You can freely copy
instances of the types but must manually manage the lifetime of the actual
resource through the acquisition and release APIs.</para>
<para>C++ designs recognize that the acquisition and release APIs are error
prone and try to eliminate possible errors by acquiring the resource in the
constructor and releasing it in the destructor. The best example of such a
design is the std::iostream set of classes which can represent the same
resource as the FILE* type in C. A file is opened in the std::fstream's
constructor and closed in its destructor. However, if an iostream were
copyable it could lead to a file being closed twice, an obvious error, so
the std::iostream types are noncopyable by design. This is the same design
used by boost::thread, which is a simple and easy to understand design
that's consistent with other C++ standard types.</para>
<para>During the design of boost::thread it was pointed out that it would be
possible to allow it to be a copyable type if some form of "reference
management" were used, such as ref-counting or ref-lists, and many argued
for a boost::thread_ref design instead. The reasoning was that copying
"thread" objects was a typical need in the C libraries, and so presumably
would be in the C++ libraries as well. It was also thought that
implementations could provide more efficient reference management than
wrappers (such as boost::shared_ptr) around a noncopyable thread
concept. Analysis of whether or not these arguments would hold true doesn't
appear to bear them out. To illustrate the analysis we'll first provide
pseudo-code illustrating the six typical usage patterns of a thread
object.</para>
<section id="threads.rationale.non-copyable.simple">
<title>1. Use case: Simple creation of a thread.</title>
<programlisting>
void foo()
{
create_thread(&amp;bar);
}
</programlisting>
</section>
<section id="threads.rationale.non-copyable.joined">
<title>2. Use case: Creation of a thread that's later joined.</title>
<programlisting>
void foo()
{
thread = create_thread(&amp;bar);
join(thread);
}
</programlisting>
</section>
<section id="threads.rationale.non-copyable.loop">
<title>3. Use case: Simple creation of several threads in a loop.</title>
<programlisting>
void foo()
{
for (int i=0; i&lt;NUM_THREADS; ++i)
create_thread(&amp;bar);
}
</programlisting>
</section>
<section id="threads.rationale.non-copyable.loop-join">
<title>4. Use case: Creation of several threads in a loop which are later joined.</title>
<programlisting>
void foo()
{
for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = create_thread(&amp;bar);
for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i].join();
}
</programlisting>
</section>
<section id="threads.rationale.non-copyable.pass">
<title>5. Use case: Creation of a thread whose ownership is passed to another object/method.</title>
<programlisting>
void foo()
{
thread = create_thread(&amp;bar);
manager.owns(thread);
}
</programlisting>
</section>
<section id="threads.rationale.non-copyable.shared">
<title>6. Use case: Creation of a thread whose ownership is shared between multiple
objects.</title>
<programlisting>
void foo()
{
thread = create_thread(&amp;bar);
manager1.add(thread);
manager2.add(thread);
}
</programlisting>
</section>
<para>Of these usage patterns there's only one that requires reference
management (number 6). Hopefully it's fairly obvious that this usage pattern
simply won't occur as often as the other usage patterns. So there really
isn't a "typical need" for a thread concept, though there is some
need.</para>
<para>Since the need isn't typical we must use different criteria for
deciding on either a thread_ref or thread design. Possible criteria include
ease of use and performance. So let's analyze both of these
carefully.</para>
<para>With ease of use we can look at existing experience. The standard C++
objects that represent a system resource, such as std::iostream, are
noncopyable, so we know that C++ programmers must at least be experienced
with this design. Most C++ developers are also used to smart pointers such
as boost::shared_ptr, so we know they can at least adapt to a thread_ref
concept with little effort. So existing experience isn't going to lead us to
a choice.</para>
<para>The other thing we can look at is how difficult it is to use both
types for the six usage patterns above. If we find it overly difficult to
use a concept for any of the usage patterns there would be a good argument
for choosing the other design. So we'll code all six usage patterns using
both designs.</para>
<section id="threads.rationale_comparison.non-copyable.simple">
<title>1. Comparison: simple creation of a thread.</title>
<programlisting>
void foo()
{
thread thrd(&amp;bar);
}
void foo()
{
thread_ref thrd = create_thread(&amp;bar);
}
</programlisting>
</section>
<section id="threads.rationale_comparison.non-copyable.joined">
<title>2. Comparison: creation of a thread that's later joined.</title>
<programlisting>
void foo()
{
thread thrd(&amp;bar);
thrd.join();
}
void foo()
{
thread_ref thrd =
create_thread(&amp;bar);thrd-&gt;join();
}
</programlisting>
</section>
<section id="threads.rationale_comparison.non-copyable.loop">
<title>3. Comparison: simple creation of several threads in a loop.</title>
<programlisting>
void foo()
{
for (int i=0; i&lt;NUM_THREADS; ++i)
thread thrd(&amp;bar);
}
void foo()
{
for (int i=0; i&lt;NUM_THREADS; ++i)
thread_ref thrd = create_thread(&amp;bar);
}
</programlisting>
</section>
<section id="threads.rationale_comparison.non-copyable.loop-join">
<title>4. Comparison: creation of several threads in a loop which are later joined.</title>
<programlisting>
void foo()
{
std::auto_ptr&lt;thread&gt; threads[NUM_THREADS];
for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = std::auto_ptr&lt;thread&gt;(new thread(&amp;bar));
for (int i= 0; i&lt;NUM_THREADS;
++i)threads[i]-&gt;join();
}
void foo()
{
thread_ref threads[NUM_THREADS];
for (int i=0; i&lt;NUM_THREADS; ++i)
threads[i] = create_thread(&amp;bar);
for (int i= 0; i&lt;NUM_THREADS;
++i)threads[i]-&gt;join();
}
</programlisting>
</section>
<section id="threads.rationale_comparison.non-copyable.pass">
<title>5. Comparison: creation of a thread whose ownership is passed to another object/method.</title>
<programlisting>
void foo()
{
thread thrd* = new thread(&amp;bar);
manager.owns(thread);
}
void foo()
{
thread_ref thrd = create_thread(&amp;bar);
manager.owns(thrd);
}
</programlisting>
</section>
<section id="threads.rationale_comparison.non-copyable.shared">
<title>6. Comparison: creation of a thread whose ownership is shared
between multiple objects.</title>
<programlisting>
void foo()
{
boost::shared_ptr&lt;thread&gt; thrd(new thread(&amp;bar));
manager1.add(thrd);
manager2.add(thrd);
}
void foo()
{
thread_ref thrd = create_thread(&amp;bar);
manager1.add(thrd);
manager2.add(thrd);
}
</programlisting>
</section>
<para>This shows the usage patterns being nearly identical in complexity for
both designs. The only actual added complexity occurs because of the use of
operator new in
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>,
<link linkend="threads.rationale_comparison.non-copyable.pass">(5)</link>, and
<link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>;
and the use of std::auto_ptr and boost::shared_ptr in
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link> and
<link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>
respectively. However, that's not really
much added complexity, and C++ programmers are used to using these idioms
anyway. Some may dislike the presence of operator new in user code, but
this can be eliminated by proper design of higher level concepts, such as
the boost::thread_group class that simplifies example
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>
down to:</para>
<programlisting>
void foo()
{
thread_group threads;
for (int i=0; i&lt;NUM_THREADS; ++i)
threads.create_thread(&amp;bar);
threads.join_all();
}
</programlisting>
<para>So ease of use is really a wash and not much help in picking a
design.</para>
<para>So what about performance? Looking at the above code examples,
we can analyze the theoretical impact to performance that both designs
have. For <link linkend="threads.rationale_comparison.non-copyable.simple">(1)</link>
we can see that platforms that don't have a ref-counted native
thread type (POSIX, for instance) will be impacted by a thread_ref
design. Even if the native thread type is ref-counted there may be an impact
if more state information has to be maintained for concepts foreign to the
native API, such as clean up stacks for Win32 implementations.
For <link linkend="threads.rationale_comparison.non-copyable.joined">(2)</link>
and <link linkend="threads.rationale_comparison.non-copyable.loop">(3)</link>
the performance impact will be identical to
<link linkend="threads.rationale_comparison.non-copyable.simple">(1)</link>.
For <link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>
things get a little more interesting and we find that theoretically at least
the thread_ref may perform faster since the thread design requires dynamic
memory allocation/deallocation. However, in practice there may be dynamic
allocation for the thread_ref design as well, it will just be hidden from
the user. As long as the implementation has to do dynamic allocations the
thread_ref loses again because of the reference management. For
<link linkend="threads.rationale_comparison.non-copyable.pass">(5)</link> we see
the same impact as we do for
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>.
For <link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>
we still have a possible impact to
the thread design because of dynamic allocation but thread_ref no longer
suffers because of its reference management, and in fact, theoretically at
least, the thread_ref may do a better job of managing the references. All of
this indicates that thread wins for
<link linkend="threads.rationale_comparison.non-copyable.simple">(1)</link>,
<link linkend="threads.rationale_comparison.non-copyable.joined">(2)</link> and
<link linkend="threads.rationale_comparison.non-copyable.loop">(3)</link>; with
<link linkend="threads.rationale_comparison.non-copyable.loop-join">(4)</link>
and <link linkend="threads.rationale_comparison.non-copyable.pass">(5)</link> the
winner depending on the implementation and the platform but with the thread design
probably having a better chance; and with
<link linkend="threads.rationale_comparison.non-copyable.shared">(6)</link>
it will again depend on the
implementation and platform but this time we favor thread_ref
slightly. Given all of this it's a narrow margin, but the thread design
prevails.</para>
<para>Given this analysis, and the fact that noncopyable objects for system
resources are the normal designs that C++ programmers are used to dealing
with, the &Boost.Threads; library has gone with a noncopyable design.</para>
</section>
<section id="threads.rationale.events">
<title>Rationale for not providing <emphasis>Event Variables</emphasis></title>
<para><emphasis>Event variables</emphasis> are simply far too
error-prone. <classname>boost::condition</classname> variables are a much safer
alternative. [Note that Graphical User Interface <emphasis>events</emphasis> are
a different concept, and are not what is being discussed here.]</para>
<para>Event variables were one of the first synchronization primitives. They
are still used today, for example, in the native Windows multithreading
API. Yet both respected computer science researchers and experienced
multithreading practitioners believe event variables are so inherently
error-prone that they should never be used, and thus should not be part of a
multithreading library.</para>
<para>Per Brinch Hansen &cite.Hansen73; analyzed event variables in some
detail, pointing out [emphasis his] that "<emphasis>event operations force
the programmer to be aware of the relative speeds of the sending and
receiving processes</emphasis>". His summary:</para>
<blockquote>
<para>We must therefore conclude that event variables of the previous type
are impractical for system design. <emphasis>The effect of an interaction
between two processes must be independent of the speed at which it is
carried out.</emphasis></para>
</blockquote>
<para>Experienced programmers using the Windows platform today report that
event variables are a continuing source of errors, even after previous bad
experiences caused them to be very careful in their use of event
variables. Overt problems can be avoided, for example, by teaming the event
variable with a mutex, but that may just convert a <link
linkend="threads.glossary.race-condition">race condition</link> into another
problem, such as excessive resource use. One of the most distressing aspects
of the experience reports is the claim that many defects are latent. That
is, the programs appear to work correctly, but contain hidden timing
dependencies which will cause them to fail when environmental factors or
usage patterns change, altering relative thread timings.</para>
<para>The decision to exclude event variables from &Boost.Threads; has been
surprising to some Windows programmers. They have written programs which
work using event variables, and wonder what the problem is. It seems similar
to the "goto considered harmful" controversy of 30 years ago. It isn't that
events, like gotos, can't be made to work, but rather that virtually all
programs using alternatives will be easier to write, debug, read, maintain,
and will be less likely to contain latent defects.</para>
<para>[Rationale provided by Beman Dawes]</para>
</section>
</section>

View File

@@ -0,0 +1,362 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/read_write_mutex.hpp"
last-revision="$Date$">
<namespace name="boost">
<namespace name="read_write_scheduling_policy">
<enum name="read_write_scheduling_policy">
<enumvalue name="writer_priority" />
<enumvalue name="reader_priority" />
<enumvalue name="alternating_many_reads" />
<enumvalue name="alternating_single_read" />
<purpose>
<para>Specifies the
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
to use when a set of threads try to obtain different types of
locks simultaneously.</para>
</purpose>
<description>
<para>The only clock type supported by &Boost.Threads; is
<code>TIME_UTC</code>. The epoch for <code>TIME_UTC</code>
is 1970-01-01 00:00:00.</para>
</description>
</enum>
</namespace>
<class name="read_write_mutex">
<purpose>
<para>The <classname>read_write_mutex</classname> class is a model of the
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>read_write_mutex</classname> class is a model of the
<link linkend="threads.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>try_read_write_mutex</classname> and <classname>timed_read_write_mutex</classname>.</para>
<para>The <classname>read_write_mutex</classname> class supplies the following typedef,
which <link linkend="threads.concepts.read-write-lock-models">models</link>
the specified locking strategy:
<informaltable>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>The <classname>read_write_mutex</classname> class uses an
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
locking strategy, so attempts to recursively lock a <classname>read_write_mutex</classname>
object or attempts to unlock one by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.
This strategy allows implementations to be as efficient as possible
on any given platform. It is, however, recommended that
implementations include debugging support to detect misuse when
<code>NDEBUG</code> is not defined.</para>
<para>Like all
<link linkend="threads.concepts.read-write-mutex-models">read/write mutex models</link>
in &Boost.Threads;, <classname>read_write_mutex</classname> has two types of
<link linkend="threads.concepts.read-write-scheduling-policies">scheduling policies</link>, an
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
between threads trying to obtain different types of locks and an
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
between threads trying to obtain the same type of lock.
The <classname>read_write_mutex</classname> class allows the
programmer to choose what
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
will be used; however, like all read/write mutex models,
<classname>read_write_mutex</classname> leaves the
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>.
</para>
<note>Self-deadlock is virtually guaranteed if a thread tries to
lock the same <classname>read_write_mutex</classname> multiple times
unless all locks are read-locks (but see below)</note>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<parameter name="count">
<paramtype>boost::read_write_scheduling_policy</paramtype>
</parameter>
<effects>Constructs a <classname>read_write_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>read_write_mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
<class name="try_read_write_mutex">
<purpose>
<para>The <classname>try_read_write_mutex</classname> class is a model of the
<link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>try_read_write_mutex</classname> class is a model of the
<link linkend="threads.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>read_write_mutex</classname> and <classname>timed_read_write_mutex</classname>.</para>
<para>The <classname>try_read_write_mutex</classname> class supplies the following typedefs,
which <link linkend="threads.concepts.read-write-lock-models">model</link>
the specified locking strategy:
<informaltable>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_try_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>The <classname>try_read_write_mutex</classname> class uses an
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
locking strategy, so attempts to recursively lock a <classname>try_read_write_mutex</classname>
object or attempts to unlock one by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.
This strategy allows implementations to be as efficient as possible
on any given platform. It is, however, recommended that
implementations include debugging support to detect misuse when
<code>NDEBUG</code> is not defined.</para>
<para>Like all
<link linkend="threads.concepts.read-write-mutex-models">read/write mutex models</link>
in &Boost.Threads;, <classname>try_read_write_mutex</classname> has two types of
<link linkend="threads.concepts.read-write-scheduling-policies">scheduling policies</link>, an
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
between threads trying to obtain different types of locks and an
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
between threads trying to obtain the same type of lock.
The <classname>try_read_write_mutex</classname> class allows the
programmer to choose what
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
will be used; however, like all read/write mutex models,
<classname>try_read_write_mutex</classname> leaves the
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
<link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
</para>
<note>Self-deadlock is virtually guaranteed if a thread tries to
lock the same <classname>try_read_write_mutex</classname> multiple times
unless all locks are read-locks (but see below)</note>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<parameter name="count">
<paramtype>boost::read_write_scheduling_policy</paramtype>
</parameter>
<effects>Constructs a <classname>try_read_write_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>try_read_write_mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
<class name="timed_read_write_mutex">
<purpose>
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
<link linkend="threads.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
<link linkend="threads.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>read_write_mutex</classname> and <classname>try_read_write_mutex</classname>.</para>
<para>The <classname>timed_read_write_mutex</classname> class supplies the following typedefs,
which <link linkend="threads.concepts.read-write-lock-models">model</link>
the specified locking strategy:
<informaltable>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_try_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_timed_lock</entry>
<entry><link linkend="threads.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link></entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<para>The <classname>timed_read_write_mutex</classname> class uses an
<link linkend="threads.concepts.read-write-locking-strategies.unspecified">Unspecified</link>
locking strategy, so attempts to recursively lock a <classname>timed_read_write_mutex</classname>
object or attempts to unlock one by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.
This strategy allows implementations to be as efficient as possible
on any given platform. It is, however, recommended that
implementations include debugging support to detect misuse when
<code>NDEBUG</code> is not defined.</para>
<para>Like all
<link linkend="threads.concepts.read-write-mutex-models">read/write mutex models</link>
in &Boost.Threads;, <classname>timed_read_write_mutex</classname> has two types of
<link linkend="threads.concepts.read-write-scheduling-policies">scheduling policies</link>, an
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
between threads trying to obtain different types of locks and an
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link>
between threads trying to obtain the same type of lock.
The <classname>timed_read_write_mutex</classname> class allows the
programmer to choose what
<link linkend="threads.concepts.read-write-scheduling-policies.inter-class">inter-class sheduling policy</link>
will be used; however, like all read/write mutex models,
<classname>timed_read_write_mutex</classname> leaves the
<link linkend="threads.concepts.read-write-scheduling-policies.intra-class">intra-class sheduling policy</link> as
<link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
</para>
<note>Self-deadlock is virtually guaranteed if a thread tries to
lock the same <classname>timed_read_write_mutex</classname> multiple times
unless all locks are read-locks (but see below)</note>
</description>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_timed_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<parameter name="count">
<paramtype>boost::read_write_scheduling_policy</paramtype>
</parameter>
<effects>Constructs a <classname>timed_read_write_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>timed_read_write_mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
</namespace>
</header>

302
doc/recursive_mutex-ref.xml Normal file
View File

@@ -0,0 +1,302 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/recursive_mutex.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="recursive_mutex">
<purpose>
<para>The <classname>recursive_mutex</classname> class is a model of the
<link linkend="threads.concepts.Mutex">Mutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>recursive_mutex</classname> class is a model of the
<link linkend="threads.concepts.Mutex">Mutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>recursive_try_mutex</classname> and <classname>recursive_timed_mutex</classname>.</para>
<para>For <link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking mechanics, see <classname>mutex</classname>,
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
</para>
<para>The <classname>recursive_mutex</classname> class supplies the following typedef,
which models the specified locking strategy:
<table>
<title>Supported Lock Types</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>The <classname>recursive_mutex</classname> class uses a
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking strategy, so attempts to recursively lock a
<classname>recursive_mutex</classname> object
succeed and an internal "lock count" is maintained.
Attempts to unlock a <classname>recursive_mutex</classname> object
by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.</para>
<para>Like all
<link linkend="threads.concepts.mutex-models">mutex models</link>
in &Boost.Threads;, <classname>recursive_mutex</classname> leaves the
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
Programmers should make no assumptions about the order in which
waiting threads acquire a lock.</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<effects>Constructs a <classname>recursive_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>recursive_mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
<class name="recursive_try_mutex">
<purpose>
<para>The <classname>recursive_try_mutex</classname> class is a model of the
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>recursive_try_mutex</classname> class is a model of the
<link linkend="threads.concepts.TryMutex">TryMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>recursive_mutex</classname> and <classname>recursive_timed_mutex</classname>.</para>
<para>For <link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking mechanics, see <classname>mutex</classname>,
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
</para>
<para>The <classname>recursive_try_mutex</classname> class supplies the following typedefs,
which model the specified locking strategies:
<table>
<title>Supported Lock Types</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>The <classname>recursive_try_mutex</classname> class uses a
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking strategy, so attempts to recursively lock a
<classname>recursive_try_mutex</classname> object
succeed and an internal "lock count" is maintained.
Attempts to unlock a <classname>recursive_mutex</classname> object
by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.</para>
<para>Like all
<link linkend="threads.concepts.mutex-models">mutex models</link>
in &Boost.Threads;, <classname>recursive_try_mutex</classname> leaves the
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
Programmers should make no assumptions about the order in which
waiting threads acquire a lock.</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<effects>Constructs a <classname>recursive_try_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>recursive_try_mutex</classname> object.
</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
<class name="recursive_timed_mutex">
<purpose>
<para>The <classname>recursive_timed_mutex</classname> class is a model of the
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.</para>
</purpose>
<description>
<para>The <classname>recursive_timed_mutex</classname> class is a model of the
<link linkend="threads.concepts.TimedMutex">TimedMutex</link> concept.
It should be used to synchronize access to shared resources using
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking mechanics.</para>
<para>For classes that model related mutex concepts, see
<classname>recursive_mutex</classname> and <classname>recursive_try_mutex</classname>.</para>
<para>For <link linkend="threads.concepts.unspecified-locking-strategy">Unspecified</link>
locking mechanics, see <classname>mutex</classname>,
<classname>try_mutex</classname>, and <classname>timed_mutex</classname>.
</para>
<para>The <classname>recursive_timed_mutex</classname> class supplies the following typedefs,
which model the specified locking strategies:
<table>
<title>Supported Lock Types</title>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
<row>
<entry>scoped_timed_lock</entry>
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
</row>
</tbody>
</tgroup>
</table>
</para>
<para>The <classname>recursive_timed_mutex</classname> class uses a
<link linkend="threads.concepts.recursive-locking-strategy">Recursive</link>
locking strategy, so attempts to recursively lock a
<classname>recursive_timed_mutex</classname> object
succeed and an internal "lock count" is maintained.
Attempts to unlock a <classname>recursive_mutex</classname> object
by threads that don't own a lock on it result in
<emphasis role="bold">undefined behavior</emphasis>.</para>
<para>Like all
<link linkend="threads.concepts.mutex-models">mutex models</link>
in &Boost.Threads;, <classname>recursive_timed_mutex</classname> leaves the
<link linkend="threads.concepts.sheduling-policies">scheduling policy</link>
as <link linkend="threads.concepts.unspecified-scheduling-policy">Unspecified</link>.
Programmers should make no assumptions about the order in which
waiting threads acquire a lock.</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<typedef name="scoped_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_timed_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<constructor>
<effects>Constructs a <classname>recursive_timed_mutex</classname> object.
</effects>
<postconditions><code>*this</code> is in an unlocked state.
</postconditions>
</constructor>
<destructor>
<effects>Destroys a <classname>recursive_timed_mutex</classname> object.</effects>
<requires><code>*this</code> is in an unlocked state.</requires>
<notes><emphasis role="bold">Danger:</emphasis> Destruction of a
locked mutex is a serious programming error resulting in undefined
behavior such as a program crash.</notes>
</destructor>
</class>
</namespace>
</header>

20
doc/reference.xml Normal file
View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<library-reference id="threads.reference"
last-revision="$Date$"
xmlns:xi="http://www.w3.org/2001/XInclude">
<xi:include href="barrier-ref.xml"/>
<xi:include href="condition-ref.xml"/>
<xi:include href="exceptions-ref.xml"/>
<xi:include href="mutex-ref.xml"/>
<xi:include href="once-ref.xml"/>
<xi:include href="recursive_mutex-ref.xml"/>
<xi:include href="read_write_mutex-ref.xml"/>
<xi:include href="thread-ref.xml"/>
<xi:include href="tss-ref.xml"/>
<xi:include href="xtime-ref.xml"/>
</library-reference>

112
doc/release_notes.xml Normal file
View File

@@ -0,0 +1,112 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<section id="threads.release_notes" last-revision="$Date$">
<title>Release Notes</title>
<section id="threads.release_notes.boost_1_32_0">
<title>Boost 1.32.0</title>
<section id="threads.release_notes.boost_1_32_0.change_log.documentation">
<title>Documentation converted to BoostBook</title>
<para>The documentation was converted to BoostBook format,
and a number of errors and inconsistencies were
fixed in the process.
Since this was a fairly large task, there are likely to be
more errors and inconsistencies remaining. If you find any,
please report them!</para>
</section>
<section id="threads.release_notes.boost_1_32_0.change_log.static_link">
<title>Static-link build option added</title>
<para>The option to link &Boost.Threads; as a static
library has been added back with some limitations.
This feature was originally removed because
<classname>boost::thread_specific_ptr</classname> required
that &Boost.Threads; be dynamically linked in order for its
cleanup functionality to work on Win32 platforms.
Several options are currently being explored to resolve
this issue. In the meantime, the ability to link
&Boost.Threads; statically has been added back
<emphasis>with <classname>boost::thread_specific_ptr</classname>
support removed</emphasis> from the statically linked version.
The decision to add it back was made because its lack is
one of the most frequent complaints about &Boost.Threads;
and because the other approaches that are being investigated
to deal with <classname>boost::thread_specific_ptr</classname>
cleanup look fairly promising.
<note>&Boost.Threads; is still dynamically linked by default.
In order to force it to be statically linked, it is necessary to
#define BOOST_THREAD_USE_LIB before any of the &Boost.Threads;
header files are #included.</note>
<note>If the <classname>boost::thread_specific_ptr</classname> cleanup
issue cannot be resolved by some other means, it is highly
likely that the option to statically link &Boost.Threads;
will be removed again in a future version of Boost, at least
for Win32 platforms. This is because the
<classname>boost::thread_specific_ptr</classname> functionality
will be increasingly used by &Boost.Threads; itself,
so that proper cleanup will become essential
in future versions of &Boost.Threads;.</note>
</para>
</section>
<section id="threads.release_notes.boost_1_32_0.change_log.barrier">
<title>Barrier functionality added</title>
<para>A new class, <classname>boost::barrier</classname>, was added.</para>
</section>
<section id="threads.release_notes.boost_1_32_0.change_log.read_write_mutex">
<title>Read/write mutex functionality added</title>
<para>New classes,
<classname>boost::read_write_mutex</classname>,
<classname>boost::try_read_write_mutex</classname>, and
<classname>boost::timed_read_write_mutex</classname>
were added.</para>
</section>
<section id="threads.release_notes.boost_1_32_0.change_log.thread_specific_ptr">
<title>Thread-specific pointer functionality changed</title>
<para>The <classname>boost::thread_specific_ptr</classname>
constructor now takes an optional pointer to a cleanup function that
is called to release the thread-specific data that is being pointed
to by <classname>boost::thread_specific_ptr</classname> objects.</para>
<para>Fixed: the number of available thread-specific storage "slots"
is too small on some platforms.</para>
<para>Fixed: <functionname>thread_specific_ptr::reset()</functionname>
doesn't check error returned by <functionname>tss::set()</functionname>
(the <functionname>tss::set()</functionname> function now throws
if it fails instead of returning an error code).</para>
<para>Fixed: calling
<functionname>boost::thread_specific_ptr::reset()</functionname> or
<functionname>boost::thread_specific_ptr::release()</functionname>
causes double-delete: once when
<functionname>boost::thread_specific_ptr::reset()</functionname> or
<functionname>boost::thread_specific_ptr::release()</functionname>
is called and once when
<functionname>boost::thread_specific_ptr::~thread_specific_ptr()</functionname>
is called.</para>
</section>
<section id="threads.release_notes.boost_1_32_0.change_log.mutex">
<title>Mutex implementation changed for Win32</title>
<para>On Win32, <classname>boost::mutex</classname>,
<classname>boost::try_mutex</classname>, <classname>boost::recursive_mutex</classname>,
and <classname>boost::recursive_try_mutex</classname> now use a Win32 critical section
whenever possible; otherwise they use a Win32 mutex. As before,
<classname>boost::timed_mutex</classname> and
<classname>boost::recursive_timed_mutex</classname> use a Win32 mutex.</para>
</section>
</section>
</section>

266
doc/thread-ref.xml Normal file
View File

@@ -0,0 +1,266 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/thread.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="thread">
<purpose>
<para>The <classname>thread</classname> class represents threads of
execution, and provides the functionality to create and manage
threads within the &Boost.Threads; library. See
<xref linkend="threads.glossary"/> for a precise description of
<link linkend="threads.glossary.thread">thread of execution</link>,
and for definitions of threading-related terms and of thread states such as
<link linkend="threads.glossary.thread-state">blocked</link>.</para>
</purpose>
<description>
<para>A <link linkend="threads.glossary.thread">thread of execution</link>
has an initial function. For the program's initial thread, the initial
function is <code>main()</code>. For other threads, the initial
function is <code>operator()</code> of the function object passed to
the <classname>thread</classname> object's constructor.</para>
<para>A thread of execution is said to be &quot;finished&quot;
or to have &quot;finished execution&quot; when its initial function returns or
is terminated. This includes completion of all thread cleanup
handlers, and completion of the normal C++ function return behaviors,
such as destruction of automatic storage (stack) objects and releasing
any associated implementation resources.</para>
<para>A thread object has an associated state which is either
&quot;joinable&quot; or &quot;non-joinable&quot;.</para>
<para>Except as described below, the policy used by an implementation
of &Boost.Threads; to schedule transitions between thread states is
unspecified.</para>
<para><note>Just as the lifetime of a file may be different from the
lifetime of an <code>iostream</code> object which represents the file, the lifetime
of a thread of execution may be different from the
<classname>thread</classname> object which represents the thread of
execution. In particular, after a call to <code>join()</code>,
the thread of execution will no longer exist even though the
<classname>thread</classname> object continues to exist until the
end of its normal lifetime. The converse is also possible; if
a <classname>thread</classname> object is destroyed without
<code>join()</code> first having been called, the thread of execution
continues until its initial function completes.</note></para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<constructor>
<effects>Constructs a <classname>thread</classname> object
representing the current thread of execution.</effects>
<postconditions><code>*this</code> is non-joinable.</postconditions>
<notes><emphasis role="bold">Danger:</emphasis>
<code>*this</code> is valid only within the current thread.</notes>
</constructor>
<constructor specifiers="explicit">
<parameter name="threadfunc">
<paramtype>const boost::function0&lt;void&gt;&amp;</paramtype>
</parameter>
<effects>
Starts a new thread of execution and constructs a
<classname>thread</classname> object representing it.
Copies <code>threadfunc</code> (which in turn copies
the function object wrapped by <code>threadfunc</code>)
to an internal location which persists for the lifetime
of the new thread of execution. Calls <code>operator()</code>
on the copy of the <code>threadfunc</code> function object
in the new thread of execution.
</effects>
<postconditions><code>*this</code> is joinable.</postconditions>
<throws><code>boost::thread_resource_error</code> if a new thread
of execution cannot be started.</throws>
</constructor>
<destructor>
<effects>Destroys <code>*this</code>. The actual thread of
execution may continue to execute after the
<classname>thread</classname> object has been destroyed.
</effects>
<notes>If <code>*this</code> is joinable the actual thread
of execution becomes &quot;detached&quot;. Any resources used
by the thread will be reclaimed when the thread of execution
completes. To ensure such a thread of execution runs to completion
before the <classname>thread</classname> object is destroyed, call
<code>join()</code>.</notes>
</destructor>
<method-group name="comparison">
<method name="operator==" cv="const">
<type>bool</type>
<parameter name="rhs">
<type>const thread&amp;</type>
</parameter>
<requires>The thread is non-terminated or <code>*this</code>
is joinable.</requires>
<returns><code>true</code> if <code>*this</code> and
<code>rhs</code> represent the same thread of
execution.</returns>
</method>
<method name="operator!=" cv="const">
<type>bool</type>
<parameter name="rhs">
<type>const thread&amp;</type>
</parameter>
<requires>The thread is non-terminated or <code>*this</code>
is joinable.</requires>
<returns><code>!(*this==rhs)</code>.</returns>
</method>
</method-group>
<method-group name="modifier">
<method name="join">
<type>void</type>
<requires><code>*this</code> is joinable.</requires>
<effects>The current thread of execution blocks until the
initial function of the thread of execution represented by
<code>*this</code> finishes and all resources are
reclaimed.</effects>
<postcondition><code>*this</code> is non-joinable.</postcondition>
<notes>If <code>*this == thread()</code> the result is
implementation-defined. If the implementation doesn't
detect this the result will be
<link linkend="threads.glossary.deadlock">deadlock</link>.
</notes>
</method>
</method-group>
<method-group name="static">
<method name="sleep" specifiers="static">
<type>void</type>
<parameter name="xt">
<paramtype>const <classname>xtime</classname>&amp;</paramtype>
</parameter>
<effects>The current thread of execution blocks until
<code>xt</code> is reached.</effects>
</method>
<method name="yield" specifiers="static">
<type>void</type>
<effects>The current thread of execution is placed in the
<link linkend="threads.glossary.thread-state">ready</link>
state.</effects>
<notes>
<simpara>Allow the current thread to give up the rest of its
time slice (or other scheduling quota) to another thread.
Particularly useful in non-preemptive implementations.</simpara>
</notes>
</method>
</method-group>
</class>
<class name="thread_group">
<purpose>
The <classname>thread_group</classname> class provides a container
for easy grouping of threads to simplify several common thread
creation and management idioms.
</purpose>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<constructor>
<effects>Constructs an empty <classname>thread_group</classname>
container.</effects>
</constructor>
<destructor>
<effects>Destroys each contained thread object. Destroys <code>*this</code>.</effects>
<notes>Behavior is undefined if another thread references
<code>*this </code> during the execution of the destructor.
</notes>
</destructor>
<method-group name="modifier">
<method name="create_thread">
<type><classname>thread</classname>*</type>
<parameter name="threadfunc">
<paramtype>const boost::function0&lt;void&gt;&amp;</paramtype>
</parameter>
<effects>Creates a new <classname>thread</classname> object
that executes <code>threadfunc</code> and adds it to the
<code>thread_group</code> container object's list of managed
<classname>thread</classname> objects.</effects>
<returns>Pointer to the newly created
<classname>thread</classname> object.</returns>
</method>
<method name="add_thread">
<type>void</type>
<parameter name="thrd">
<paramtype><classname>thread</classname>* thrd</paramtype>
</parameter>
<effects>Adds <code>thrd</code> to the
<classname>thread_group</classname> object's list of managed
<classname>thread</classname> objects. The <code>thrd</code>
object must have been allocated via <code>operator new</code> and will
be deleted when the group is destroyed.</effects>
</method>
<method name="remove_thread">
<type>void</type>
<parameter name="thrd">
<paramtype><classname>thread</classname>* thrd</paramtype>
</parameter>
<effects>Removes <code>thread</code> from <code>*this</code>'s
list of managed <classname>thread</classname> objects.</effects>
<throws><emphasis role="bold">???</emphasis> if
<code>thrd</code> is not in <code>*this</code>'s list
of managed <classname>thread</classname> objects.</throws>
</method>
<method name="join_all">
<type>void</type>
<effects>Calls <code>join()</code> on each of the managed
<classname>thread</classname> objects.</effects>
</method>
</method-group>
</class>
</namespace>
</header>

54
doc/thread.xml Normal file
View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<library name="Threads" dirname="thread" id="threads"
last-revision="$Date$"
xmlns:xi="http://www.w3.org/2001/XInclude">
<libraryinfo>
<author>
<firstname>William</firstname>
<othername>E.</othername>
<surname>Kempf</surname>
</author>
<copyright>
<year>2001</year>
<year>2002</year>
<year>2003</year>
<holder>William E. Kempf</holder>
</copyright>
<legalnotice>
<para>Permission to use, copy, modify, distribute and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in all
copies and that both that copyright notice and this permission notice
appear in supporting documentation. William E. Kempf makes no
representations about the suitability of this software for any purpose.
It is provided "as is" without express or implied warranty.</para>
</legalnotice>
<librarypurpose>Portable C++ multi-threading</librarypurpose>
<librarycategory name="category:concurrent" />
<title>Boost.Threads</title>
</libraryinfo>
<title>&Boost.Threads;</title>
<xi:include href="overview.xml"/>
<xi:include href="design.xml"/>
<xi:include href="concepts.xml"/>
<xi:include href="rationale.xml"/>
<xi:include href="reference.xml"/>
<xi:include href="faq.xml"/>
<xi:include href="configuration.xml"/>
<xi:include href="build.xml"/>
<xi:include href="implementation_notes.xml"/>
<xi:include href="release_notes.xml"/>
<xi:include href="glossary.xml"/>
<xi:include href="acknowledgements.xml"/>
<xi:include href="bibliography.xml"/>
</library>

13
doc/thread_pool-ref.xml Normal file
View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/thread_pool.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="thread_pool">
</class>
</namespace>
</header>

207
doc/thread_pool.html Normal file
View File

@@ -0,0 +1,207 @@
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="stylesheet" type="text/css" href="../../../boost.css">
<title>Boost.Threads - Header &lt;boost/thread/thread_pool.hpp&gt;</title>
</head>
<body link="#0000ff" vlink="#800080">
<table border="0" cellpadding="7" cellspacing="0" width="100%" summary=
"header">
<tr>
<td valign="top" width="300">
<h3><a href="../../../index.htm"><img height="86" width="277" alt="C++ Boost" src="../../../c++boost.gif" border="0"></a></h3>
</td>
<td valign="top">
<h1 align="center">Boost.Threads</h1>
<h2 align="center">Header &lt;<a href="../../../boost/thread/thread_pool.hpp">boost/thread/thread_pool.hpp</a>&gt;</h2>
</td>
</tr>
</table>
<hr>
<h2>Contents</h2>
<dl class="page-index">
<dt><a href="#introduction">Introduction</a></dt>
<dt><a href="#classes">Classes</a></dt>
<dl class="page-index">
<dt><a href="#class-thread_pool">Class <code>thread_pool</code></a></dt>
<dl class="page-index">
<dt><a href="#class-thread_pool-synopsis">Class <code>thread_pool</code> synopsis</a></dt>
<dt><a href="#class-thread_pool-ctors">Class <code>thread_pool</code> constructors and destructor</a></dt>
<dt><a href="#class-thread_pool-modifiers">Class <code>thread_pool</code> modifier functions</a></dt>
</dl>
</dl>
<dt><a href="#examples">Example(s)</a></dt>
</dl>
<hr>
<h2><a name="introduction"></a>Introduction</h2>
<p>Include the header &lt;<a href="../../../boost/thread/thread_pool.hpp">boost/thread/thread_pool.hpp</a>&gt;
to define the <a href="#class-thread_pool">thread_pool</a> class.</p>
<h2><a name="classes"></a>Classes</h2>
<h3><a name="class-thread_pool"></a>Class <code>thread_pool</code></h3>
<p>The <tt>thread_pool</tt> class provides&nbsp;an interface for&nbsp;running
jobs on a dynamically managed set&nbsp;of worker threads called a pool.&nbsp;
When a job is added, it can execute on any&nbsp;available thread in the pool.&nbsp;
This class controls&nbsp;both the maximum and minimum number of threads&nbsp;in
the pool.&nbsp; If a thread in the pool is sitting idle&nbsp;for a period&nbsp;of
time, it&nbsp;will exit unless by exiting the number of threads would dip below
the minimum. Thread pools provide an optimization over creating a new thread
for each job since the pool can often remove the overhead of thread creation.</p>
<h4><a name="class-thread_pool-synopsis"></a>Class <code>thread_pool</code> synopsis</h4>
<pre>
namespace boost
{
class thread_pool : <a href="../../utility/utility.htm#Class noncopyable">boost::noncopyable</a> // Exposition only.
// Class thread meets the <a href="overview.html#non-copyable">NonCopyable</a> requirement.
{
public:
thread_pool(int max_threads=std::numeric_limits&lt;int&gt;::max(),
int min_threads=0,
int timeout_secs=5);
~thread_pool();
void add(const boost::function0&lt;void&gt; &amp;job);
void join();
void cancel();
void detach();
};
};
</pre>
<h4><a name="class-spec-ctors"></a>Class <code>thread_pool</code> constructors and destructor</h4>
<pre>
thread_pool(int max_threads=std::numeric_limits&lt;int&gt;::max(),
int min_threads=0,
int timeout_secs=5);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Constructs a thread pool object and starts min_threads threads
running in the pool.</dt>
</dl>
<pre>
~thread_pool();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Calls join() if neither join() nor detach() were called
previously for this thread_pool.&nbsp; If detach() was not called, destroys all
resources associated with the threads in the pool and with the queue of jobs
still waiting to be executed.</dt>
</dl>
<h4><a name="class-spec-modifiers"></a>Class <code>thread_pool</code> modifier
functions</h4>
<pre>
void add(const boost::function0&lt;void&gt;&amp; job);
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Adds <tt>job</tt> to the <tt>thread_pool</tt> object's list of
jobs waiting to be executed.&nbsp; If any threads in the pool are idle, the job
will be execute as soon as the idle thread is scheduled by the operating
system.&nbsp; If no threads are idle and the number of threads in the pool is
less than the maximum number provided to the constructor, an additional thread
is created and added to the pool.&nbsp; That new thread will execute this job
as soon as it is scheduled by the operating system.&nbsp; If no threads are
idle and&nbsp;the thread count is at the maximum, this job will be queued until
a thread becomes available.&nbsp; Currently, queued jobs are processed in FIFO
order.</dt>
<dt><b>Throws:</b> std::runtime_error if join() or detach() have
previously been called for this thread_pool object.</dt>
</dl>
<pre>
void detach();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Relinquishes control of the pool of threads by this thread_pool
object.&nbsp; Any threads in the pool will continue to run and continue to
process any queued jobs, but no new threads will be created, and any subsequent
attempts to add new jobs will result in an exception.</dt>
<dt><b>Throws:</b> std::runtime_error if join()&nbsp;has previously
been called for this thread_pool object.</dt>
</dl>
<pre>
void cancel();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Removes all queued jobs from the thread_pool's internal queue,
and calls cancel() on all boost::thread objects in the pool.&nbsp; The specific
behavior of those threads will be dictated by their cancellation behavior - the
pool threads may be executing a user's job that deferrs cancellation, for
example.</dt>
<dt><b>Throws:</b> std::runtime_error if join() or detach() have
previously been called for this thread_pool object.</dt>
<dt><b>Note:</b> for the current version (1.27.0) of Boost.Threads, thread::cancel() is
not provided.&nbsp; This function -will- clear out all queued jobs, but any
currently executing jobs will not be cancelled.</dt>
</dl>
<pre>
void join();
</pre>
<dl class="function-semantics">
<dt><b>Effects:</b> Waits until all queued jobs are completed by the thread pool,
and then join()s will all of the threads in the pool.&nbsp; When join()
returns, no running threads will remain in the pool, and this object is invalid
for anything except destruction.&nbsp; Any calls to cancel(), join(), detach(),
or add() will result in an exception.</dt>
</dl>
<h2><a name="examples"></a>Example(s)</h2>
<pre>
#include &lt;boost/thread/thread_pool.hpp&gt;
#include &lt;boost/thread/mutex.hpp&gt;
#include &lt;iostream&gt;
boost::mutex io_mutex;
class job_adapter {
public:
job_adapter(void (*func)(int), int param) :
_func(func), _param(param){ }
void operator()() const { _func(_param); }
private:
void (*_func)(int);
int _param;
};
void simple_job(int param)
{
boost::mutex::scoped_lock l(io_mutex);
std::cout &lt;&lt; param &lt;&lt; " squared is " &lt;&lt; (param*param) &lt;&lt; "\n";
}
int main(int argc, char* argv[])
{
boost::thread_pool tp;
for (int i = 1; i &lt;= 10; ++i)
tp.add(simple_job);
tp.join();
return 0;
}
</pre>
<p>Typical output would be:</p>
<pre>
1 squared is 1
2 squared is 4
3 squared is 9
4 squared is 16
5 squared is 25
7 squared is 49
6 squared is 36
8 squared is 64
10 squared is 100
9 squared is 81
</pre>
<P>While the jobs are dispatched in the order they are received, the scheduling of
the individual threads in the pool is platform-dependent.</P>
<P>
<p>Revised
<!--webbot bot="Timestamp" S-Type="EDITED" S-Format="%d %B, %Y" startspan -->
05 November, 2001
<!--webbot bot="Timestamp" endspan i-checksum="39359" -->
</p>
<p><i>&copy; Copyright <a href="mailto:wekempf@cox.net">William E. Kempf</a>, David Moore 2001-2002.
All Rights Reserved.</i></p>
<p>Permission to use, copy, modify, distribute and sell this software and its
documentation for any purpose is hereby granted without fee, provided that the
above copyright notice appear in all copies and that both that copyright notice
and this permission notice appear in supporting documentation. William E. Kempf
makes no representations about the suitability of this software for any purpose.
It is provided &quot;as is&quot; without express or implied warranty.</p>
</body>
</html>

202
doc/tss-ref.xml Normal file
View File

@@ -0,0 +1,202 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/tss.hpp"
last-revision="$Date$">
<namespace name="boost">
<class name="thread_specific_ptr">
<purpose>
The <classname>thread_specific_ptr</classname> class defines
an interface for using thread specific storage.
</purpose>
<description>
<para>Thread specific storage is data associated with
individual threads and is often used to make operations
that rely on global data
<link linkend="threads.glossary.thread-safe">thread-safe</link>.
</para>
<para>Template <classname>thread_specific_ptr</classname>
stores a pointer to an object obtained on a thread-by-thread
basis and calls a specified cleanup handler on the contained
pointer when the thread terminates. The cleanup handlers are
called in the reverse order of construction of the
<classname>thread_specific_ptr</classname>s, and for the
initial thread are called by the destructor, providing the
same ordering guarantees as for normal declarations. Each
thread initially stores the null pointer in each
<classname>thread_specific_ptr</classname> instance.</para>
<para>The template <classname>thread_specific_ptr</classname>
is useful in the following cases:
<itemizedlist>
<listitem>An interface was originally written assuming
a single thread of control and it is being ported to a
multithreaded environment.</listitem>
<listitem>Each thread of control invokes sequences of
methods that share data that are physically unique
for each thread, but must be logically accessed
through a globally visible access point instead of
being explicitly passed.</listitem>
</itemizedlist>
</para>
</description>
<inherit access="private">
<type><classname>boost::noncopyable</classname></type>
<purpose>Exposition only</purpose>
</inherit>
<constructor>
<requires>The expression <code>delete get()</code> is well
formed.</requires>
<effects>A thread-specific data key is allocated and visible to
all threads in the process. Upon creation, the value
<code>NULL</code> will be associated with the new key in all
active threads. A cleanup method is registered with the key
that will call <code>delete</code> on the value associated
with the key for a thread when it exits. When a thread exits,
if a key has a registered cleanup method and the thread has a
non-<code>NULL</code> value associated with that key, the value
of the key is set to <code>NULL</code> and then the cleanup
method is called with the previously associated value as its
sole argument. The order in which registered cleanup methods
are called when a thread exits is undefined. If after all the
cleanup methods have been called for all non-<code>NULL</code>
values, there are still some non-<code>NULL</code> values
with associated cleanup handlers the result is undefined
behavior.</effects>
<throws><classname>boost::thread_resource_error</classname> if
the necessary resources can not be obtained.</throws>
<notes>There may be an implementation specific limit to the
number of thread specific storage objects that can be created,
and this limit may be small.</notes>
<rationale>The most common need for cleanup will be to call
<code>delete</code> on the associated value. If other forms
of cleanup are required the overloaded constructor should be
called instead.</rationale>
</constructor>
<constructor>
<parameter name="cleanup">
<paramtype>void (*cleanup)(void*)</paramtype>
</parameter>
<effects>A thread-specific data key is allocated and visible to
all threads in the process. Upon creation, the value
<code>NULL</code> will be associated with the new key in all
active threads. The <code>cleanup</code> method is registered
with the key and will be called for a thread with the value
associated with the key for that thread when it exits. When a
thread exits, if a key has a registered cleanup method and the
thread has a non-<code>NULL</code> value associated with that
key, the value of the key is set to <code>NULL</code> and then
the cleanup method is called with the previously associated
value as its sole argument. The order in which registered
cleanup methods are called when a thread exits is undefined.
If after all the cleanup methods have been called for all
non-<code>NULL</code> values, there are still some
non-<code>NULL</code> values with associated cleanup handlers
the result is undefined behavior.</effects>
<throws><classname>boost::thread_resource_error</classname> if
the necessary resources can not be obtained.</throws>
<notes>There may be an implementation specific limit to the
number of thread specific storage objects that can be created,
and this limit may be small.</notes>
<rationale>There is the occasional need to register
specialized cleanup methods, or to register no cleanup method
at all (done by passing <code>NULL</code> to this constructor.
</rationale>
</constructor>
<destructor>
<effects>Deletes the thread-specific data key allocated by the
constructor. The thread-specific data values associated with
the key need not be <code>NULL</code>. It is the responsibility
of the application to perform any cleanup actions for data
associated with the key.</effects>
<notes>Does not destroy any data that may be stored in any
thread's thread specific storage. For this reason you should
not destroy a <classname>thread_specific_ptr</classname> object
until you are certain there are no threads running that have
made use of its thread specific storage.</notes>
<rationale>Associated data is not cleaned up because registered
cleanup methods need to be run in the thread that allocated the
associated data to be guarranteed to work correctly. There's no
safe way to inject the call into another thread's execution
path, making it impossible to call the cleanup methods safely.
</rationale>
</destructor>
<method-group name="modifier functions">
<method name="release">
<type>T*</type>
<postconditions><code>*this</code> holds the null pointer
for the current thread.</postconditions>
<returns><code>this-&gt;get()</code> prior to the call.</returns>
<rationale>This method provides a mechanism for the user to
relinquish control of the data associated with the
thread-specific key.</rationale>
</method>
<method name="reset">
<type>void</type>
<parameter name="p">
<paramtype>T*</paramtype>
<default>0</default>
</parameter>
<effects>If <code>this-&gt;get() != p &amp;&amp;
this-&gt;get() != NULL</code> then call the
associated cleanup function.</effects>
<postconditions><code>*this</code> holds the pointer
<code>p</code> for the current thread.</postconditions>
</method>
</method-group>
<method-group name="observer functions">
<method name="get" cv="const">
<type>T*</type>
<returns>The object stored in thread specific storage for
the current thread for <code>*this</code>.</returns>
<notes>Each thread initially returns 0.</notes>
</method>
<method name="operator-&gt;" cv="const">
<type>T*</type>
<returns><code>this-&gt;get()</code>.</returns>
</method>
<method name="operator*()" cv="const">
<type>T&amp;</type>
<requires><code>this-&gt;get() != 0</code></requires>
<returns><code>this-&gt;get()</code>.</returns>
</method>
</method-group>
</class>
</namespace>
</header>

78
doc/xtime-ref.xml Normal file
View File

@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE library PUBLIC "-//Boost//DTD BoostBook XML V1.0//EN"
"http://www.boost.org/tools/boostbook/dtd/boostbook.dtd" [
<!ENTITY % threads.entities SYSTEM "entities.xml">
%threads.entities;
]>
<header name="boost/thread/xtime.hpp"
last-revision="$Date$">
<namespace name="boost">
<enum name="xtime_clock_types">
<enumvalue name="TIME_UTC" />
<purpose>
<para>Specifies the clock type to use when creating
an object of type <classname>xtime</classname>.</para>
</purpose>
<description>
<para>The only clock type supported by &Boost.Threads; is
<code>TIME_UTC</code>. The epoch for <code>TIME_UTC</code>
is 1970-01-01 00:00:00.</para>
</description>
</enum>
<struct name="xtime">
<purpose>
<simpara>An object of type <classname>xtime</classname>
defines a time that is used to perform high-resolution time operations.
This is a temporary solution that will be replaced by a more robust time
library once available in Boost.</simpara>
</purpose>
<description>
<simpara>The <classname>xtime</classname> type is used to represent a point on
some time scale or a duration in time. This type may be proposed for the C standard by
Markus Kuhn. &Boost.Threads; provides only a very minimal implementation of this
proposal; it is expected that a full implementation (or some other time
library) will be provided in Boost as a separate library, at which time &Boost.Threads;
will deprecate its own implementation.</simpara>
<simpara><emphasis role="bold">Note</emphasis> that the resolution is
implementation specific. For many implementations the best resolution
of time is far more than one nanosecond, and even when the resolution
is reasonably good, the latency of a call to <code>xtime_get()</code>
may be significant. For maximum portability, avoid durations of less than
one second.</simpara>
</description>
<free-function-group name="creation">
<function name="xtime_get">
<type>int</type>
<parameter name="xtp">
<paramtype><classname>xtime</classname>*</paramtype>
</parameter>
<parameter name="clock_type">
<paramtype>int</paramtype>
</parameter>
<postconditions>
<simpara><code>xtp</code> represents the current point in
time as a duration since the epoch specified by
<code>clock_type</code>.</simpara>
</postconditions>
<returns>
<simpara><code>clock_type</code> if successful, otherwise 0.</simpara>
</returns>
</function>
</free-function-group>
<data-member name="sec">
<type><emphasis>platform-specific-type</emphasis></type>
</data-member>
</struct>
</namespace>
</header>

2
example/.cvsignore Normal file
View File

@@ -0,0 +1,2 @@
bin
*.pdb

View File

@@ -0,0 +1,54 @@
# Copyright (C) 2001-2003
# William E. Kempf
#
# Permission to use, copy, modify, distribute and sell this software
# and its documentation for any purpose is hereby granted without fee,
# provided that the above copyright notice appear in all copies and
# that both that copyright notice and this permission notice appear
# in supporting documentation. William E. Kempf makes no representations
# about the suitability of this software for any purpose.
# It is provided "as is" without express or implied warranty.
#
# Boost.Threads example Jamfile
#
# Additional configuration variables used:
# 1. PTW32 may be used on Win32 platforms to specify that the pthreads-win32
# library should be used instead of "native" threads. This feature is
# mostly used for testing and it's generally recommended you use the
# native threading libraries instead. PTW32 should be set to be a list
# of two strings, the first specifying the installation path of the
# pthreads-win32 library and the second specifying which library
# variant to link against (see the pthreads-win32 documentation).
# Example: jam -sPTW32="c:\pthreads-win32 pthreadVCE.lib"
# Declare the location of this subproject relative to the root.
subproject libs/thread/example ;
# Include threads.jam for Boost.Threads global build information.
# This greatly simplifies the Jam code needed to configure the build
# for the various Win32 build types.
import ../build/threads ;
{
template example
## sources ##
: <template>thread_base
<dll>../build/boost_thread
## requirements ##
:
## default build ##
:
;
exe monitor : <template>example monitor.cpp ;
exe starvephil : <template>example starvephil.cpp ;
exe tennis : <template>example tennis.cpp ;
exe condition : <template>example condition.cpp ;
exe mutex : <template>example mutex.cpp ;
exe once : <template>example once.cpp ;
exe recursive_mutex : <template>example recursive_mutex.cpp ;
exe thread : <template>example thread.cpp ;
exe thread_group : <template>example thread_group.cpp ;
exe tss : <template>example tss.cpp ;
exe xtime : <template>example xtime.cpp ;
}

5
example/Jamfile.v2 Normal file
View File

@@ -0,0 +1,5 @@
exe starvephil
: starvephil.cpp ../build/boost_thread ../../test/build/unit_test_framework
;

79
example/condition.cpp Normal file
View File

@@ -0,0 +1,79 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
class bounded_buffer : private boost::noncopyable
{
public:
typedef boost::mutex::scoped_lock lock;
bounded_buffer(int n) : begin(0), end(0), buffered(0), circular_buf(n) { }
void send (int m) {
lock lk(monitor);
while (buffered == circular_buf.size())
buffer_not_full.wait(lk);
circular_buf[end] = m;
end = (end+1) % circular_buf.size();
++buffered;
buffer_not_empty.notify_one();
}
int receive() {
lock lk(monitor);
while (buffered == 0)
buffer_not_empty.wait(lk);
int i = circular_buf[begin];
begin = (begin+1) % circular_buf.size();
--buffered;
buffer_not_full.notify_one();
return i;
}
private:
int begin, end, buffered;
std::vector<int> circular_buf;
boost::condition buffer_not_full, buffer_not_empty;
boost::mutex monitor;
};
bounded_buffer buf(2);
void sender() {
int n = 0;
while (n < 100) {
buf.send(n);
std::cout << "sent: " << n << std::endl;
++n;
}
buf.send(-1);
}
void receiver() {
int n;
do {
n = buf.receive();
std::cout << "received: " << n << std::endl;
} while (n != -1); // -1 indicates end of buffer
}
int main(int, char*[])
{
boost::thread thrd1(&sender);
boost::thread thrd2(&receiver);
thrd1.join();
thrd2.join();
return 0;
}

117
example/monitor.cpp Normal file
View File

@@ -0,0 +1,117 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <vector>
#include <iostream>
#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
namespace {
const int ITERS = 100;
boost::mutex io_mutex;
} // namespace
template <typename M>
class buffer_t
{
public:
typedef typename M::scoped_lock scoped_lock;
buffer_t(int n)
: p(0), c(0), full(0), buf(n)
{
}
void send(int m)
{
scoped_lock lk(mutex);
while (full == buf.size())
cond.wait(lk);
buf[p] = m;
p = (p+1) % buf.size();
++full;
cond.notify_one();
}
int receive()
{
scoped_lock lk(mutex);
while (full == 0)
cond.wait(lk);
int i = buf[c];
c = (c+1) % buf.size();
--full;
cond.notify_one();
return i;
}
static buffer_t& get_buffer()
{
static buffer_t buf(2);
return buf;
}
static void do_sender_thread()
{
for (int n = 0; n < ITERS; ++n)
{
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "sending: " << n << std::endl;
}
get_buffer().send(n);
}
}
static void do_receiver_thread()
{
for (int x=0; x < (ITERS/2); ++x)
{
int n = get_buffer().receive();
{
boost::mutex::scoped_lock lock(io_mutex);
std::cout << "received: " << n << std::endl;
}
}
}
private:
M mutex;
boost::condition cond;
unsigned int p, c, full;
std::vector<int> buf;
};
template <typename M>
void do_test(M* dummy=0)
{
typedef buffer_t<M> buffer_type;
buffer_type::get_buffer();
boost::thread thrd1(&buffer_type::do_receiver_thread);
boost::thread thrd2(&buffer_type::do_receiver_thread);
boost::thread thrd3(&buffer_type::do_sender_thread);
thrd1.join();
thrd2.join();
thrd3.join();
}
void test_buffer()
{
do_test<boost::mutex>();
do_test<boost::recursive_mutex>();
}
int main()
{
test_buffer();
return 0;
}

52
example/mutex.cpp Normal file
View File

@@ -0,0 +1,52 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
boost::mutex io_mutex; // The iostreams are not guaranteed to be thread-safe!
class counter
{
public:
counter() : count(0) { }
int increment() {
boost::mutex::scoped_lock scoped_lock(mutex);
return ++count;
}
private:
boost::mutex mutex;
int count;
};
counter c;
void change_count()
{
int i = c.increment();
boost::mutex::scoped_lock scoped_lock(io_mutex);
std::cout << "count == " << i << std::endl;
}
int main(int, char*[])
{
const int num_threads = 4;
boost::thread_group thrds;
for (int i=0; i < num_threads; ++i)
thrds.create_thread(&change_count);
thrds.join_all();
return 0;
}

36
example/once.cpp Normal file
View File

@@ -0,0 +1,36 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/once.hpp>
#include <cassert>
int value=0;
boost::once_flag once = BOOST_ONCE_INIT;
void init()
{
++value;
}
void thread_proc()
{
boost::call_once(&init, once);
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
assert(value == 1);
}

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <iostream>
class counter
{
public:
counter() : count(0) { }
int add(int val) {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
count += val;
return count;
}
int increment() {
boost::recursive_mutex::scoped_lock scoped_lock(mutex);
return add(1);
}
private:
boost::recursive_mutex mutex;
int count;
};
counter c;
void change_count()
{
std::cout << "count == " << c.increment() << std::endl;
}
int main(int, char*[])
{
const int num_threads=4;
boost::thread_group threads;
for (int i=0; i < num_threads; ++i)
threads.create_thread(&change_count);
threads.join_all();
return 0;
}

190
example/starvephil.cpp Normal file
View File

@@ -0,0 +1,190 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#include <time.h>
namespace
{
boost::mutex iomx;
}
class canteen
{
public:
canteen() : m_chickens(0) { }
void get(int id)
{
boost::mutex::scoped_lock lock(m_mutex);
while (m_chickens == 0)
{
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << id <<
": wot, no chickens? I'll WAIT ..." << std::endl;
}
m_condition.wait(lock);
}
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << id <<
": those chickens look good ... one please ..." << std::endl;
}
m_chickens--;
}
void put(int value)
{
boost::mutex::scoped_lock lock(m_mutex);
{
boost::mutex::scoped_lock lock(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);
xt.sec += 3;
boost::thread::sleep(xt);
m_chickens += value;
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() <<
") Chef: more chickens ... " << m_chickens <<
" now available ... NOTIFYING ..." << std::endl;
}
m_condition.notify_all();
}
private:
boost::mutex m_mutex;
boost::condition m_condition;
int m_chickens;
};
canteen g_canteen;
void chef()
{
const int chickens = 4;
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: starting ..." << std::endl;
}
for (;;)
{
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: cooking ..." << std::endl;
}
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 2;
boost::thread::sleep(xt);
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Chef: " << chickens
<< " chickens, ready-to-go ..." << std::endl;
}
g_canteen.put(chickens);
}
}
struct phil
{
phil(int id) : m_id(id) { }
void run() {
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": starting ..." << std::endl;
}
for (;;)
{
if (m_id > 0)
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 3;
boost::thread::sleep(xt);
}
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": gotta eat ..." << std::endl;
}
g_canteen.get(m_id);
{
boost::mutex::scoped_lock lock(iomx);
std::cout << "(" << clock() << ") Phil" << m_id
<< ": mmm ... that's good ..." << std::endl;
}
}
}
static void do_thread(void* param) {
static_cast<phil*>(param)->run();
}
int m_id;
};
struct thread_adapt
{
thread_adapt(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
int operator()() const
{
_func(_param);
return 0;
}
void (*_func)(void*);
void* _param;
};
class thread_adapter
{
public:
thread_adapter(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); }
private:
void (*_func)(void*);
void* _param;
};
int main(int argc, char* argv[])
{
boost::thread thrd_chef(&chef);
phil p[] = { phil(0), phil(1), phil(2), phil(3), phil(4) };
boost::thread thrd_phil0(thread_adapter(&phil::do_thread, &p[0]));
boost::thread thrd_phil1(thread_adapter(&phil::do_thread, &p[1]));
boost::thread thrd_phil2(thread_adapter(&phil::do_thread, &p[2]));
boost::thread thrd_phil3(thread_adapter(&phil::do_thread, &p[3]));
boost::thread thrd_phil4(thread_adapter(&phil::do_thread, &p[4]));
thrd_chef.join();
thrd_phil0.join();
thrd_phil1.join();
thrd_phil2.join();
thrd_phil3.join();
thrd_phil4.join();
return 0;
}

140
example/tennis.cpp Normal file
View File

@@ -0,0 +1,140 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#if defined(BOOST_HAS_WINTHREADS)
# include <windows.h>
# include <process.h>
#endif
enum game_state
{
START,
PLAYER_A,
PLAYER_B,
GAME_OVER,
ONE_PLAYER_GONE,
BOTH_PLAYERS_GONE
};
int state;
boost::mutex mutex;
boost::condition cond;
char* player_name(int state)
{
if (state == PLAYER_A)
return "PLAYER-A";
if (state == PLAYER_B)
return "PLAYER-B";
throw "bad player";
return 0;
}
void player(void* param)
{
boost::mutex::scoped_lock lock(mutex);
int active = (int)param;
int other = active == PLAYER_A ? PLAYER_B : PLAYER_A;
while (state < GAME_OVER)
{
std::cout << player_name(active) << ": Play." << std::endl;
state = other;
cond.notify_all();
do
{
cond.wait(lock);
if (state == other)
{
std::cout << "---" << player_name(active)
<< ": Spurious wakeup!" << std::endl;
}
} while (state == other);
}
++state;
std::cout << player_name(active) << ": Gone." << std::endl;
cond.notify_all();
}
struct thread_adapt
{
thread_adapt(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
int operator()() const
{
_func(_param);
return 0;
}
void (*_func)(void*);
void* _param;
};
class thread_adapter
{
public:
thread_adapter(void (*func)(void*), void* param)
: _func(func), _param(param)
{
}
void operator()() const { _func(_param); }
private:
void (*_func)(void*);
void* _param;
};
int main(int argc, char* argv[])
{
state = START;
boost::thread thrda(thread_adapter(&player, (void*)PLAYER_A));
boost::thread thrdb(thread_adapter(&player, (void*)PLAYER_B));
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt);
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "---Noise ON..." << std::endl;
}
for (int i = 0; i < 1000000; ++i)
cond.notify_all();
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "---Noise OFF..." << std::endl;
state = GAME_OVER;
cond.notify_all();
do
{
cond.wait(lock);
} while (state != BOTH_PLAYERS_GONE);
}
std::cout << "GAME OVER" << std::endl;
thrda.join();
thrdb.join();
return 0;
}

40
example/thread.cpp Normal file
View File

@@ -0,0 +1,40 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
struct thread_alarm
{
thread_alarm(int secs) : m_secs(secs) { }
void operator()()
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += m_secs;
boost::thread::sleep(xt);
std::cout << "alarm sounded..." << std::endl;
}
int m_secs;
};
int main(int argc, char* argv[])
{
int secs = 5;
std::cout << "setting alarm for 5 seconds..." << std::endl;
thread_alarm alarm(secs);
boost::thread thrd(alarm);
thrd.join();
}

30
example/thread_group.cpp Normal file
View File

@@ -0,0 +1,30 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <iostream>
int count = 0;
boost::mutex mutex;
void increment_count()
{
boost::mutex::scoped_lock lock(mutex);
std::cout << "count = " << ++count << std::endl;
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i = 0; i < 10; ++i)
threads.create_thread(&increment_count);
threads.join_all();
}

41
example/tss.cpp Normal file
View File

@@ -0,0 +1,41 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/tss.hpp>
#include <cassert>
boost::thread_specific_ptr<int> value;
void increment()
{
int* p = value.get();
++*p;
}
void thread_proc()
{
value.reset(new int(0)); // initialize the thread's storage
for (int i=0; i<10; ++i)
{
increment();
int* p = value.get();
assert(*p == i+1);
}
}
int main(int argc, char* argv[])
{
boost::thread_group threads;
for (int i=0; i<5; ++i)
threads.create_thread(&thread_proc);
threads.join_all();
}

21
example/xtime.cpp Normal file
View File

@@ -0,0 +1,21 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
int main(int argc, char* argv[])
{
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += 1;
boost::thread::sleep(xt); // Sleep for 1 second
}

View File

@@ -0,0 +1,40 @@
// Copyright (C) 2002-2003
// David Moore, William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_BARRIER_JDM030602_HPP
#define BOOST_BARRIER_JDM030602_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
namespace boost {
class BOOST_THREAD_DECL barrier
{
public:
barrier(unsigned int count);
~barrier();
bool wait();
private:
mutex m_mutex;
condition m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
};
} // namespace boost
#endif

View File

@@ -0,0 +1,198 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_CONDITION_WEK070601_HPP
#define BOOST_CONDITION_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
{
friend class condition;
public:
condition_impl();
~condition_impl();
void notify_one();
void notify_all();
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
void enter_wait();
void do_wait();
bool do_timed_wait(const xtime& xt);
#elif defined(BOOST_HAS_PTHREADS)
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
#endif
#if defined(BOOST_HAS_WINTHREADS)
void* m_gate;
void* m_queue;
void* m_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#elif defined(BOOST_HAS_PTHREADS)
pthread_cond_t m_condition;
#elif defined(BOOST_HAS_MPTASKS)
MPSemaphoreID m_gate;
MPSemaphoreID m_queue;
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#endif
};
} // namespace detail
class condition : private noncopyable
{
public:
condition() { }
~condition() { }
void notify_one() { m_impl.notify_one(); }
void notify_all() { m_impl.notify_all(); }
template <typename L>
void wait(L& lock)
{
if (!lock)
throw lock_error();
do_wait(lock.m_mutex);
}
template <typename L, typename Pr>
void wait(L& lock, Pr pred)
{
if (!lock)
throw lock_error();
while (!pred())
do_wait(lock.m_mutex);
}
template <typename L>
bool timed_wait(L& lock, const xtime& xt)
{
if (!lock)
throw lock_error();
return do_timed_wait(lock.m_mutex, xt);
}
template <typename L, typename Pr>
bool timed_wait(L& lock, const xtime& xt, Pr pred)
{
if (!lock)
throw lock_error();
while (!pred())
{
if (!do_timed_wait(lock.m_mutex, xt))
return false;
}
return true;
}
private:
detail::condition_impl m_impl;
template <typename M>
void do_wait(M& mutex)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
#if defined(BOOST_HAS_PTHREADS)
m_impl.do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.do_wait();
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
}
template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
bool ret = false;
#if defined(BOOST_HAS_PTHREADS)
ret = m_impl.do_timed_wait(xt, state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
ret = m_impl.do_timed_wait(xt);
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
return ret;
}
};
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
// difficult to use with spurious wakeups.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_CONDITION_WEK070601_HPP

View File

@@ -0,0 +1,60 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
#define BOOST_THREAD_CONFIG_WEK01032003_HPP
#include <boost/config.hpp>
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
# define BOOST_THREAD_DECL __declspec(dllexport)
# elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
# define BOOST_THREAD_DECL
# elif defined(BOOST_THREAD_USE_LIB) //Use lib
# define BOOST_THREAD_DECL
# else //Use dll
# define BOOST_THREAD_DECL __declspec(dllimport)
# define BOOST_DYN_LINK
# endif
#else
# define BOOST_THREAD_DECL
# if defined(BOOST_THREAD_USE_LIB) //Use lib
# else //Use dll
# define BOOST_DYN_LINK
# endif
#endif // BOOST_HAS_WINTHREADS
//
// Automatically link to the correct build variant where possible.
//
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
//
// Set the name of our library, this will get undef'ed by auto_link.hpp
// once it's done with it:
//
#if defined(BOOST_THREAD_LIB_NAME)
# define BOOST_LIB_NAME BOOST_THREAD_LIB_NAME
#else
# define BOOST_LIB_NAME boost_thread
#endif
//
// If we're importing code from a dll, then tell auto_link.hpp about it:
//
// And include the header that does the work:
//
#include <boost/config/auto_link.hpp>
#endif // auto-linking disabled
#endif // BOOST_THREAD_CONFIG_WEK1032003_HPP

View File

@@ -0,0 +1,43 @@
// Copyright (C) 2001-2003
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_FORCE_CAST_MJM012402_HPP
#define BOOST_FORCE_CAST_MJM012402_HPP
#include <boost/thread/detail/config.hpp>
namespace boost {
namespace detail {
namespace thread {
// force_cast will convert anything to anything.
// general case
template<class Return_Type, class Argument_Type>
inline Return_Type &force_cast(Argument_Type &rSrc)
{
return(*reinterpret_cast<Return_Type *>(&rSrc));
}
// specialization for const
template<class Return_Type, class Argument_Type>
inline const Return_Type &force_cast(const Argument_Type &rSrc)
{
return(*reinterpret_cast<const Return_Type *>(&rSrc));
}
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_FORCE_CAST_MJM012402_HPP

View File

@@ -0,0 +1,214 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_XLOCK_WEK070601_HPP
#define BOOST_XLOCK_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
namespace boost {
class condition;
struct xtime;
namespace detail { namespace thread {
template <typename Mutex>
class lock_ops : private noncopyable
{
private:
lock_ops() { }
public:
typedef typename Mutex::cv_state lock_state;
static void lock(Mutex& m)
{
m.do_lock();
}
static bool trylock(Mutex& m)
{
return m.do_trylock();
}
static bool timedlock(Mutex& m, const xtime& xt)
{
return m.do_timedlock(xt);
}
static void unlock(Mutex& m)
{
m.do_unlock();
}
static void lock(Mutex& m, lock_state& state)
{
m.do_lock(state);
}
static void unlock(Mutex& m, lock_state& state)
{
m.do_unlock(state);
}
};
template <typename Mutex>
class scoped_lock : private noncopyable
{
public:
typedef Mutex mutex_type;
explicit scoped_lock(Mutex& mx, bool initially_locked=true)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<Mutex>::lock(m_mutex);
m_locked = true;
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<Mutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
Mutex& m_mutex;
bool m_locked;
};
template <typename TryMutex>
class scoped_try_lock : private noncopyable
{
public:
typedef TryMutex mutex_type;
explicit scoped_try_lock(TryMutex& mx)
: m_mutex(mx), m_locked(false)
{
try_lock();
}
scoped_try_lock(TryMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_try_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<TryMutex>::lock(m_mutex);
m_locked = true;
}
bool try_lock()
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TryMutex>::trylock(m_mutex));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TryMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TryMutex& m_mutex;
bool m_locked;
};
template <typename TimedMutex>
class scoped_timed_lock : private noncopyable
{
public:
typedef TimedMutex mutex_type;
scoped_timed_lock(TimedMutex& mx, const xtime& xt)
: m_mutex(mx), m_locked(false)
{
timed_lock(xt);
}
scoped_timed_lock(TimedMutex& mx, bool initially_locked)
: m_mutex(mx), m_locked(false)
{
if (initially_locked) lock();
}
~scoped_timed_lock()
{
if (m_locked) unlock();
}
void lock()
{
if (m_locked) throw lock_error();
lock_ops<TimedMutex>::lock(m_mutex);
m_locked = true;
}
bool try_lock()
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TimedMutex>::trylock(m_mutex));
}
bool timed_lock(const xtime& xt)
{
if (m_locked) throw lock_error();
return (m_locked = lock_ops<TimedMutex>::timedlock(m_mutex, xt));
}
void unlock()
{
if (!m_locked) throw lock_error();
lock_ops<TimedMutex>::unlock(m_mutex);
m_locked = false;
}
bool locked() const { return m_locked; }
operator const void*() const { return m_locked ? this : 0; }
private:
friend class boost::condition;
TimedMutex& m_mutex;
bool m_locked;
};
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_XLOCK_WEK070601_HPP
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 30 Jul 01 WEKEMPF Moved lock types into boost::detail::thread. Renamed
// some types. Added locked() methods.

View File

@@ -0,0 +1,38 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_NAMED_WEK031703_HPP
#define BOOST_NAMED_WEK031703_HPP
#include <boost/thread/detail/config.hpp>
namespace boost {
namespace detail {
class named_object
{
protected:
named_object(const char* name=0);
~named_object();
public:
const char* name() const;
const char* effective_name() const;
protected:
char* m_name;
char* m_ename;
};
} // namespace detail
} // namespace boost
#endif // BOOST_NAMED_WEK031703_HPP

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,63 @@
// Copyright (C) 2001-2003
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_SINGLETON_MJM012402_HPP
#define BOOST_SINGLETON_MJM012402_HPP
#include <boost/thread/detail/config.hpp>
namespace boost {
namespace detail {
namespace thread {
// class singleton has the same goal as all singletons: create one instance of
// a class on demand, then dish it out as requested.
template <class T>
class singleton : private T
{
private:
singleton();
~singleton();
public:
static T &instance();
};
template <class T>
inline singleton<T>::singleton()
{
/* no-op */
}
template <class T>
inline singleton<T>::~singleton()
{
/* no-op */
}
template <class T>
/*static*/ T &singleton<T>::instance()
{
// function-local static to force this to work correctly at static
// initialization time.
static singleton<T> s_oT;
return(s_oT);
}
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_SINGLETON_MJM012402_HPP

View File

@@ -0,0 +1,35 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_THREADMON_WEK062504_HPP
#define BOOST_THREADMON_WEK062504_HPP
#include <boost/thread/detail/config.hpp>
#ifdef BOOST_HAS_WINTHREADS
extern "C" BOOST_THREAD_DECL int at_thread_exit(void (__cdecl * func)(void));
//Add a function to the list of thread-exit functions
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
//To be called when the process starts, when the dll is loaded, etc.
//Called automatically by Boost.Thread when possible
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
//To be called for each thread when it exits
//Must be called in the context of the thread that is exiting
//Called automatically by Boost.Thread when possible
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
//To be called when the process exits, when the dll is unloaded, etc.
//Called automatically by Boost.Thread when possible
#endif // BOOST_HAS_WINTHREADS
#endif // BOOST_THREADMON_WEK062504_HPP

View File

@@ -0,0 +1,100 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_THREAD_EXCEPTIONS_PDM070801_H
#define BOOST_THREAD_EXCEPTIONS_PDM070801_H
#include <boost/thread/detail/config.hpp>
// pdm: Sorry, but this class is used all over the place & I end up
// with recursive headers if I don't separate it
// wek: Not sure why recursive headers would cause compilation problems
// given the include guards, but regardless it makes sense to
// seperate this out any way.
#include <stdexcept>
namespace boost {
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 { return m_sys_err; }
const char* message() const;
private:
int m_sys_err;
};
class BOOST_THREAD_DECL lock_error : public thread_exception
{
public:
lock_error();
lock_error(int sys_err_code);
~lock_error() throw();
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();
virtual const char* what() const throw();
};
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();
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();
virtual const char* what() const throw();
};
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();
};
} // namespace boost
#endif // BOOST_THREAD_CONFIG_PDM070801_H
// Change log:
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -0,0 +1,171 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_MUTEX_WEK070601_HPP
#define BOOST_MUTEX_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/named.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
#if defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
class BOOST_THREAD_DECL mutex
: private noncopyable
, public boost::detail::named_object
{
public:
friend class detail::thread::lock_ops<mutex>;
typedef detail::thread::scoped_lock<mutex> scoped_lock;
mutex(const char* name=0);
~mutex();
private:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
class BOOST_THREAD_DECL try_mutex
: private noncopyable
, public boost::detail::named_object
{
public:
friend class detail::thread::lock_ops<try_mutex>;
typedef detail::thread::scoped_lock<try_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<try_mutex> scoped_try_lock;
try_mutex(const char* name=0);
~try_mutex();
private:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
class BOOST_THREAD_DECL timed_mutex
: private noncopyable
, public boost::detail::named_object
{
public:
friend class detail::thread::lock_ops<timed_mutex>;
typedef detail::thread::scoped_lock<timed_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<timed_mutex> scoped_try_lock;
typedef detail::thread::scoped_timed_lock<timed_mutex> scoped_timed_lock;
timed_mutex(const char* name=0);
~timed_mutex();
private:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
bool do_trylock();
bool do_timedlock(const xtime& xt);
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
bool m_locked;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_MUTEX_WEK070601_HPP

View File

@@ -0,0 +1,42 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_ONCE_WEK080101_HPP
#define BOOST_ONCE_WEK080101_HPP
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
namespace boost {
#if defined(BOOST_HAS_PTHREADS)
typedef pthread_once_t once_flag;
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef long once_flag;
#define BOOST_ONCE_INIT 0
#endif
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
} // namespace boost
// Change Log:
// 1 Aug 01 WEKEMPF Initial version.
#endif // BOOST_ONCE_WEK080101_HPP

View File

@@ -0,0 +1,271 @@
// Copyright (C) 2002-2003
// David Moore, William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. David Moore makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
// A Boost::threads implementation of a synchronization
// primitive which can allow multiple readers or a single
// writer to have access to a shared resource.
#ifndef BOOST_READ_WRITE_MUTEX_JDM030602_HPP
#define BOOST_READ_WRITE_MUTEX_JDM030602_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/read_write_lock.hpp>
#include <boost/thread/condition.hpp>
namespace boost {
namespace read_write_scheduling_policy {
enum read_write_scheduling_policy_enum
{
writer_priority, //Prefer writers; can starve readers
reader_priority, //Prefer readers; can starve writers
alternating_many_reads, //Alternate readers and writers; before a writer, release all queued readers
alternating_single_read //Alternate readers and writers; before a writer, release only on queued reader
};
} // namespace read_write_scheduling_policy
namespace detail {
namespace thread {
// Shared implementation construct for explicit Scheduling Policies
// This implementation is susceptible to self-deadlock, though....
template<typename Mutex>
struct read_write_mutex_impl
{
typedef Mutex mutex_type;
typedef detail::thread::scoped_lock<Mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<Mutex> scoped_try_lock;
typedef detail::thread::scoped_timed_lock<Mutex> scoped_timed_lock;
read_write_mutex_impl(read_write_scheduling_policy::read_write_scheduling_policy_enum sp)
: m_num_waiting_writers(0),
m_num_waiting_readers(0),
m_num_readers_to_wake(0),
m_state_waiting_promotion(false),
m_state(0),
m_sp(sp),
m_readers_next(true) { }
Mutex m_prot;
boost::condition m_waiting_writers;
boost::condition m_waiting_readers;
int m_num_waiting_writers;
int m_num_waiting_readers;
int m_num_readers_to_wake;
boost::condition m_waiting_promotion;
bool m_state_waiting_promotion;
int m_state; // -1 = excl locked
// 0 = unlocked
// 1-> INT_MAX - shared locked
const read_write_scheduling_policy::read_write_scheduling_policy_enum m_sp;
bool m_readers_next;
void do_read_lock();
void do_write_lock();
void do_write_unlock();
void do_read_unlock();
bool do_try_write_lock();
bool do_try_read_lock();
bool do_timed_write_lock(const xtime &xt);
bool do_timed_read_lock(const xtime &xt);
void do_demote_to_read_lock();
bool do_try_demote_to_read_lock();
bool do_timed_demote_to_read_lock(const xtime &xt);
void do_promote_to_write_lock();
bool do_try_promote_to_write_lock();
bool do_timed_promote_to_write_lock(const xtime &xt);
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
private:
void do_unlock_scheduling_impl();
void do_demote_scheduling_impl();
void do_scheduling_impl();
bool do_demote_to_read_lock_impl();
};
} // namespace detail
} // namespace thread
class BOOST_THREAD_DECL read_write_mutex : private noncopyable
{
public:
read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
~read_write_mutex() { }
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
friend class detail::thread::read_write_lock_ops<read_write_mutex>;
typedef detail::thread::scoped_read_write_lock<
read_write_mutex> scoped_read_write_lock;
typedef detail::thread::scoped_read_lock<
read_write_mutex> scoped_read_lock;
typedef detail::thread::scoped_write_lock<
read_write_mutex> scoped_write_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_write_lock();
void do_read_lock();
void do_write_unlock();
void do_read_unlock();
void do_demote_to_read_lock();
void do_promote_to_write_lock();
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
detail::thread::read_write_mutex_impl<mutex> m_impl;
};
class BOOST_THREAD_DECL try_read_write_mutex : private noncopyable
{
public:
try_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
~try_read_write_mutex() { }
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
friend class detail::thread::read_write_lock_ops<try_read_write_mutex>;
typedef detail::thread::scoped_read_write_lock<
try_read_write_mutex> scoped_read_write_lock;
typedef detail::thread::scoped_try_read_write_lock<
try_read_write_mutex> scoped_try_read_write_lock;
typedef detail::thread::scoped_read_lock<
try_read_write_mutex> scoped_read_lock;
typedef detail::thread::scoped_try_read_lock<
try_read_write_mutex> scoped_try_read_lock;
typedef detail::thread::scoped_write_lock<
try_read_write_mutex> scoped_write_lock;
typedef detail::thread::scoped_try_write_lock<
try_read_write_mutex> scoped_try_write_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_write_lock();
void do_read_lock();
void do_write_unlock();
void do_read_unlock();
bool do_try_write_lock();
bool do_try_read_lock();
void do_demote_to_read_lock();
bool do_try_demote_to_read_lock();
void do_promote_to_write_lock();
bool do_try_promote_to_write_lock();
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
detail::thread::read_write_mutex_impl<try_mutex> m_impl;
};
class BOOST_THREAD_DECL timed_read_write_mutex : private noncopyable
{
public:
timed_read_write_mutex(read_write_scheduling_policy::read_write_scheduling_policy_enum sp) : m_impl(sp) { }
~timed_read_write_mutex() { }
read_write_scheduling_policy::read_write_scheduling_policy_enum policy() const { return m_impl.m_sp; }
friend class detail::thread::read_write_lock_ops<timed_read_write_mutex>;
typedef detail::thread::scoped_read_write_lock<
timed_read_write_mutex> scoped_read_write_lock;
typedef detail::thread::scoped_try_read_write_lock<
timed_read_write_mutex> scoped_try_read_write_lock;
typedef detail::thread::scoped_timed_read_write_lock<
timed_read_write_mutex> scoped_timed_read_write_lock;
typedef detail::thread::scoped_read_lock<
timed_read_write_mutex> scoped_read_lock;
typedef detail::thread::scoped_try_read_lock<
timed_read_write_mutex> scoped_try_read_lock;
typedef detail::thread::scoped_timed_read_lock<
timed_read_write_mutex> scoped_timed_read_lock;
typedef detail::thread::scoped_write_lock<
timed_read_write_mutex> scoped_write_lock;
typedef detail::thread::scoped_try_write_lock<
timed_read_write_mutex> scoped_try_write_lock;
typedef detail::thread::scoped_timed_write_lock<
timed_read_write_mutex> scoped_timed_write_lock;
private:
// Operations that will eventually be done only
// via lock types
void do_write_lock();
void do_read_lock();
void do_write_unlock();
void do_read_unlock();
bool do_try_write_lock();
bool do_try_read_lock();
bool do_timed_write_lock(const xtime &xt);
bool do_timed_read_lock(const xtime &xt);
void do_demote_to_read_lock();
bool do_try_demote_to_read_lock();
bool do_timed_demote_to_read_lock(const xtime &xt);
void do_promote_to_write_lock();
bool do_try_promote_to_write_lock();
bool do_timed_promote_to_write_lock(const xtime &xt);
bool locked();
read_write_lock_state::read_write_lock_state_enum state();
detail::thread::read_write_mutex_impl<timed_mutex> m_impl;
};
} // namespace boost
#endif
// Change Log:
// 10 Mar 02
// Original version.
// 4 May 04 GlassfordM
// Implement lock promotion and demotion.
// Add locked() and state() member functions for debugging
// (should these be made public?).
// Rename to improve consistency and eliminate abbreviations:
// Use "read" and "write" instead of "shared" and "exclusive".
// Change "rd" to "read", "wr" to "write", "rw" to "read_write".
// Add mutex_type typdef.

View File

@@ -0,0 +1,186 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#include <boost/thread/detail/named.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#endif
#if defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
class BOOST_THREAD_DECL recursive_mutex
: private noncopyable
, public boost::detail::named_object
{
public:
friend class detail::thread::lock_ops<recursive_mutex>;
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
recursive_mutex(const char* name=0);
~recursive_mutex();
private:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
unsigned m_count;
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
# endif
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
class BOOST_THREAD_DECL recursive_try_mutex
: private noncopyable
, public boost::detail::named_object
{
public:
friend class detail::thread::lock_ops<recursive_try_mutex>;
typedef detail::thread::scoped_lock<recursive_try_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<
recursive_try_mutex> scoped_try_lock;
recursive_try_mutex(const char* name=0);
~recursive_try_mutex();
private:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
unsigned m_count;
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
# endif
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
class BOOST_THREAD_DECL recursive_timed_mutex
: private noncopyable
, public boost::detail::named_object
{
public:
friend class detail::thread::lock_ops<recursive_timed_mutex>;
typedef detail::thread::scoped_lock<recursive_timed_mutex> scoped_lock;
typedef detail::thread::scoped_try_lock<
recursive_timed_mutex> scoped_try_lock;
typedef detail::thread::scoped_timed_lock<
recursive_timed_mutex> scoped_timed_lock;
recursive_timed_mutex(const char* name=0);
~recursive_timed_mutex();
private:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
bool do_trylock();
bool do_timedlock(const xtime& xt);
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
unsigned m_count;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
} // namespace boost
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2002-2003
// William E. Kempf, David Moore
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_MUTEX_JDM062402_HPP
#define BOOST_MUTEX_JDM062402_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/detail/named.hpp>
#include <string>
namespace boost {
class shared_memory : public boost::detail::named_object
{
public:
enum {
write=0x1,
create=0x2,
exclusive=0x4,
};
shared_memory(const char *name, std::size_t len, int flags);
shared_memory(const char *name, std::size_t len, int flags,
const boost::function1<void,void *>& initfunc);
~shared_memory();
void* get() const { return m_ptr; }
private:
void init(std::size_t len, int flags,
const boost::function1<void, void*>* initfunc);
void *m_ptr; // Pointer to shared memory block
#if defined(BOOST_HAS_WINTHREADS)
void* m_hmap;
#elif defined(BOOST_HAS_PTHREADS)
std::size_t m_len;
int m_hmap;
#endif
};
} // namespace boost
#endif

View File

@@ -0,0 +1,193 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_THREAD_WEK070601_HPP
#define BOOST_THREAD_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>
#include <list>
#include <memory>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
# include <boost/thread/condition.hpp>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#endif
namespace boost {
struct xtime;
class BOOST_THREAD_DECL thread_cancel
{
public:
thread_cancel();
~thread_cancel();
};
class BOOST_THREAD_DECL cancellation_guard
{
public:
cancellation_guard();
~cancellation_guard();
private:
void* m_handle;
};
#if defined(BOOST_HAS_WINTHREADS)
struct sched_param
{
int priority;
};
enum { sched_fifo, sched_round_robin, sched_other };
enum { scope_process, scope_system };
#elif defined(BOOST_HAS_PTHREADS)
using ::sched_param;
enum
{
sched_fifo = SCHED_FIFO,
sched_round_robin = SCHED_RR,
sched_other = SCHED_OTHER
};
enum
{
scope_process = PTHREAD_SCOPE_PROCESS,
scope_system = PTHREAD_SCOPE_SYSTEM
};
#endif
class BOOST_THREAD_DECL thread
{
public:
class BOOST_THREAD_DECL attributes
{
public:
attributes();
~attributes();
attributes& set_stack_size(size_t size);
size_t get_stack_size() const;
attributes& set_stack_address(void* addr);
void* get_stack_address() const;
attributes& inherit_scheduling(bool inherit);
bool inherit_scheduling() const;
attributes& set_schedule(int policy, const sched_param& param);
void get_schedule(int& policy, sched_param& param);
attributes& scope(int scope);
int scope() const;
private:
friend class thread;
#if defined(BOOST_HAS_WINTHREADS)
size_t m_stacksize;
bool m_schedinherit;
sched_param m_schedparam;
#elif defined(BOOST_HAS_PTHREADS)
pthread_attr_t m_attr;
#endif
};
thread();
explicit thread(const function0<void>& threadfunc,
const attributes& attr=attributes());
thread(const thread& other);
~thread();
thread& operator=(const thread& other);
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
bool operator<(const thread& other) const;
void join();
bool timed_join(const xtime& xt);
void cancel();
bool cancelled() const;
void set_scheduling_parameter(int policy, const sched_param& param);
void get_scheduling_parameter(int& policy, sched_param& param) const;
static int max_priority(int policy);
static int min_priority(int policy);
static void test_cancel();
static void sleep(const xtime& xt);
static void yield();
static const int stack_min;
#if defined(BOOST_HAS_WINTHREADS)
typedef unsigned int id_type;
#else
typedef const void* id_type;
#endif
id_type id() const;
private:
void* m_handle;
};
template <typename charT, typename Traits>
std::basic_ostream<charT, Traits>& operator<<(
std::basic_ostream<charT, Traits>& os, const thread& thrd)
{
if (!os.good()) return os;
typename std::basic_ostream<charT, Traits>::sentry opfx(os);
if (opfx)
os << thrd.id();
return os;
}
class BOOST_THREAD_DECL thread_group : private noncopyable
{
public:
thread_group();
~thread_group();
thread create_thread(const function0<void>& threadfunc);
void add_thread(thread thrd);
void remove_thread(thread thrd);
// thread* thread_group::find(thread& thrd);
void join_all();
private:
std::list<thread> m_threads;
mutex m_mutex;
};
} // namespace boost
#endif // BOOST_THREAD_WEK070601_HPP
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.

View File

@@ -0,0 +1,44 @@
// Copyright (C) 2002-2003
// David Moore, William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
// Derived loosely from work queue manager in "Programming POSIX Threads"
// by David Butenhof.
#ifndef BOOST_THREAD_POOL_JDM031802_HPP
#define BOOST_THREAD_POOL_JDM031802_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/function.hpp>
#include <boost/limits.hpp>
namespace boost {
class BOOST_THREAD_DECL thread_pool
{
public:
thread_pool(int max_threads=std::numeric_limits<int>::max(),
int min_threads=0, int timeout_secs=5, int timeout_nsecs=0);
~thread_pool();
void add(const boost::function0<void> &job);
void join();
void cancel();
void detach();
private:
class impl;
impl* m_pimpl;
};
} // namespace boost
#endif

View File

@@ -0,0 +1,121 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_TSS_WEK070601_HPP
#define BOOST_TSS_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#endif
namespace boost {
namespace detail {
class BOOST_THREAD_DECL tss : private noncopyable
{
public:
tss(boost::function1<void, void*>* pcleanup) {
if (pcleanup == 0) throw boost::thread_resource_error();
try
{
init(pcleanup);
}
catch (...)
{
delete pcleanup;
throw boost::thread_resource_error();
}
}
void* get() const;
void set(void* value);
void cleanup(void* p);
private:
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
void init(boost::function1<void, void*>* pcleanup);
};
#if defined(BOOST_HAS_MPTASKS)
void thread_cleanup();
#endif
template <typename T>
struct tss_adapter
{
template <typename F>
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
boost::function1<void, T*> m_cleanup;
};
} // namespace detail
template <typename T>
class thread_specific_ptr : private noncopyable
{
public:
thread_specific_ptr()
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(
&thread_specific_ptr<T>::cleanup)))
{
}
thread_specific_ptr(void (*clean)(T*))
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(clean)))
{
}
~thread_specific_ptr() { reset(); }
T* get() const { return static_cast<T*>(m_tss.get()); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
void reset(T* p=0)
{
T* cur = get();
if (cur == p) return;
m_tss.set(p);
if (cur) m_tss.cleanup(cur);
}
private:
static void cleanup(T* p) { delete p; }
detail::tss m_tss;
};
} // namespace boost
#endif //BOOST_TSS_WEK070601_HPP
// Change Log:
// 6 Jun 01
// WEKEMPF Initial version.
// 30 May 02 WEKEMPF
// Added interface to set specific cleanup handlers.
// Removed TLS slot limits from most implementations.
// 22 Mar 04 GlassfordM for WEKEMPF
// Fixed: thread_specific_ptr::reset() doesn't check error returned
// by tss::set(); tss::set() now throws if it fails.
// Fixed: calling thread_specific_ptr::reset() or
// thread_specific_ptr::release() causes double-delete: once on
// reset()/release() and once on ~thread_specific_ptr().

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#ifndef BOOST_XTIME_WEK070601_HPP
#define BOOST_XTIME_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/cstdint.hpp>
namespace boost {
enum xtime_clock_types
{
TIME_UTC=1
// TIME_TAI,
// TIME_MONOTONIC,
// TIME_PROCESS,
// TIME_THREAD,
// TIME_LOCAL,
// TIME_SYNC,
// TIME_RESOLUTION
};
struct xtime
{
#if defined(BOOST_NO_INT64_T)
int_fast32_t sec;
#else
int_fast64_t sec;
#endif
int_fast32_t nsec;
};
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
int res = (int)(xt1.sec - xt2.sec);
if (res == 0)
res = (int)(xt1.nsec - xt2.nsec);
return res;
}
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
#endif // BOOST_XTIME_WEK070601_HPP

8
index.html Normal file
View File

@@ -0,0 +1,8 @@
<html>
<head>
<meta http-equiv="refresh" content="0; URL=doc/index.html">
</head>
<body>
Automatic redirection failed, please go to <a href="doc/index.html">doc/index.html</a>
</body>
</html>

49
src/barrier.cpp Normal file
View File

@@ -0,0 +1,49 @@
// Copyright (C) 2002-2003
// David Moore, William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/detail/config.hpp>
#include <boost/thread/barrier.hpp>
#include <boost/thread/thread.hpp>
namespace boost {
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.");
}
barrier::~barrier()
{
}
bool barrier::wait()
{
boost::mutex::scoped_lock lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
boost::cancellation_guard guard;
while (gen == m_generation)
m_cond.wait(lock);
return false;
}
} // namespace boost

677
src/condition.cpp Normal file
View File

@@ -0,0 +1,677 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/limits.hpp>
#include <cassert>
#include "timeconv.inl"
#if defined(BOOST_HAS_WINTHREADS)
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
#elif defined(BOOST_HAS_PTHREADS)
# include <errno.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h>
# include "mac/init.hpp"
# include "mac/safe.hpp"
#endif
namespace boost {
namespace detail {
#if defined(BOOST_HAS_WINTHREADS)
condition_impl::condition_impl()
: m_gone(0), m_blocked(0), m_waiting(0)
{
m_gate = reinterpret_cast<void*>(CreateSemaphore(0, 1, 1, 0));
m_queue = reinterpret_cast<void*>(
CreateSemaphore(0, 0, (std::numeric_limits<long>::max)(), 0));
m_mutex = reinterpret_cast<void*>(CreateMutex(0, 0, 0));
if (!m_gate || !m_queue || !m_mutex)
{
int res = 0;
if (m_gate)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
assert(res);
}
if (m_queue)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
assert(res);
}
if (m_mutex)
{
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
}
throw thread_resource_error();
}
}
condition_impl::~condition_impl()
{
int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_gate));
assert(res);
res = CloseHandle(reinterpret_cast<HANDLE>(m_queue));
assert(res);
res = CloseHandle(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
}
void condition_impl::notify_one()
{
unsigned signals = 0;
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
return;
}
++m_waiting;
--m_blocked;
signals = 1;
}
else
{
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = 1;
--m_blocked;
}
else
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
if (signals)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
assert(res);
}
}
void condition_impl::notify_all()
{
unsigned signals = 0;
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
return;
}
m_waiting += (signals = m_blocked);
m_blocked = 0;
}
else
{
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = m_blocked;
m_blocked = 0;
}
else
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
if (signals)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_queue), signals, 0);
assert(res);
}
}
void condition_impl::enter_wait()
{
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
++m_blocked;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
void condition_impl::do_wait()
{
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue), INFINITE);
assert(res == WAIT_OBJECT_0);
unsigned was_waiting=0;
unsigned was_gone=0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
assert(res == WAIT_OBJECT_0);
was_waiting = m_waiting;
was_gone = m_gone;
if (was_waiting != 0)
{
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
0); // open m_gate
assert(res);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
}
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
{
// timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
m_blocked -= m_gone;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
m_gone = 0;
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{
// better now than spurious later
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
INFINITE);
assert(res == WAIT_OBJECT_0);
}
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
}
bool condition_impl::do_timed_wait(const xtime& xt)
{
bool ret = false;
unsigned int res = 0;
for (;;)
{
int milliseconds;
to_duration(xt, milliseconds);
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
milliseconds);
assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
ret = (res == WAIT_OBJECT_0);
if (res == WAIT_TIMEOUT)
{
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) > 0)
continue;
}
break;
}
unsigned was_waiting=0;
unsigned was_gone=0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_mutex), INFINITE);
assert(res == WAIT_OBJECT_0);
was_waiting = m_waiting;
was_gone = m_gone;
if (was_waiting != 0)
{
if (!ret) // timeout
{
if (m_blocked != 0)
--m_blocked;
else
++m_gone; // count spurious wakeups
}
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1,
0); // open m_gate
assert(res);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
}
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
{
// timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_gate), INFINITE);
assert(res == WAIT_OBJECT_0);
m_blocked -= m_gone;
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
m_gone = 0;
}
res = ReleaseMutex(reinterpret_cast<HANDLE>(m_mutex));
assert(res);
if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{
// better now than spurious later
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_queue),
INFINITE);
assert(res == WAIT_OBJECT_0);
}
res = ReleaseSemaphore(reinterpret_cast<HANDLE>(m_gate), 1, 0);
assert(res);
}
return ret;
}
#elif defined(BOOST_HAS_PTHREADS)
condition_impl::condition_impl()
{
int res = 0;
res = pthread_cond_init(&m_condition, 0);
if (res != 0)
throw thread_resource_error();
}
condition_impl::~condition_impl()
{
int res = 0;
res = pthread_cond_destroy(&m_condition);
assert(res == 0);
}
void condition_impl::notify_one()
{
int res = 0;
res = pthread_cond_signal(&m_condition);
assert(res == 0);
}
void condition_impl::notify_all()
{
int res = 0;
res = pthread_cond_broadcast(&m_condition);
assert(res == 0);
}
void condition_impl::do_wait(pthread_mutex_t* pmutex)
{
int res = 0;
res = pthread_cond_wait(&m_condition, pmutex);
assert(res == 0);
}
bool condition_impl::do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex)
{
timespec ts;
to_timespec(xt, ts);
int res = 0;
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
assert(res == 0 || res == ETIMEDOUT);
return res != ETIMEDOUT;
}
#elif defined(BOOST_HAS_MPTASKS)
using threads::mac::detail::safe_enter_critical_region;
using threads::mac::detail::safe_wait_on_semaphore;
condition_impl::condition_impl()
: m_gone(0), m_blocked(0), m_waiting(0)
{
threads::mac::detail::thread_init();
OSStatus lStatus = noErr;
lStatus = MPCreateSemaphore(1, 1, &m_gate);
if(lStatus == noErr)
lStatus = MPCreateSemaphore(ULONG_MAX, 0, &m_queue);
if(lStatus != noErr || !m_gate || !m_queue)
{
if (m_gate)
{
lStatus = MPDeleteSemaphore(m_gate);
assert(lStatus == noErr);
}
if (m_queue)
{
lStatus = MPDeleteSemaphore(m_queue);
assert(lStatus == noErr);
}
throw thread_resource_error();
}
}
condition_impl::~condition_impl()
{
OSStatus lStatus = noErr;
lStatus = MPDeleteSemaphore(m_gate);
assert(lStatus == noErr);
lStatus = MPDeleteSemaphore(m_queue);
assert(lStatus == noErr);
}
void condition_impl::notify_one()
{
unsigned signals = 0;
OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
return;
}
++m_waiting;
--m_blocked;
}
else
{
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = 1;
--m_blocked;
}
else
{
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
}
}
void condition_impl::notify_all()
{
unsigned signals = 0;
OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
if (m_waiting != 0) // the m_gate is already closed
{
if (m_blocked == 0)
{
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
return;
}
m_waiting += (signals = m_blocked);
m_blocked = 0;
}
else
{
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
if (m_blocked > m_gone)
{
if (m_gone != 0)
{
m_blocked -= m_gone;
m_gone = 0;
}
signals = m_waiting = m_blocked;
m_blocked = 0;
}
else
{
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
while (signals)
{
lStatus = MPSignalSemaphore(m_queue);
assert(lStatus == noErr);
--signals;
}
}
}
void condition_impl::enter_wait()
{
OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
++m_blocked;
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
void condition_impl::do_wait()
{
OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
unsigned was_waiting=0;
unsigned was_gone=0;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
was_waiting = m_waiting;
was_gone = m_gone;
if (was_waiting != 0)
{
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
lStatus = MPSignalSemaphore(m_gate); // open m_gate
assert(lStatus == noErr);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
}
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
{
// timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
m_blocked -= m_gone;
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
m_gone = 0;
}
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{
// better now than spurious later
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
}
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
}
bool condition_impl::do_timed_wait(const xtime& xt)
{
int milliseconds;
to_duration(xt, milliseconds);
OSStatus lStatus = noErr;
lStatus = safe_wait_on_semaphore(m_queue, milliseconds);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
bool ret = (lStatus == noErr);
unsigned was_waiting=0;
unsigned was_gone=0;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
was_waiting = m_waiting;
was_gone = m_gone;
if (was_waiting != 0)
{
if (!ret) // timeout
{
if (m_blocked != 0)
--m_blocked;
else
++m_gone; // count spurious wakeups
}
if (--m_waiting == 0)
{
if (m_blocked != 0)
{
lStatus = MPSignalSemaphore(m_gate); // open m_gate
assert(lStatus == noErr);
was_waiting = 0;
}
else if (m_gone != 0)
m_gone = 0;
}
}
else if (++m_gone == ((std::numeric_limits<unsigned>::max)() / 2))
{
// timeout occured, normalize the m_gone count
// this may occur if many calls to wait with a timeout are made and
// no call to notify_* is made
lStatus = safe_wait_on_semaphore(m_gate, kDurationForever);
assert(lStatus == noErr);
m_blocked -= m_gone;
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
m_gone = 0;
}
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
if (was_waiting == 1)
{
for (/**/ ; was_gone; --was_gone)
{
// better now than spurious later
lStatus = safe_wait_on_semaphore(m_queue, kDurationForever);
assert(lStatus == noErr);
}
lStatus = MPSignalSemaphore(m_gate);
assert(lStatus == noErr);
}
return ret;
}
#endif
} // namespace detail
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

182
src/exceptions.cpp Normal file
View File

@@ -0,0 +1,182 @@
// Copyright (C) 2001-2003
// William E. Kempf
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. William E. Kempf makes no representations
// about the suitability of this software for any purpose.
// It is provided "as is" without express or implied warranty.
#include <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <cstring>
#include <string>
# ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::strerror; }
# endif
// BOOST_POSIX or BOOST_WINDOWS specify which API to use.
# if !defined( BOOST_WINDOWS ) && !defined( BOOST_POSIX )
# if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)
# define BOOST_WINDOWS
# else
# define BOOST_POSIX
# endif
# endif
# if defined( BOOST_WINDOWS )
# include "windows.h"
# else
# include <errno.h> // for POSIX error codes
# endif
namespace
{
std::string system_message(int sys_err_code)
{
std::string str;
# ifdef BOOST_WINDOWS
LPVOID lpMsgBuf;
::FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
sys_err_code,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPSTR)&lpMsgBuf,
0,
NULL);
str += static_cast<LPCSTR>(lpMsgBuf);
::LocalFree(lpMsgBuf); // free the buffer
while (str.size() && (str[str.size()-1] == '\n' ||
str[str.size()-1] == '\r'))
{
str.erase(str.size()-1);
}
# else
str += std::strerror(errno);
# endif
return str;
}
} // unnamed namespace
namespace boost {
thread_exception::thread_exception()
: m_sys_err(0)
{
}
thread_exception::thread_exception(int sys_err_code)
: m_sys_err(sys_err_code)
{
}
thread_exception::~thread_exception() throw()
{
}
const char* thread_exception::message() const
{
if (m_sys_err != 0)
return system_message(m_sys_err).c_str();
return what();
}
lock_error::lock_error()
{
}
lock_error::lock_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
lock_error::~lock_error() throw()
{
}
const char* lock_error::what() const throw()
{
return "boost::lock_error";
}
thread_resource_error::thread_resource_error()
{
}
thread_resource_error::thread_resource_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
thread_resource_error::~thread_resource_error() throw()
{
}
const char* thread_resource_error::what() const throw()
{
return "boost::thread_resource_error";
}
unsupported_thread_option::unsupported_thread_option()
{
}
unsupported_thread_option::unsupported_thread_option(int sys_err_code)
: thread_exception(sys_err_code)
{
}
unsupported_thread_option::~unsupported_thread_option() throw()
{
}
const char* unsupported_thread_option::what() const throw()
{
return "boost::unsupported_thread_option";
}
invalid_thread_argument::invalid_thread_argument()
{
}
invalid_thread_argument::invalid_thread_argument(int sys_err_code)
: thread_exception(sys_err_code)
{
}
invalid_thread_argument::~invalid_thread_argument() throw()
{
}
const char* invalid_thread_argument::what() const throw()
{
return "boost::invalid_thread_argument";
}
thread_permission_error::thread_permission_error()
{
}
thread_permission_error::thread_permission_error(int sys_err_code)
: thread_exception(sys_err_code)
{
}
thread_permission_error::~thread_permission_error() throw()
{
}
const char* thread_permission_error::what() const throw()
{
return "boost::thread_permission_error";
}
} // namespace boost

14
src/mac/debug_prefix.hpp Normal file
View File

@@ -0,0 +1,14 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#define TARGET_CARBON 1

72
src/mac/delivery_man.cpp Normal file
View File

@@ -0,0 +1,72 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "delivery_man.hpp"
#include "os.hpp"
#include "execution_context.hpp"
namespace boost {
namespace threads {
namespace mac {
namespace detail {
delivery_man::delivery_man():
m_pPackage(NULL),
m_pSemaphore(kInvalidID),
m_bPackageWaiting(false)
{
assert(at_st());
OSStatus lStatus = MPCreateSemaphore(1UL, 0UL, &m_pSemaphore);
// TODO - throw on error here
assert(lStatus == noErr);
}
delivery_man::~delivery_man()
{
assert(m_bPackageWaiting == false);
OSStatus lStatus = MPDeleteSemaphore(m_pSemaphore);
assert(lStatus == noErr);
}
void delivery_man::accept_deliveries()
{
if(m_bPackageWaiting)
{
assert(m_pPackage != NULL);
m_pPackage->accept();
m_pPackage = NULL;
m_bPackageWaiting = false;
// signal to the thread making the call that we're done
OSStatus lStatus = MPSignalSemaphore(m_pSemaphore);
assert(lStatus == noErr);
}
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

90
src/mac/delivery_man.hpp Normal file
View File

@@ -0,0 +1,90 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_DELIVERY_MAN_MJM012402_HPP
#define BOOST_DELIVERY_MAN_MJM012402_HPP
#include <boost/function.hpp>
#include <boost/utility.hpp>
#include <boost/thread/mutex.hpp>
#include "package.hpp"
#include <Multiprocessing.h>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// class delivery_man is intended to move boost::function objects from MP tasks to
// other execution contexts (such as deferred task time or system task time).
class delivery_man: private noncopyable
{
public:
delivery_man();
~delivery_man();
public:
template<class R>
R deliver(function<R> &rFunctor);
void accept_deliveries();
private:
base_package *m_pPackage;
mutex m_oMutex;
MPSemaphoreID m_pSemaphore;
bool m_bPackageWaiting;
};
template<class R>
R delivery_man::deliver(function<R> &rFunctor)
{
assert(at_mp());
// lock our mutex
mutex::scoped_lock oLock(m_oMutex);
// create a package and save it
package<R> oPackage(rFunctor);
m_pPackage = &oPackage;
m_bPackageWaiting = true;
// wait on the semaphore
OSStatus lStatus = MPWaitOnSemaphore(m_pSemaphore, kDurationForever);
assert(lStatus == noErr);
return(oPackage.return_value());
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_DELIVERY_MAN_MJM012402_HPP

99
src/mac/dt_scheduler.cpp Normal file
View File

@@ -0,0 +1,99 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "dt_scheduler.hpp"
#include "ot_context.hpp"
#include <boost/thread/detail/singleton.hpp>
#include <OpenTransportProtocol.h>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
const OTTimeout k_ulTimerTaskDelay = 1UL;
dt_scheduler::dt_scheduler():
m_bReschedule(false),
m_uppTask(NULL),
m_lTask(0UL)
{
using ::boost::detail::thread::singleton;
ot_context &rContext(singleton<ot_context>::instance());
m_uppTask = NewOTProcessUPP(task_entry);
m_lTask = OTCreateTimerTaskInContext(m_uppTask, this, rContext.get_context());
}
dt_scheduler::~dt_scheduler()
{
OTDestroyTimerTask(m_lTask);
m_lTask = 0UL;
DisposeOTProcessUPP(m_uppTask);
m_uppTask = NULL;
}
void dt_scheduler::start_polling()
{
m_bReschedule = true;
schedule_task();
}
void dt_scheduler::stop_polling()
{
m_bReschedule = false;
}
void dt_scheduler::schedule_task()
{
if(m_bReschedule)
{
OTScheduleTimerTask(m_lTask, k_ulTimerTaskDelay);
}
}
/*static*/ pascal void dt_scheduler::task_entry(void *pRefCon)
{
dt_scheduler *pThis = reinterpret_cast<dt_scheduler *>(pRefCon);
assert(pThis != NULL);
pThis->task();
}
void dt_scheduler::task()
{
periodic_function();
schedule_task();
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

69
src/mac/dt_scheduler.hpp Normal file
View File

@@ -0,0 +1,69 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_DT_SCHEDULER_MJM012402_HPP
#define BOOST_DT_SCHEDULER_MJM012402_HPP
#include "periodical.hpp"
#include <OpenTransport.h>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// class dt_scheduler calls its pure-virtual periodic_function method periodically at
// deferred task time. This is generally 1kHz under Mac OS 9.
class dt_scheduler
{
public:
dt_scheduler();
virtual ~dt_scheduler();
protected:
void start_polling();
void stop_polling();
private:
virtual void periodic_function() = 0;
private:
void schedule_task();
static pascal void task_entry(void *pRefCon);
void task();
private:
bool m_bReschedule;
OTProcessUPP m_uppTask;
long m_lTask;
};
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_DT_SCHEDULER_MJM012402_HPP

View File

@@ -0,0 +1,66 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include <Debugging.h>
#include <Multiprocessing.h>
#include "execution_context.hpp"
#include "init.hpp"
namespace boost {
namespace threads {
namespace mac {
execution_context_t execution_context()
{
// make sure that MP services are available the first time through
static bool bIgnored = detail::thread_init();
// first check if we're an MP task
if(MPTaskIsPreemptive(kInvalidID))
{
return(k_eExecutionContextMPTask);
}
#if TARGET_CARBON
// Carbon has TaskLevel
UInt32 ulLevel = TaskLevel();
if(ulLevel == 0UL)
{
return(k_eExecutionContextSystemTask);
}
if(ulLevel & kInDeferredTaskMask)
{
return(k_eExecutionContextDeferredTask);
}
return(k_eExecutionContextOther);
#else
// this can be implemented using TaskLevel if you don't mind linking against
// DebugLib (and therefore breaking Mac OS 8.6 support), or CurrentExecutionLevel.
# error execution_context unimplimented
#endif
}
} // namespace mac
} // namespace threads
} // namespace boost

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_EXECUTION_CONTEXT_MJM012402_HPP
#define BOOST_EXECUTION_CONTEXT_MJM012402_HPP
namespace boost {
namespace threads {
namespace mac {
// utility functions for figuring out what context your code is executing in.
// Bear in mind that at_mp and in_blue are the only functions guarenteed by
// Apple to work. There is simply no way of being sure that you will not get
// false readings about task level at interrupt time in blue.
typedef enum {
k_eExecutionContextSystemTask,
k_eExecutionContextDeferredTask,
k_eExecutionContextMPTask,
k_eExecutionContextOther
} execution_context_t;
execution_context_t execution_context();
inline bool at_st()
{ return(execution_context() == k_eExecutionContextSystemTask); }
inline bool at_mp()
{ return(execution_context() == k_eExecutionContextMPTask); }
inline bool in_blue()
{ return(!at_mp()); }
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_EXECUTION_CONTEXT_MJM012402_HPP

64
src/mac/init.cpp Normal file
View File

@@ -0,0 +1,64 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "init.hpp"
#include "remote_call_manager.hpp"
#include <boost/thread/detail/singleton.hpp>
#include <Multiprocessing.h>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
namespace {
// force these to get called by the end of static initialization time.
static bool g_bInitialized = (thread_init() && create_singletons());
}
bool thread_init()
{
static bool bResult = MPLibraryIsLoaded();
return(bResult);
}
bool create_singletons()
{
using ::boost::detail::thread::singleton;
singleton<remote_call_manager>::instance();
return(true);
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

40
src/mac/init.hpp Normal file
View File

@@ -0,0 +1,40 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_INIT_MJM012402_HPP
#define BOOST_INIT_MJM012402_HPP
namespace boost {
namespace threads {
namespace mac {
namespace detail {
bool thread_init();
bool create_singletons();
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_INIT_MJM012402_HPP

View File

@@ -0,0 +1,30 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include <cassert>
#include <cstdio>
#include <MacTypes.h>
#include "remote_calls.hpp"
// this function will be called when an assertion fails. We redirect the assertion
// to DebugStr (MacsBug under Mac OS 1.x-9.x, Console under Mac OS X).
void __assertion_failed(char const *pszAssertion, char const *pszFile, int nLine)
{
using std::snprintf;
unsigned char strlDebug[sizeof(Str255) + 1];
char *pszDebug = reinterpret_cast<char *>(&strlDebug[1]);
strlDebug[0] = snprintf(pszDebug, sizeof(Str255), "assertion failed: \"%s\", %s, line %d", pszAssertion, pszFile, nLine);
boost::threads::mac::dt_remote_call(DebugStr, static_cast<ConstStringPtr>(strlDebug));
}

View File

@@ -0,0 +1,134 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
//
// includes
//
#include <abort_exit.h>
#include <console.h>
#include <console_io.h>
#include <misc_io.h>
#include <SIOUX.h>
#include "remote_calls.hpp"
//
// using declarations
//
using std::__file_handle;
using std::__idle_proc;
using std::__io_error;
using std::__no_io_error;
using std::size_t;
using boost::threads::mac::st_remote_call;
//
// prototypes
//
static bool check_console();
static int do_read_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
static int do_write_console(__file_handle ulHandle, unsigned char *pBuffer, size_t *pCount, __idle_proc pfnIdleProc);
//
// MSL function replacements
//
// these two functions are called by cin and cout, respectively, as well as by (all?)
// other functions in MSL that do console I/O. All that they do is as the remote
// call manager to ensure that their guts are called at system task time.
int __read_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
{
return(st_remote_call(do_read_console, handle, buffer, count, idle_proc));
}
int __write_console(__file_handle handle, unsigned char * buffer, size_t * count, __idle_proc idle_proc)
{
return(st_remote_call(do_write_console, handle, buffer, count, idle_proc));
}
//
// implementations
//
static bool check_console()
{
static bool s_bHaveConsole(false);
static bool s_bWontHaveConsole(false);
if(s_bHaveConsole)
{
return(true);
}
if(s_bWontHaveConsole == false)
{
__stdio_atexit();
if(InstallConsole(0) != 0)
{
s_bWontHaveConsole = true;
return(false);
}
__console_exit = RemoveConsole;
s_bHaveConsole = true;
return(true);
}
return(false);
}
int do_read_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
{
assert(pCount != NULL);
assert(pBuffer != NULL || *pCount == 0UL);
if(check_console() == false)
{
return(__io_error);
}
std::fflush(stdout);
long lCount = ReadCharsFromConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
*pCount = static_cast<size_t>(lCount);
if(lCount == -1L)
{
return(__io_error);
}
return(__no_io_error);
}
int do_write_console(__file_handle /*ulHandle*/, unsigned char *pBuffer, size_t *pCount, __idle_proc /*pfnIdleProc*/)
{
if(check_console() == false)
{
return(__io_error);
}
long lCount = WriteCharsToConsole(reinterpret_cast<char *>(pBuffer), static_cast<long>(*pCount));
*pCount = static_cast<size_t>(lCount);
if(lCount == -1L)
{
return(__io_error);
}
return(__no_io_error);
}

View File

@@ -0,0 +1,58 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
//
// includes
//
#include <cstdlib>
#include <Multiprocessing.h>
//
// using declarations
//
using std::size_t;
extern "C" {
//
// prototypes
//
void *malloc(size_t ulSize);
void free(void *pBlock);
}
//
// MSL function replacements
//
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
// solution is sub-optimal at best, but will have to do for now.
void *malloc(size_t ulSize)
{
static bool bIgnored = MPLibraryIsLoaded();
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
}
void free(void *pBlock)
{
if(pBlock == NULL) return;
MPFree(pBlock);
}

View File

@@ -0,0 +1,105 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
//
// includes
//
#include <new>
#include <Multiprocessing.h>
//
// using declarations
//
using std::size_t;
using std::bad_alloc;
using std::nothrow_t;
using std::nothrow;
//
// local utility functions
//
// all allocation/deallocation currently goes through MPAllocateAligned/MPFree. This
// solution is sub-optimal at best, but will have to do for now.
inline static void *allocate(size_t ulSize, const nothrow_t &)
{
static bool bIgnored = MPLibraryIsLoaded();
return(MPAllocateAligned(ulSize, kMPAllocateDefaultAligned, 0UL));
}
inline static void *allocate(size_t ulSize)
{
void *pBlock = allocate(ulSize, nothrow);
if(pBlock == NULL)
throw(bad_alloc());
return(pBlock);
}
inline static void deallocate(void *pBlock)
{
if(pBlock == NULL) return;
MPFree(pBlock);
}
//
// global operators
//
void *operator new(size_t ulSize)
{
return(allocate(ulSize));
}
void *operator new[](size_t ulSize)
{
return(allocate(ulSize));
}
void *operator new(size_t ulSize, const nothrow_t &rNoThrow)
{
return(allocate(ulSize, rNoThrow));
}
void *operator new[](size_t ulSize, const nothrow_t &rNoThrow)
{
return(allocate(ulSize, rNoThrow));
}
void operator delete(void *pBlock)
{
deallocate(pBlock);
}
void operator delete[](void *pBlock)
{
deallocate(pBlock);
}
void operator delete(void *pBlock, const nothrow_t &)
{
deallocate(pBlock);
}
void operator delete[](void *pBlock, const nothrow_t &)
{
deallocate(pBlock);
}

View File

@@ -0,0 +1,156 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include <cassert>
// we include timesize.mac.h to get whether or not __TIMESIZE_DOUBLE__ is
// defined. This is not safe, given that __TIMESIZE_DOUBLE__ affects MSL
// at MSL's compile time, not ours, so be forgiving if you have changed it
// since you have built MSL.
#include <timesize.mac.h>
#include <time.h>
#include <boost/thread/detail/force_cast.hpp>
#include <boost/thread/xtime.hpp>
#include "execution_context.hpp"
#include <DriverServices.h>
extern "C"
{
clock_t __get_clock();
time_t __get_time();
int __to_gm_time(time_t *pTime);
int __is_dst();
}
static inline uint64_t get_nanoseconds()
{
using boost::detail::thread::force_cast;
return(force_cast<uint64_t>(AbsoluteToNanoseconds(UpTime())));
}
#ifdef __TIMESIZE_DOUBLE__
// return number of microseconds since startup as a double
clock_t __get_clock()
{
static const double k_dNanosecondsPerMicrosecond(1000.0);
return(get_nanoseconds() / k_dNanosecondsPerMicrosecond);
}
#else
// return number of ticks (60th of a second) since startup as a long
clock_t __get_clock()
{
static const uint64_t k_ullTicksPerSecond(60ULL);
static const uint64_t k_ullNanosecondsPerSecond(1000ULL * 1000ULL * 1000ULL);
static const uint64_t k_ullNanosecondsPerTick(k_ullNanosecondsPerSecond / k_ullTicksPerSecond);
return(get_nanoseconds() / k_ullNanosecondsPerTick);
}
#endif
// return number of seconds elapsed since Jan 1, 1970
time_t __get_time()
{
boost::xtime sTime;
int nType = boost::xtime_get(&sTime, boost::TIME_UTC);
assert(nType == boost::TIME_UTC);
return(static_cast<time_t>(sTime.sec));
}
static inline MachineLocation &read_location()
{
static MachineLocation s_sLocation;
assert(boost::threads::mac::at_st());
ReadLocation(&s_sLocation);
return(s_sLocation);
}
static inline MachineLocation &get_location()
{
static MachineLocation &s_rLocation(read_location());
return(s_rLocation);
}
// force the machine location to be cached at static initlialization
static MachineLocation &g_rIgnored(get_location());
static inline long calculate_delta()
{
MachineLocation &rLocation(get_location());
// gmtDelta is a 24-bit, signed integer. We need to strip out the lower 24 bits,
// then sign-extend what we have.
long lDelta = rLocation.u.gmtDelta & 0x00ffffffL;
if((lDelta & 0x00800000L) != 0L)
{
lDelta |= 0xFF000000;
}
return(lDelta);
}
static inline bool check_if_location_is_broken()
{
MachineLocation &rLocation(get_location());
if(rLocation.latitude == 0 && rLocation.longitude == 0 && rLocation.u.gmtDelta == 0)
return(true);
return(false);
}
static inline bool location_is_broken()
{
static bool s_bLocationIsBroken(check_if_location_is_broken());
return(s_bLocationIsBroken);
}
// translate time to GMT
int __to_gm_time(time_t *pTime)
{
if(location_is_broken())
{
return(0);
}
static long s_lDelta(calculate_delta());
*pTime -= s_lDelta;
return(1);
}
static inline bool is_daylight_savings_time()
{
MachineLocation &rLocation(get_location());
return(rLocation.u.dlsDelta != 0);
}
// check if we're in daylight savings time
int __is_dst()
{
if(location_is_broken())
{
return(-1);
}
static bool bIsDaylightSavingsTime(is_daylight_savings_time());
return(static_cast<int>(bIsDaylightSavingsTime));
}

63
src/mac/os.cpp Normal file
View File

@@ -0,0 +1,63 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "os.hpp"
#include <cassert>
#include <Gestalt.h>
namespace boost {
namespace threads {
namespace mac {
namespace os {
// read the OS version from Gestalt
static inline long get_version()
{
long lVersion;
OSErr nErr = Gestalt(gestaltSystemVersion, &lVersion);
assert(nErr == noErr);
return(lVersion);
}
// check if we're running under Mac OS X and cache that information
bool x()
{
static bool bX = (version() >= 0x1000);
return(bX);
}
// read the OS version and cache it
long version()
{
static long lVersion = get_version();
return(lVersion);
}
} // namespace os
} // namespace mac
} // namespace threads
} // namespace boost

43
src/mac/os.hpp Normal file
View File

@@ -0,0 +1,43 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_OS_MJM012402_HPP
#define BOOST_OS_MJM012402_HPP
namespace boost {
namespace threads {
namespace mac {
namespace os {
// functions to determine the OS environment. With namespaces, you get a cute call:
// mac::os::x
bool x();
long version();
} // namespace os
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_OS_MJM012402_HPP

52
src/mac/ot_context.cpp Normal file
View File

@@ -0,0 +1,52 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "ot_context.hpp"
#include "execution_context.hpp"
#include <cassert>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
ot_context::ot_context()
{
assert(at_st());
OSStatus lStatus = InitOpenTransportInContext(0UL, &m_pContext);
// TODO - throw on error
assert(lStatus == noErr);
}
ot_context::~ot_context()
{
CloseOpenTransportInContext(m_pContext);
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

64
src/mac/ot_context.hpp Normal file
View File

@@ -0,0 +1,64 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_OT_CONTEXT_MJM012402_HPP
#define BOOST_OT_CONTEXT_MJM012402_HPP
#include <OpenTransport.h>
#include <boost/utility.hpp>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// class ot_context is intended to be used only as a singleton. All that this class
// does is ask OpenTransport to create him an OTClientContextPtr, and then doles
// this out to anyone who wants it. ot_context should only be instantiated at
// system task time.
class ot_context: private noncopyable
{
protected:
ot_context();
~ot_context();
public:
OTClientContextPtr get_context();
private:
OTClientContextPtr m_pContext;
};
inline OTClientContextPtr ot_context::get_context()
{ return(m_pContext); }
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_OT_CONTEXT_MJM012402_HPP

82
src/mac/package.hpp Normal file
View File

@@ -0,0 +1,82 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_PACKAGE_MJM012402_HPP
#define BOOST_PACKAGE_MJM012402_HPP
namespace boost {
namespace threads {
namespace mac {
namespace detail {
class base_package: private noncopyable
{
public:
virtual void accept() = 0;
};
template<class R>
class package: public base_package
{
public:
inline package(function<R> &rFunctor):
m_rFunctor(rFunctor)
{ /* no-op */ }
inline ~package()
{ /* no-op */ }
virtual void accept()
{ m_oR = m_rFunctor(); }
inline R return_value()
{ return(m_oR); }
private:
function<R> &m_rFunctor;
R m_oR;
};
template<>
class package<void>: public base_package
{
public:
inline package(function<void> &rFunctor):
m_rFunctor(rFunctor)
{ /* no-op */ }
inline ~package()
{ /* no-op */ }
virtual void accept()
{ m_rFunctor(); }
inline void return_value()
{ return; }
private:
function<void> &m_rFunctor;
};
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_PACKAGE_MJM012402_HPP

103
src/mac/periodical.hpp Normal file
View File

@@ -0,0 +1,103 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_PERIODICAL_MJM012402_HPP
#define BOOST_PERIODICAL_MJM012402_HPP
#include <boost/function.hpp>
#include <boost/utility.hpp>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// class periodical inherits from its template parameter, which should follow the
// pattern set by classes dt_scheduler and st_scheduler. periodical knows how to
// call a boost::function, where the xx_scheduler classes only know to to call a
// member periodically.
template<class Scheduler>
class periodical: private noncopyable, private Scheduler
{
public:
periodical(function<void> &rFunction);
~periodical();
public:
void start();
void stop();
protected:
virtual void periodic_function();
private:
function<void> m_oFunction;
};
template<class Scheduler>
periodical<Scheduler>::periodical(function<void> &rFunction):
m_oFunction(rFunction)
{
// no-op
}
template<class Scheduler>
periodical<Scheduler>::~periodical()
{
stop();
}
template<class Scheduler>
void periodical<Scheduler>::start()
{
start_polling();
}
template<class Scheduler>
void periodical<Scheduler>::stop()
{
stop_polling();
}
template<class Scheduler>
inline void periodical<Scheduler>::periodic_function()
{
try
{
m_oFunction();
}
catch(...)
{
}
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_PERIODICAL_MJM012402_HPP

15
src/mac/prefix.hpp Normal file
View File

@@ -0,0 +1,15 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#define NDEBUG
#define TARGET_CARBON 1

View File

@@ -0,0 +1,54 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "remote_call_manager.hpp"
#include <boost/bind.hpp>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
using detail::delivery_man;
remote_call_manager::remote_call_manager():
m_oDTDeliveryMan(),
m_oSTDeliveryMan(),
m_oDTFunction(bind(&delivery_man::accept_deliveries, &m_oDTDeliveryMan)),
m_oSTFunction(bind(&delivery_man::accept_deliveries, &m_oSTDeliveryMan)),
m_oDTPeriodical(m_oDTFunction),
m_oSTPeriodical(m_oSTFunction)
{
m_oDTPeriodical.start();
m_oSTPeriodical.start();
}
remote_call_manager::~remote_call_manager()
{
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

View File

@@ -0,0 +1,108 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
#define BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP
#include <boost/utility.hpp>
#include "delivery_man.hpp"
#include "dt_scheduler.hpp"
#include "periodical.hpp"
#include "execution_context.hpp"
#include "st_scheduler.hpp"
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// class remote_call_manager is used by the remote call functions (dt_remote_call and
// st_remote_call) to execute functions in non-MP contexts.
class remote_call_manager: private noncopyable
{
protected:
remote_call_manager();
~remote_call_manager();
public:
template<class R>
R execute_at_dt(function<R> &rFunctor);
template<class R>
R execute_at_st(function<R> &rFunctor);
private:
template<class R>
static R execute_now(function<R> &rFunctor);
private:
delivery_man m_oDTDeliveryMan;
delivery_man m_oSTDeliveryMan;
function<void> m_oDTFunction;
function<void> m_oSTFunction;
periodical<dt_scheduler> m_oDTPeriodical;
periodical<st_scheduler> m_oSTPeriodical;
};
template<class R>
/*static*/ inline R remote_call_manager::execute_now(function<R> &rFunctor)
{
return(rFunctor());
}
template<>
/*static*/ inline void remote_call_manager::execute_now<void>(function<void> &rFunctor)
{
rFunctor();
}
template<class R>
inline R remote_call_manager::execute_at_dt(function<R> &rFunctor)
{
if(at_mp())
{
return(m_oDTDeliveryMan.deliver(rFunctor));
}
return(execute_now(rFunctor));
}
template<class R>
inline R remote_call_manager::execute_at_st(function<R> &rFunctor)
{
if(at_mp())
{
return(m_oSTDeliveryMan.deliver(rFunctor));
}
assert(at_st());
return(execute_now(rFunctor));
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_REMOTE_CALL_MANAGER_MJM012402_HPP

163
src/mac/remote_calls.hpp Normal file
View File

@@ -0,0 +1,163 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_REMOTE_CALLS_MJM012402_HPP
#define BOOST_REMOTE_CALLS_MJM012402_HPP
#include <boost/bind.hpp>
#include "remote_call_manager.hpp"
#include <boost/thread/detail/singleton.hpp>
// this file contains macros to generate functions with the signatures:
// ReturnType st_remote_call([pascal] ReturnType (*pfnFunction)(
// [Argument1Type[, Argument2Type[...]]])
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
// and
// ReturnType dt_remote_call([pascal] ReturnType (*pfnFunction)(
// [Argument1Type[, Argument2Type[...]]])
// [, Argument1Type oArgument1[, Argument2Type oArgument2[...]]])
// in other words, identical to the function pointer versions of boost::bind, but
// with the return type returned. The purpose of these functions is to be able to
// request that a function be called at system task time or deferred task time, then
// sleep until it is called, and finally get back its return value.
#define BOOST_REMOTE_CALL_CLASS_LIST_0
#define BOOST_REMOTE_CALL_CLASS_LIST_1 BOOST_REMOTE_CALL_CLASS_LIST_0, class A1
#define BOOST_REMOTE_CALL_CLASS_LIST_2 BOOST_REMOTE_CALL_CLASS_LIST_1, class A2
#define BOOST_REMOTE_CALL_CLASS_LIST_3 BOOST_REMOTE_CALL_CLASS_LIST_2, class A3
#define BOOST_REMOTE_CALL_CLASS_LIST_4 BOOST_REMOTE_CALL_CLASS_LIST_3, class A4
#define BOOST_REMOTE_CALL_CLASS_LIST_5 BOOST_REMOTE_CALL_CLASS_LIST_4, class A5
#define BOOST_REMOTE_CALL_CLASS_LIST_6 BOOST_REMOTE_CALL_CLASS_LIST_5, class A6
#define BOOST_REMOTE_CALL_CLASS_LIST_7 BOOST_REMOTE_CALL_CLASS_LIST_6, class A7
#define BOOST_REMOTE_CALL_CLASS_LIST_8 BOOST_REMOTE_CALL_CLASS_LIST_7, class A8
#define BOOST_REMOTE_CALL_CLASS_LIST_9 BOOST_REMOTE_CALL_CLASS_LIST_8, class A9
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_0
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_ARGUMENT_LIST_0 A1 oA1
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_ARGUMENT_LIST_1, A2 oA2
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_ARGUMENT_LIST_2, A3 oA3
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_ARGUMENT_LIST_3, A4 oA4
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_ARGUMENT_LIST_4, A5 oA5
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_ARGUMENT_LIST_5, A6 oA6
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_ARGUMENT_LIST_6, A7 oA7
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_ARGUMENT_LIST_7, A8 oA8
#define BOOST_REMOTE_CALL_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_ARGUMENT_LIST_8, A9 oA9
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_0, oA1
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_1, oA2
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_2, oA3
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_3, oA4
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_4, oA5
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_5, oA6
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_6, oA7
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_7, oA8
#define BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_9 BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_8, oA9
#define BOOST_REMOTE_CALL_COMMA_0
#define BOOST_REMOTE_CALL_COMMA_1 ,
#define BOOST_REMOTE_CALL_COMMA_2 ,
#define BOOST_REMOTE_CALL_COMMA_3 ,
#define BOOST_REMOTE_CALL_COMMA_4 ,
#define BOOST_REMOTE_CALL_COMMA_5 ,
#define BOOST_REMOTE_CALL_COMMA_6 ,
#define BOOST_REMOTE_CALL_COMMA_7 ,
#define BOOST_REMOTE_CALL_COMMA_8 ,
#define BOOST_REMOTE_CALL_COMMA_9 ,
// this is the macro that ties it all together. From here, we generate all forms of
// dt_remote_call and st_remote_call.
#define BOOST_REMOTE_CALL(context, stack, n) \
template<class R BOOST_REMOTE_CALL_CLASS_LIST_ ## n> \
inline R context ## _remote_call(stack R (*pfnF)( \
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
BOOST_REMOTE_CALL_COMMA_ ## n \
BOOST_REMOTE_CALL_ARGUMENT_LIST_ ## n) \
{ \
using ::boost::detail::thread::singleton; \
using detail::remote_call_manager; \
function<R> oFunc(bind(pfnF BOOST_REMOTE_CALL_FUNCTION_ARGUMENT_LIST_ ## n)); \
remote_call_manager &rManager(singleton<remote_call_manager>::instance()); \
return(rManager.execute_at_ ## context(oFunc)); \
}
namespace boost {
namespace threads {
namespace mac {
BOOST_REMOTE_CALL(st, , 0)
BOOST_REMOTE_CALL(st, , 1)
BOOST_REMOTE_CALL(st, , 2)
BOOST_REMOTE_CALL(st, , 3)
BOOST_REMOTE_CALL(st, , 4)
BOOST_REMOTE_CALL(st, , 5)
BOOST_REMOTE_CALL(st, , 6)
BOOST_REMOTE_CALL(st, , 7)
BOOST_REMOTE_CALL(st, , 8)
BOOST_REMOTE_CALL(st, , 9)
BOOST_REMOTE_CALL(dt, , 0)
BOOST_REMOTE_CALL(dt, , 1)
BOOST_REMOTE_CALL(dt, , 2)
BOOST_REMOTE_CALL(dt, , 3)
BOOST_REMOTE_CALL(dt, , 4)
BOOST_REMOTE_CALL(dt, , 5)
BOOST_REMOTE_CALL(dt, , 6)
BOOST_REMOTE_CALL(dt, , 7)
BOOST_REMOTE_CALL(dt, , 8)
BOOST_REMOTE_CALL(dt, , 9)
BOOST_REMOTE_CALL(st, pascal, 0)
BOOST_REMOTE_CALL(st, pascal, 1)
BOOST_REMOTE_CALL(st, pascal, 2)
BOOST_REMOTE_CALL(st, pascal, 3)
BOOST_REMOTE_CALL(st, pascal, 4)
BOOST_REMOTE_CALL(st, pascal, 5)
BOOST_REMOTE_CALL(st, pascal, 6)
BOOST_REMOTE_CALL(st, pascal, 7)
BOOST_REMOTE_CALL(st, pascal, 8)
BOOST_REMOTE_CALL(st, pascal, 9)
BOOST_REMOTE_CALL(dt, pascal, 0)
BOOST_REMOTE_CALL(dt, pascal, 1)
BOOST_REMOTE_CALL(dt, pascal, 2)
BOOST_REMOTE_CALL(dt, pascal, 3)
BOOST_REMOTE_CALL(dt, pascal, 4)
BOOST_REMOTE_CALL(dt, pascal, 5)
BOOST_REMOTE_CALL(dt, pascal, 6)
BOOST_REMOTE_CALL(dt, pascal, 7)
BOOST_REMOTE_CALL(dt, pascal, 8)
BOOST_REMOTE_CALL(dt, pascal, 9)
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_REMOTE_CALLS_MJM012402_HPP

216
src/mac/safe.cpp Normal file
View File

@@ -0,0 +1,216 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include <DriverServices.h>
#include <Events.h>
#include <Multiprocessing.h>
#include <Threads.h>
#include <boost/bind.hpp>
#include <boost/function.hpp>
#include <boost/thread/detail/force_cast.hpp>
#include <limits>
#include "execution_context.hpp"
using boost::detail::thread::force_cast;
namespace boost {
namespace threads {
namespace mac {
namespace detail {
static OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration);
// we call WNE to allow tasks that own the resource the blue is waiting on system
// task time, in case they are blocked on an ST remote call (or a memory allocation
// for that matter).
static void idle()
{
if(at_st())
{
EventRecord sEvent;
bool bEvent = WaitNextEvent(0U, &sEvent, 0UL, NULL);
}
}
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration)
{
function<OSStatus, Duration> oWaitOnSemaphore;
oWaitOnSemaphore = bind(MPWaitOnSemaphore, pSemaphoreID, _1);
return(safe_wait(oWaitOnSemaphore, lDuration));
}
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID/* = kInvalidID*/)
{
if(pCriticalRegionCriticalRegionID != kInvalidID)
{
if(at_mp())
{
// enter the critical region's critical region
OSStatus lStatus = noErr;
AbsoluteTime sExpiration;
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
{
sExpiration = AddDurationToAbsolute(lDuration, UpTime());
}
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, lDuration);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
if(lStatus == noErr)
{
// calculate a new duration
if(lDuration != kDurationImmediate && lDuration != kDurationForever)
{
// check if we have any time left
AbsoluteTime sUpTime(UpTime());
if(force_cast<uint64_t>(sExpiration) > force_cast<uint64_t>(sUpTime))
{
// reset our duration to our remaining time
lDuration = AbsoluteDeltaToDuration(sExpiration, sUpTime);
}
else
{
// no time left
lDuration = kDurationImmediate;
}
}
// if we entered the critical region, exit it again
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
assert(lStatus == noErr);
}
else
{
// otherwise, give up
return(lStatus);
}
}
else
{
// if we're at system task time, try to enter the critical region's critical
// region until we succeed. MP tasks will block on this until we let it go.
OSStatus lStatus;
do
{
lStatus = MPEnterCriticalRegion(pCriticalRegionCriticalRegionID, kDurationImmediate);
} while(lStatus == kMPTimeoutErr);
assert(lStatus == noErr);
}
}
// try to enter the critical region
function<OSStatus, Duration> oEnterCriticalRegion;
oEnterCriticalRegion = bind(MPEnterCriticalRegion, pCriticalRegionID, _1);
OSStatus lStatus = safe_wait(oEnterCriticalRegion, lDuration);
// if we entered the critical region's critical region to get the critical region,
// exit the critical region's critical region.
if(pCriticalRegionCriticalRegionID != kInvalidID && at_mp() == false)
{
lStatus = MPExitCriticalRegion(pCriticalRegionCriticalRegionID);
assert(lStatus == noErr);
}
return(lStatus);
}
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration)
{
function<OSStatus, Duration> oWaitOnQueue;
oWaitOnQueue = bind(MPWaitOnQueue, pQueueID, pParam1, pParam2, pParam3, _1);
return(safe_wait(oWaitOnQueue, lDuration));
}
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime)
{
if(execution_context() == k_eExecutionContextMPTask)
{
return(MPDelayUntil(pWakeUpTime));
}
else
{
uint64_t ullWakeUpTime = force_cast<uint64_t>(*pWakeUpTime);
while(force_cast<uint64_t>(UpTime()) < ullWakeUpTime)
{
idle();
}
return(noErr);
}
}
OSStatus safe_wait(function<OSStatus, Duration> &rFunction, Duration lDuration)
{
if(execution_context() == k_eExecutionContextMPTask)
{
return(rFunction(lDuration));
}
else
{
uint64_t ullExpiration = 0ULL;
// get the expiration time in UpTime units
if(lDuration == kDurationForever)
{
ullExpiration = ::std::numeric_limits<uint64_t>::max();
}
else if(lDuration == kDurationImmediate)
{
ullExpiration = force_cast<uint64_t>(UpTime());
}
else
{
AbsoluteTime sExpiration = AddDurationToAbsolute(lDuration, UpTime());
ullExpiration = force_cast<uint64_t>(sExpiration);
}
OSStatus lStatus;
bool bExpired = false;
do
{
lStatus = rFunction(kDurationImmediate);
// mm - "if" #if 0'd out to allow task time to threads blocked on I/O
#if 0
if(lStatus == kMPTimeoutErr)
#endif
{
idle();
}
if(lDuration != kDurationForever)
{
bExpired = (force_cast<uint64_t>(UpTime()) < ullExpiration);
}
} while(lStatus == kMPTimeoutErr && bExpired == false);
return(lStatus);
}
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

47
src/mac/safe.hpp Normal file
View File

@@ -0,0 +1,47 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_SAFE_MJM012402_HPP
#define BOOST_SAFE_MJM012402_HPP
#include <Multiprocessing.h>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// these functions are used to wain in an execution context-independent manor. All of these
// functions are both MP- and ST-safe.
OSStatus safe_wait_on_semaphore(MPSemaphoreID pSemaphoreID, Duration lDuration);
OSStatus safe_enter_critical_region(MPCriticalRegionID pCriticalRegionID, Duration lDuration, MPCriticalRegionID pCriticalRegionCriticalRegionID = kInvalidID);
OSStatus safe_wait_on_queue(MPQueueID pQueueID, void **pParam1, void **pParam2, void **pParam3, Duration lDuration);
OSStatus safe_delay_until(AbsoluteTime *pWakeUpTime);
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_SAFE_MJM012402_HPP

View File

@@ -0,0 +1,53 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "scoped_critical_region.hpp"
#include "init.hpp"
#include <cassert>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
scoped_critical_region::scoped_critical_region():
m_pCriticalRegionID(kInvalidID)
{
static bool bIgnored = thread_init();
OSStatus lStatus = MPCreateCriticalRegion(&m_pCriticalRegionID);
if(lStatus != noErr || m_pCriticalRegionID == kInvalidID)
throw(thread_resource_error());
}
scoped_critical_region::~scoped_critical_region()
{
OSStatus lStatus = MPDeleteCriticalRegion(m_pCriticalRegionID);
assert(lStatus == noErr);
}
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

View File

@@ -0,0 +1,69 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#ifndef BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
#define BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP
#include <boost/thread/exceptions.hpp>
#include <Multiprocessing.h>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
// class scoped_critical_region probably needs a new name. Although the current name
// is accurate, it can be read to mean that a critical region is entered for the
// current scope. In reality, a critical region is _created_ for the current scope.
// This class is intended as a replacement for MPCriticalRegionID that will
// automatically create and dispose of itself.
class scoped_critical_region
{
public:
scoped_critical_region();
~scoped_critical_region();
public:
operator const MPCriticalRegionID &() const;
const MPCriticalRegionID &get() const;
private:
MPCriticalRegionID m_pCriticalRegionID;
};
// these are inlined for speed.
inline scoped_critical_region::operator const MPCriticalRegionID &() const
{ return(m_pCriticalRegionID); }
inline const MPCriticalRegionID &scoped_critical_region::get() const
{ return(m_pCriticalRegionID); }
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost
#endif // BOOST_SCOPED_CRITICAL_REGION_MJM012402_HPP

91
src/mac/st_scheduler.cpp Normal file
View File

@@ -0,0 +1,91 @@
// Copyright (C) 2001
// Mac Murrett
//
// Permission to use, copy, modify, distribute and sell this software
// and its documentation for any purpose is hereby granted without fee,
// provided that the above copyright notice appear in all copies and
// that both that copyright notice and this permission notice appear
// in supporting documentation. Mac Murrett makes no representations
// about the suitability of this software for any purpose. It is
// provided "as is" without express or implied warranty.
//
// See http://www.boost.org for most recent version including documentation.
#include "st_scheduler.hpp"
#include <cassert>
namespace boost {
namespace threads {
namespace mac {
namespace detail {
#if TARGET_CARBON
st_scheduler::st_scheduler():
m_uppTask(NULL),
m_pTimer(NULL)
{
m_uppTask = NewEventLoopTimerUPP(task_entry);
// TODO - throw on error
assert(m_uppTask != NULL);
}
st_scheduler::~st_scheduler()
{
DisposeEventLoopTimerUPP(m_uppTask);
m_uppTask = NULL;
}
void st_scheduler::start_polling()
{
assert(m_pTimer == NULL);
OSStatus lStatus = InstallEventLoopTimer(GetMainEventLoop(),
0 * kEventDurationSecond,
kEventDurationMillisecond,
m_uppTask,
this,
&m_pTimer);
// TODO - throw on error
assert(lStatus == noErr);
}
void st_scheduler::stop_polling()
{
assert(m_pTimer != NULL);
OSStatus lStatus = RemoveEventLoopTimer(m_pTimer);
assert(lStatus == noErr);
m_pTimer = NULL;
}
/*static*/ pascal void st_scheduler::task_entry(EventLoopTimerRef /*pTimer*/, void *pRefCon)
{
st_scheduler *pThis = reinterpret_cast<st_scheduler *>(pRefCon);
assert(pThis != NULL);
pThis->task();
}
void st_scheduler::task()
{
periodic_function();
}
#else
# error st_scheduler unimplemented!
#endif
} // namespace detail
} // namespace mac
} // namespace threads
} // namespace boost

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