2
0
mirror of https://github.com/boostorg/thread.git synced 2026-02-05 10:12:09 +00:00

Compare commits

...

407 Commits

Author SHA1 Message Date
Anthony Williams
ab1c01b17a declared _ReadWriteBarrier intrinsic; added explicit check for zero to ReleaseSemaphore call
[SVN r39700]
2007-10-05 10:41:16 +00:00
Anthony Williams
bb06946bf1 reverted condition
[SVN r39698]
2007-10-05 09:56:20 +00:00
Anthony Williams
68a7a469ca reverted condition.hpp
[SVN r39696]
2007-10-05 09:55:12 +00:00
Anthony Williams
b2a095098d header-only once for POSIX
[SVN r39695]
2007-10-05 09:52:08 +00:00
Anthony Williams
b5ac347a0b Initial pthreads implementation
[SVN r38179]
2007-07-11 08:31:24 +00:00
Anthony Williams
cf15597a9e Added timeout constant
[SVN r37650]
2007-05-09 14:37:56 +00:00
Anthony Williams
ab0e9930c5 Added copyright and licence
[SVN r37189]
2007-03-15 13:53:43 +00:00
Anthony Williams
d0d1db2feb New condvar implementation that doesn't depend on APC calls, so OS can pick thread to wake
[SVN r37188]
2007-03-15 13:39:59 +00:00
Anthony Williams
89348a9569 basic timed mutex uses an Auto-Reset Event rather than a semaphore; changed thread_primitives to avoid use of macros
[SVN r36067]
2006-11-17 10:45:27 +00:00
Anthony Williams
f260fd62d4 inherit publicly from underlying mutex
[SVN r36066]
2006-11-17 09:07:29 +00:00
Anthony Williams
e2550db927 More tests for try_lock_shareable
[SVN r35870]
2006-11-06 12:17:34 +00:00
Anthony Williams
0d763fe627 Added try_lock_shareable
[SVN r35869]
2006-11-06 09:32:26 +00:00
Anthony Williams
9895e74560 Added upgradeable stuff
[SVN r35798]
2006-10-30 21:36:44 +00:00
Anthony Williams
82aa808b3b Current read-write mutex impl doesn't support upgrading
[SVN r35752]
2006-10-27 15:18:59 +00:00
Anthony Williams
fb683c8d95 New, fairer and faster read-write mutex algorithm
[SVN r35751]
2006-10-27 15:18:00 +00:00
Anthony Williams
819c67d52b Increased count limits to use all available space in state field; extracted create_anonymous_event; ensure shared event is correctly
set


[SVN r35659]
2006-10-18 13:15:41 +00:00
Anthony Williams
95a476a4cc Updated tests for read_write_mutex, and fixed initialization of events
[SVN r35648]
2006-10-17 17:22:57 +00:00
Anthony Williams
c4625de938 Updated read-write mutex implementation to support upgradeable locks too
[SVN r35499]
2006-10-05 14:42:08 +00:00
Anthony Williams
eeb77fdd87 New look read-write mutex
[SVN r35497]
2006-10-05 09:38:31 +00:00
Anthony Williams
7aed765a77 Only get the semaphore once at the beginning of lock/timed_lock
[SVN r35494]
2006-10-05 07:34:28 +00:00
Anthony Williams
5a4f798320 Avoid doing an extra CAS if the same number of threads are waiting when we wake up as when we go to sleep
[SVN r35487]
2006-10-04 11:28:26 +00:00
Anthony Williams
8f611e4d19 Improved algorithm of basic_timed_mutex, and changed boost::mutex to use that as the underlying type
[SVN r35486]
2006-10-04 11:09:55 +00:00
Anthony Williams
a646f1c818 Changed tests that rely on condition variables to use the new basic_condition<lock_type> rather than plain condition
[SVN r35485]
2006-10-04 11:06:24 +00:00
Anthony Williams
3d4743972e New lock algorithm with
[SVN r35454]
2006-10-03 10:16:22 +00:00
Anthony Williams
553aad753b Experimental change to template the whole condition variable on the lock type, rather than the wait functions
[SVN r35362]
2006-09-28 11:41:14 +00:00
Anthony Williams
f8a08dfaad condition doesn't need to be a friend of these classes in the new implementation
[SVN r35361]
2006-09-28 11:31:40 +00:00
Anthony Williams
956ed86655 Added missing include
[SVN r35318]
2006-09-25 09:09:02 +00:00
Roland Schwarz
e258fb3fe9 Added pthread compile comments for win32
[SVN r35309]
2006-09-24 13:55:47 +00:00
Roland Schwarz
676eb029b8 Examples compile with bbv1
[SVN r35308]
2006-09-24 13:08:22 +00:00
Roland Schwarz
6459de79c3 More sources added
[SVN r35290]
2006-09-23 15:37:42 +00:00
Roland Schwarz
af774310ef disable MSVC DLL warnings for derivation from noncopyable
[SVN r35281]
2006-09-22 17:00:21 +00:00
Roland Schwarz
b1c5977064 cleaned up time conversions for pthread implementation
[SVN r35280]
2006-09-22 16:56:06 +00:00
Anthony Williams
d92430c8ee Added explicit check for value!=0, to remove warning
[SVN r35273]
2006-09-22 10:31:25 +00:00
Anthony Williams
ce384ef3d8 Ensure thread handle is closed correctly. Fix race conditions on notify.
[SVN r35272]
2006-09-22 09:41:34 +00:00
Roland Schwarz
c2cfd16c6c replaced <library-file> by <library>
[SVN r35251]
2006-09-21 16:31:56 +00:00
Anthony Williams
fcfd30f124 Don't unlink a thread that's been notified when it wakes, as the unlink is done as part of the notify
Hold the gate whilst we notify all the waiting threads, so they don't unlink out from under us.


[SVN r35222]
2006-09-20 10:06:49 +00:00
Roland Schwarz
20cc8e6c30 corrected PTW32_LIB variable
[SVN r35220]
2006-09-19 20:59:40 +00:00
Anthony Williams
4bff122033 We don't need to lock round every notify when notifying all, since we've already isolated the list
[SVN r35202]
2006-09-19 14:11:45 +00:00
Roland Schwarz
49e437f11e using modules.peek to access environment variables for pthread
[SVN r35167]
2006-09-18 19:28:28 +00:00
Roland Schwarz
63bad0ad64 build support for boost.build v2
[SVN r35166]
2006-09-18 18:47:47 +00:00
Roland Schwarz
33ff838081 <sysinclude> really needs to refer to $(BOOST_ROOT). Relative paths not working.
[SVN r35162]
2006-09-18 18:02:29 +00:00
Anthony Williams
5328b43191 Serialize the final checks, too, so we don't get race conditions in the BOOST_CHECK_EQUAL in call_once_thread
[SVN r34842]
2006-08-07 16:32:26 +00:00
Anthony Williams
7aac1e69af New once test under BSL
[SVN r34841]
2006-08-07 16:31:32 +00:00
Anthony Williams
94207924ad Eliminated some "magic numbers"
[SVN r34840]
2006-08-07 16:14:42 +00:00
Roland Schwarz
3671f1792d compiler choked on conversion to long in function get_milliseconds_until_time
[SVN r34816]
2006-08-04 16:57:57 +00:00
Roland Schwarz
3da29cb470 corrected typo
[SVN r34815]
2006-08-04 10:39:46 +00:00
Roland Schwarz
4448aa7fb9 disable warnings of non dll base class for noncopyable. This is necessary for bbv2 since the warning level now is W3
[SVN r34814]
2006-08-04 10:35:19 +00:00
Roland Schwarz
71358d8842 Allow examples to be built out of boost source tree.
[SVN r34584]
2006-07-17 10:19:36 +00:00
Roland Schwarz
5366b629d3 Fallback to time if neither gettimeofday nor clock_gettime available.
[SVN r34583]
2006-07-17 10:17:12 +00:00
Roland Schwarz
01b2d5c088 bbv1 Jamfile restructured
[SVN r34582]
2006-07-17 10:15:17 +00:00
Roland Schwarz
8d22f58bc3 Native files now without platform tag.
[SVN r34581]
2006-07-17 10:12:43 +00:00
Anthony Williams
be64ba98b3 Ensure all checks are guarded by a mutex, to avoid race conditions in the test library
[SVN r34503]
2006-07-10 20:53:56 +00:00
Roland Schwarz
ad551dd333 xtime source added
[SVN r34318]
2006-06-16 13:40:30 +00:00
Anthony Williams
1e055e618d try_lock should throw if already locked
[SVN r34313]
2006-06-15 20:10:42 +00:00
Anthony Williams
46064d1b20 Added test to ensure that try_lock locks if not already locked
[SVN r34312]
2006-06-15 20:01:37 +00:00
Anthony Williams
08cf6a81a5 Changes test_scoped_try_lock over to being a templated test case
[SVN r34300]
2006-06-14 07:52:29 +00:00
Anthony Williams
8ce25c6ecd Changed scoped_lock_test to templated test case, in order to get better error messages
[SVN r34299]
2006-06-14 07:48:05 +00:00
Anthony Williams
01f93931cb timed_mutex and recursive_timed_mutex have scoped_locks
[SVN r34298]
2006-06-14 07:31:13 +00:00
Anthony Williams
0d3f4a0b7c recursive_try_mutex has both a scoped_lock and a scoped_try_lock
[SVN r34297]
2006-06-13 21:08:02 +00:00
Anthony Williams
29a1903c4b recursive_mutex::scoped_lock should support scoped_lock concept
[SVN r34295]
2006-06-13 20:36:27 +00:00
Anthony Williams
08041bf58e try_mutex locks throw if unlocked twice
[SVN r34249]
2006-06-08 16:39:21 +00:00
Anthony Williams
781794aa2d Templated test_throws_if_unlock_called_when_already_unlocked
[SVN r34248]
2006-06-08 16:32:40 +00:00
Anthony Williams
36c1198113 Added more tests for try_mutex::scoped_try_lock
[SVN r34247]
2006-06-08 16:31:15 +00:00
Anthony Williams
552dfff988 try_mutex_scoped_lock throws if you try and lock it twice
[SVN r34246]
2006-06-08 16:30:14 +00:00
Anthony Williams
6efc06f50c templated test_throws_if_lock_called_when_already_locked
[SVN r34245]
2006-06-08 16:22:33 +00:00
Anthony Williams
e72cb93fe0 Templated test_locked_after_lock_called
[SVN r34243]
2006-06-08 14:53:02 +00:00
Anthony Williams
d57be95047 Templated more tests
[SVN r34242]
2006-06-08 14:48:46 +00:00
Anthony Williams
1d1989bbfe Templated test_initially_locked_with_bool_parameter_true
[SVN r34241]
2006-06-08 14:42:41 +00:00
Anthony Williams
11178cdc84 Templated test_initially_locked, and applied to boost::try_mutex::scoped_lock too
[SVN r34240]
2006-06-08 14:40:43 +00:00
Anthony Williams
54d37cd6af Added more checks round scoped_lock concept
[SVN r34239]
2006-06-08 14:33:29 +00:00
Anthony Williams
ede873549b Throw lock error if we try and unlock twice
[SVN r34238]
2006-06-08 14:24:23 +00:00
Anthony Williams
83a2a4ec38 Started to add tests for locking concepts; ensure mutex::scoped_lock throws when try to lock if already locked
[SVN r34237]
2006-06-08 14:12:10 +00:00
Anthony Williams
29e3665ead scoped_read_lock calls m.cond.notify_one, so it passes test
[SVN r34236]
2006-06-08 09:57:00 +00:00
Anthony Williams
acd9b9db7e Two tests in
[SVN r33904]
2006-05-02 09:23:33 +00:00
Anthony Williams
71c652dd9f Basic condition-based read-write mutex
[SVN r33850]
2006-04-28 08:20:18 +00:00
Anthony Williams
6afcf7615d Use headers from most general point rather than most specific
[SVN r33845]
2006-04-27 21:07:30 +00:00
Anthony Williams
70302577f9 Empty read_write_mutex supports any number of readers
[SVN r33844]
2006-04-27 20:39:36 +00:00
Anthony Williams
b5fdb39877 Updated to fix line endings
[SVN r33838]
2006-04-27 14:04:45 +00:00
Anthony Williams
26f3f0fd2d Changed the Comparison for the condition-based test in test_timedlock to state what we really mean
[SVN r33837]
2006-04-27 14:03:39 +00:00
Anthony Williams
562a748bc6 Moved more stuff over to new platform layout; made tests work on win32
[SVN r33680]
2006-04-12 16:48:10 +00:00
Roland Schwarz
45ca67ec26 obsolete code
[SVN r33672]
2006-04-11 22:23:47 +00:00
Roland Schwarz
65f466c813 platform split
[SVN r33669]
2006-04-11 19:54:45 +00:00
Roland Schwarz
2b37cee9e5 platform split
[SVN r33668]
2006-04-11 19:49:21 +00:00
Roland Schwarz
ad33e705b2 platform split
[SVN r33667]
2006-04-11 19:42:57 +00:00
Roland Schwarz
a639fe4dbe platform split
[SVN r33666]
2006-04-11 19:35:10 +00:00
Roland Schwarz
8806d38775 platform split
[SVN r33665]
2006-04-11 19:24:06 +00:00
Anthony Williams
ba49aaa0f7 Added "unspecified" read-write sync policy, for use in read-write mutex tests
[SVN r33564]
2006-04-06 09:13:22 +00:00
Anthony Williams
1a92100467 Don't make qualified calls where we don't have to
[SVN r33556]
2006-04-05 11:46:12 +00:00
Anthony Williams
ef6dc83fa8 Use BOOST_INTERLOCKED_EXCHANGE_ADD in preference to BOOST_INTERLOCKED_COMPARE_EXCHANGE, since this should be faster
[SVN r33555]
2006-04-05 11:45:11 +00:00
Anthony Williams
48f550d403 Updated copyright
[SVN r33554]
2006-04-05 11:43:07 +00:00
Anthony Williams
3c9be720b8 Simplified code by extracting create_once_mutex, so the essence of call_once is clarified.
Use boost::detail::interlocked_read rather than BOOST_INTERLOCKED_COMPARE_EXCHANGE to check flag value


[SVN r33553]
2006-04-05 11:42:07 +00:00
Anthony Williams
b3ba8802bf Better express intent in structure of call_once
[SVN r33457]
2006-03-23 16:11:52 +00:00
Anthony Williams
0fddf00c8f Removed using declaration for get_active_count, since we don't need it, and VC6 moans about it
[SVN r33411]
2006-03-20 22:08:33 +00:00
Anthony Williams
bb7976f666 Tidied up access for condition members
[SVN r33345]
2006-03-14 23:43:23 +00:00
Anthony Williams
3ad4fb38b5 Eliminated redundant #ifdef parts
[SVN r33335]
2006-03-13 17:00:46 +00:00
Anthony Williams
deaccce853 Corrected #ifdefs for WINTHREADS
[SVN r33331]
2006-03-13 10:07:49 +00:00
Anthony Williams
6aabcaac5c Added appropriate support for QueueUserAPC condition implementation
[SVN r33330]
2006-03-13 08:29:17 +00:00
Anthony Williams
d07407306f Added boost::detail::get_xtime_sentinel, which always yields 2^32-1 (INFINITE) seconds until expiry
[SVN r33329]
2006-03-13 08:14:16 +00:00
Anthony Williams
4231423773 Reduced duplication by extracting do_notify_one
[SVN r33304]
2006-03-10 10:54:27 +00:00
Anthony Williams
46b66d5268 Reduced scope of locking
[SVN r33303]
2006-03-10 10:33:37 +00:00
Anthony Williams
9c439a73db Inlined barrier code, new implementation of condition based on QueueUserAPC. Blocks all waits and notifies whilst notifying.
[SVN r33302]
2006-03-10 10:07:01 +00:00
Anthony Williams
cdd57f50ef Added recursive_timed_mutex
[SVN r33279]
2006-03-09 11:13:29 +00:00
Anthony Williams
8c2ded3235 Win32 implementation of boost::timed_mutex
[SVN r33272]
2006-03-08 22:24:52 +00:00
Anthony Williams
d3b590f213 Assert rather than throw when using checked mutexes
[SVN r33231]
2006-03-06 09:47:09 +00:00
Anthony Williams
7fcdd5d9e2 Added basic_checked_mutex, and make use of it dependent on BOOST_USE_CHECKED_MUTEX
[SVN r33208]
2006-03-03 09:35:41 +00:00
Anthony Williams
9ceee4b030 New implementations of mutex and recursive mutex for win32
[SVN r33172]
2006-02-28 11:27:19 +00:00
Anthony Williams
50f8f34ab8 Simplified wait functions
[SVN r32393]
2006-01-24 11:24:00 +00:00
Anthony Williams
d76e67ffe2 Updated tests, to ensure unblocked_count is guarded by mutex when reading, and added new test for unblocking only one writer
[SVN r31627]
2005-11-12 10:21:39 +00:00
Anthony Williams
617729f2ae Added new test for unblocking all readers to read_write_mutex code. Added necessary implementation.
[SVN r31122]
2005-09-26 07:09:09 +00:00
Anthony Williams
e8363511d0 Moved BOOST_INTERLOCKED_READ stuff into its own header
[SVN r31098]
2005-09-23 17:24:29 +00:00
Anthony Williams
4749f47f00 Verify that only one writer permitted at once
[SVN r31064]
2005-09-20 22:09:49 +00:00
Anthony Williams
07af8a5605 Removed duplication between reader_thread and writer_thread into a template locking_thread
[SVN r31063]
2005-09-20 21:51:02 +00:00
Anthony Williams
cc89b8d2c6 A locked reader blocks a waiting writer
[SVN r31062]
2005-09-20 21:42:45 +00:00
Anthony Williams
946d45ee70 Added brute force test for multiple readers
[SVN r31061]
2005-09-20 21:20:31 +00:00
Anthony Williams
8a3b5145ac reverted QueueUserAPC changes
[SVN r31052]
2005-09-20 07:27:35 +00:00
Anthony Williams
1af9fb7267 Wake up threads using QueueUserAPC rather than triggering the semaphore.
[SVN r31047]
2005-09-19 22:31:21 +00:00
Anthony Williams
6fe2e36fb0 Put a mutex around the increment in init_once_value, to ensure that if two threads call init_once_value, the increment is done
correctly.


[SVN r31046]
2005-09-19 21:09:14 +00:00
Anthony Williams
e5ada85386 Extended stress test: 100 threads, loop 100 times on same thread.
[SVN r31045]
2005-09-19 20:59:49 +00:00
Anthony Williams
a9760cd2e6 Added test to verify that threads block on a mutex, and only one waiting thread is released when the mutex is unlocked.
[SVN r31040]
2005-09-19 15:11:41 +00:00
Anthony Williams
3e0ce8d25a Added a looping test to check for cross-thread sync problems
[SVN r31016]
2005-09-17 22:20:35 +00:00
Anthony Williams
7d59bbbad5 Set semaphore handle back to NULL on destruction
[SVN r31011]
2005-09-16 13:58:44 +00:00
Anthony Williams
c7a85f366c New read_write_mutex implementation for win32. No try/timed varieties, and no support for read/write priority policies.
[SVN r30994]
2005-09-15 10:47:29 +00:00
Anthony Williams
8b3773f157 Trimmed included headers
[SVN r30986]
2005-09-14 15:44:28 +00:00
Anthony Williams
cb27585fa2 Added new implementation of timed_mutex for win32
[SVN r30985]
2005-09-14 15:20:24 +00:00
Anthony Williams
d3ee1b804a Added new implementation of timed_mutex for win32
[SVN r30984]
2005-09-14 15:10:41 +00:00
Anthony Williams
48ff760e18 Remove references to WINTHREADS from the generic code, as windows threads handled in separate header
[SVN r30982]
2005-09-14 12:49:52 +00:00
Anthony Williams
ba0bdc6489 Use lightweight_mutex for mutex impl. Added basic condition implementation.
[SVN r30981]
2005-09-14 12:43:02 +00:00
Anthony Williams
953461904c Added licence text
[SVN r30979]
2005-09-14 10:44:27 +00:00
Anthony Williams
c956bc9ad7 Moved lightweight_mutex_win32.hpp and mutex_win32.hpp into boost source tree
[SVN r30978]
2005-09-14 10:35:12 +00:00
Anthony Williams
91d88bb24a Added lightweight_mutex_win32.hpp
[SVN r30977]
2005-09-14 10:18:33 +00:00
nobody
545a0f5c86 This commit was manufactured by cvs2svn to create branch
'thread_rewrite'.

[SVN r30953]
2005-09-13 14:20:32 +00:00
Anthony Williams
64b5b67661 Updated thread primitives to include semaphore functions
[SVN r30952]
2005-09-13 14:20:31 +00:00
Anthony Williams
b6f0ec7fd9 Moved win32 thread sync primitives to their own file
[SVN r30947]
2005-09-13 13:48:01 +00:00
Anthony Williams
e9c0b5e0c5 Nibble mask is 0x0f, not 0x7f
[SVN r30888]
2005-09-09 12:51:17 +00:00
Anthony Williams
4a005ea288 New version of call_once for win32
[SVN r30847]
2005-09-07 15:02:16 +00:00
John Maddock
9658b69af4 Added config and header include changes needed to support MSVC + STLport 5.0.
[SVN r30701]
2005-08-27 10:25:15 +00:00
Douglas Gregor
e3c9446e29 Merged from 1.33.0 release
[SVN r30540]
2005-08-12 13:02:37 +00:00
Douglas Gregor
aa240e61d9 Clear up broken links, tabs, etc
[SVN r30077]
2005-07-14 15:47:04 +00:00
Douglas Gregor
2954e932ce Fix test_read_write_mutex, from Tobias Schwinger
[SVN r29988]
2005-07-11 15:06:09 +00:00
Douglas Gregor
5be79cc858 Unbolidify Threads title
[SVN r29938]
2005-07-07 18:06:26 +00:00
Martin Wille
4a9d97d22d -- made the initialization order for the members of
boost::detail::thread::read_write_mutex_impl
   consistent with the declaration.


[SVN r29913]
2005-07-06 21:36:56 +00:00
Martin Wille
f4f3433854 -- fixed order of member initialization
[SVN r29881]
2005-07-03 16:51:35 +00:00
Michael Glassford
26bffa3740 Rename binder to eliminate name conflicts with type traits.
[SVN r29229]
2005-05-26 14:12:41 +00:00
Michael Glassford
69e52a9882 Fix CW 8.3 warnings.
[SVN r28638]
2005-05-03 20:42:09 +00:00
Michael Glassford
cc8de48849 Commit Caleb Epstein patch to fix errors due to Boost.Test not being thread safe.
[SVN r28537]
2005-04-29 20:38:46 +00:00
Michael Glassford
9d7c119f94 Fixed CodeWarrior 8.3 warnings.
[SVN r28497]
2005-04-27 01:22:12 +00:00
Vladimir Prus
6ba9fd1b60 Sync with V1
[SVN r28369]
2005-04-21 08:17:12 +00:00
Michael Glassford
fb6250eb94 Completely rewrite tests to eliminate most calls to Sleep(), which was making the tests take far too long.
[SVN r28331]
2005-04-19 20:52:08 +00:00
Michael Glassford
bc73368c96 Remove line that could cause unnecessary extra waiting.
[SVN r28330]
2005-04-19 20:49:59 +00:00
Michael Glassford
3068f0c62c Fix undefined BOOST_READ_WRITE_MUTEX_TRACE in non-BOOST_HAS_WINTHREADS builds.
[SVN r27924]
2005-04-02 04:31:10 +00:00
Michael Glassford
8e00803c83 Don't include explicit instantiations in release builds (they increase the code size significantly).
[SVN r27887]
2005-03-30 16:59:07 +00:00
Michael Glassford
087b69b629 Fix build errors on some Win32 machines.
[SVN r27884]
2005-03-30 14:51:09 +00:00
Michael Glassford
3b237267fb Added more debugging aids, assertions. Corrected errors, including hangs, at the cost or making the read-write mutex even larger. The whole read-write mutex is too complicated; the design needs to be revisited.
[SVN r27874]
2005-03-29 21:46:38 +00:00
Michael Glassford
b9dbb1ed45 Expand read_write_mutex regression tests.
[SVN r27873]
2005-03-29 21:23:39 +00:00
Michael Glassford
41d3b29ec0 Add assert() at beginning of thread::join().
[SVN r27868]
2005-03-29 16:19:32 +00:00
Michael Glassford
05ceb8b1e2 Fix Sourceforge issue #828980, "comparisons in libs/thread/src/timeconv.inl".
[SVN r27867]
2005-03-29 15:43:00 +00:00
Michael Glassford
80d3925b8d Remove obsolete header.
[SVN r27718]
2005-03-17 02:03:31 +00:00
Michael Glassford
2cd6cbeacc Change assert() in recursive_try_mutex::do_trylock() to handle the case of pthread_mutex_trylock returning EBUSY.
[SVN r27717]
2005-03-17 01:55:44 +00:00
Michael Glassford
6382846f6c Add thread_group::size() method.
[SVN r27716]
2005-03-17 01:46:11 +00:00
Stefan Slapeta
349d0fd74b replaced BOOST_TEST
[SVN r27054]
2005-02-03 13:48:49 +00:00
Beman Dawes
9c88855bf4 correct date (Andreas Wachowski)
[SVN r26826]
2005-01-24 01:51:16 +00:00
Roland Schwarz
f0e6cdfcb5 ptw32 can be used again
[SVN r26802]
2005-01-22 13:43:48 +00:00
Roland Schwarz
af9864a1b5 Making use of BOOST_HAS_DECLSPEC macro
[SVN r26801]
2005-01-22 13:22:29 +00:00
Stefan Slapeta
8ac145e667 removed requirement of static rt for static lib
[SVN r26480]
2004-12-09 10:42:09 +00:00
Michael Glassford
39f7afc7d0 Reword comment to make its meaning clearer.
[SVN r26453]
2004-12-06 21:00:16 +00:00
Aleksey Gurtovoy
113b974bb7 merge RC_1_32_0 fixes
[SVN r26333]
2004-11-28 04:44:21 +00:00
Stefan Slapeta
c747a6ff4e Fix uninitialized variables
[SVN r25410]
2004-09-26 09:32:04 +00:00
Stefan Slapeta
107d11cfd5 Fix to make auto tss cleanup work for Intel Compiler
[SVN r25374]
2004-09-23 11:39:14 +00:00
Rene Rivera
a4d2cd94b9 Move <threadind>multi from default build, to the requirement it is.
[SVN r25195]
2004-09-18 18:24:03 +00:00
Rene Rivera
3d9fb84fc9 Move definition of __STD_CONSTANT_MACROS to be above first indirect inclusion of <cstdint> to fix compilation problem with MSL.
[SVN r25181]
2004-09-17 23:31:13 +00:00
Michael Glassford
e500bc075e Make recent xtime_get() changes more portable and easier to understand.
[SVN r25160]
2004-09-16 20:39:49 +00:00
Michael Glassford
25e8fa0e11 Fixed bug in pthreads implementation that caused incorrect behavior when used with condition variables.
[SVN r25151]
2004-09-16 17:49:16 +00:00
Michael Glassford
5f27fb2607 Add newline to end of file.
[SVN r24976]
2004-09-08 15:58:40 +00:00
Michael Glassford
d977cedb78 Fix gcc warning about inline function being marked as dllimport.
[SVN r24975]
2004-09-08 15:57:03 +00:00
Stefan Slapeta
454b58cdf0 Configure Intel for Windows like MSVC
[SVN r24805]
2004-08-29 14:13:47 +00:00
Michael Glassford
82a632b0f9 Remove cast from FILETIME to __int64, which may have alignment issues on, e.g. IA64.
[SVN r24786]
2004-08-27 14:31:28 +00:00
Michael Glassford
43cbe3f1f8 Include detail/config.hpp; fix include path.
[SVN r24607]
2004-08-19 19:39:16 +00:00
Michael Glassford
d027cec8a6 Remove accidental checkin.
[SVN r24606]
2004-08-19 19:33:46 +00:00
Michael Glassford
e53c2c52ee Add <threading>multi to work around what appears to be a bjam bug.
[SVN r24605]
2004-08-19 19:31:23 +00:00
Michael Glassford
5ff0ecc12d Remove previous checkin, which should have been in test\\jamfile, not build\\jamfile.
[SVN r24604]
2004-08-19 19:27:15 +00:00
Michael Glassford
9c1f421ccb Add <threading>multi to work around regression test build errors.
[SVN r24603]
2004-08-19 19:12:57 +00:00
Michael Glassford
66850bc057 Add <threading>multi to work around what appears to be a bjam bug.
[SVN r24601]
2004-08-19 17:16:50 +00:00
Michael Glassford
33da34b4bf Don't use subtraction to compare xtime.sec because it could overflow.
[SVN r24361]
2004-08-09 21:46:34 +00:00
Michael Glassford
792cd49310 Add #define BOOST_THREAD_TEST to command line so code can behave differently when being tested.
[SVN r24360]
2004-08-09 21:43:24 +00:00
Michael Glassford
37fdb5e2b0 Removed unnecessary casts that were causing warnings on DEC C++ 6.5 compiler.
[SVN r24359]
2004-08-09 21:39:03 +00:00
Michael Stevens
88cd251db7 tss changes to match Jamfile 1.32
[SVN r24356]
2004-08-09 16:22:43 +00:00
Michael Glassford
4038d18fc8 Only implement functions if not already implemented elsewhere to prevent linking problems.
[SVN r24341]
2004-08-08 11:17:21 +00:00
Michael Glassford
59bf92a183 Write info to cout to help debug problems.
[SVN r24339]
2004-08-08 01:20:37 +00:00
Michael Glassford
57879155d2 Fixed incorrect test.
[SVN r24336]
2004-08-07 16:10:56 +00:00
Michael Glassford
96d43cebc0 Added tests (currently only on Win32, where there's most likely to be a problem) to make sure tss works properly with threads not created by Boost.
[SVN r24325]
2004-08-06 15:50:11 +00:00
Michael Glassford
8e13857b29 Unlock mutex sooner to allow recursive calls to on_thread_exit().
[SVN r24324]
2004-08-06 15:31:08 +00:00
Michael Glassford
8c6e454697 Uncommented call to on_process_enter(). Fixed line endings.
[SVN r24322]
2004-08-06 11:55:51 +00:00
Michael Glassford
4c7c7df89b Fixed typos.
[SVN r24320]
2004-08-06 11:54:11 +00:00
Michael Glassford
515e6d8635 Completely restructured tss cleanup. Automatic tss cleanup in Win32 static Boost.Threads library now works for both VC++ 6 and 7.1 (probably also 7.0, but this hasn't been tested).
[SVN r24312]
2004-08-05 18:13:43 +00:00
Michael Glassford
bbd941e2df Updated release notes for static liking of Boost.Threads to reflect recent changes.
[SVN r24311]
2004-08-05 18:08:09 +00:00
Michael Glassford
3edba1bf19 Changed default linking option on non-Win32 platforms from dynamic to static linking.
[SVN r24310]
2004-08-05 18:06:34 +00:00
Michael Glassford
4ad99d8242 Completely restructured tss cleanup. Automatic tss cleanup in Win32 static Boost.Threads library now works for both VC++ 6 and 7.1 (probably also 7.0, but this hasn't been tested).
[SVN r24307]
2004-08-05 17:33:07 +00:00
Michael Glassford
c0aeaecc14 Add tests for statically linked Boost.Threads.
[SVN r24274]
2004-08-03 21:19:08 +00:00
Michael Glassford
792be9e687 Add on_process_enter() and on_thread_enter(); make tss cleanup more robust.
[SVN r24258]
2004-08-03 01:38:04 +00:00
Michael Glassford
fd65337f43 Add tests for statically linked and dynamically linked versions of Boost.Threads.
[SVN r24257]
2004-08-03 01:33:24 +00:00
Michael Glassford
9de9726e6f Removed erroneous call to on_process_exit().
[SVN r24237]
2004-08-01 19:25:05 +00:00
Michael Glassford
522037ca4a Add automatic tss cleanup to statically linked Win32 Boost.Threads library (currently works only for VC++ 7.1).
[SVN r24236]
2004-08-01 17:50:11 +00:00
Michael Glassford
8fc3d1f718 Add automatic tss cleanup to statically linked Win32 Boost.Threads library (currently works only for VC++ 7.1).
[SVN r24235]
2004-08-01 17:26:45 +00:00
Michael Glassford
cebaf27ee8 Set thread cleanup handlers to null when deleting it so that calling on_thread_exit() twice doesn't use an invalid pointer.
[SVN r24228]
2004-08-01 12:07:11 +00:00
Michael Glassford
b62503f274 Call tss cleanup after thread function exits even in dll builds of Boost.Threads (win32 only).
[SVN r24227]
2004-08-01 11:39:59 +00:00
Aleksey Gurtovoy
af50c640ab MSVC 6.5 + STLPort 4.5.3 workaround
[SVN r24207]
2004-07-31 12:27:25 +00:00
Michael Glassford
b5c5fbe0f5 #include <string> before every #<stdexcept> to eliminate compile errors on VC++ 6 with STLPort-4.5.3 when standard exceptions are thrown with a string literal passed to the constructor.
[SVN r24159]
2004-07-29 14:25:30 +00:00
Douglas Gregor
b88ae8105e Converted to Boost Software License, Version 1.0
[SVN r24055]
2004-07-26 00:32:12 +00:00
Michael Glassford
9ad04bb65e Handle locks that timeout.
[SVN r23999]
2004-07-23 18:39:50 +00:00
Michael Glassford
13bbaab1c4 Removed incorrect assertions.
[SVN r23916]
2004-07-21 20:57:31 +00:00
Michael Glassford
09ca8d1728 Update copyright to use Boost License 1.0, with permission from Mac Murrett.
[SVN r23914]
2004-07-21 20:44:45 +00:00
Michael Glassford
9797a93d86 Fix typos.
[SVN r23913]
2004-07-21 20:43:54 +00:00
Michael Glassford
d29dae72de Clean up scheduling algorithms to pass unit tests and hopefully eliminate reported deadlocks. Still needs work, but should be better than before.
[SVN r23849]
2004-07-20 20:25:18 +00:00
Vladimir Prus
59fba2bff6 Fix minor issue gcc 3.4 found. The test was trying to pass rvalue to
function taking reference, and this requires, according to standard,
accessible copy ctor, which boost::thread does not have.


[SVN r23838]
2004-07-20 13:13:22 +00:00
Michael Glassford
0350d4c501 Renamed add_thread_exit() to at_thread_exit(), a better name.
[SVN r23796]
2004-07-19 14:25:00 +00:00
Vladimir Prus
d3e4a90e70 More V2 Jamfile tweaks.
[SVN r23764]
2004-07-19 07:12:45 +00:00
Michael Glassford
8ebb19fd18 Call on_thread_exit() after thread function has exited to clean up tss on boost-created threads.
[SVN r23715]
2004-07-17 23:15:50 +00:00
Michael Glassford
02ddc33e6c Replace tabs with spaces.
[SVN r23714]
2004-07-17 23:13:06 +00:00
Michael Glassford
410e8efeba Fix warnings on some compilers.
[SVN r23691]
2004-07-17 15:31:28 +00:00
Rene Rivera
e9f8e0bad9 Prevent use of auto-link functionality as it can't be used within regression testing.
[SVN r23667]
2004-07-17 05:44:06 +00:00
Rene Rivera
f69e0313dc Add an import to std namespace in boost_error function for tools/runtimes that put snprintf and related functions there. This fixes the unqualified use of snprintf (as _sntprintf) in CodeWarrior 8.
[SVN r23666]
2004-07-17 05:42:22 +00:00
Rene Rivera
baa9b396d9 Fix some compilation problems on Win32 platforms because of inconsistent line-endings.
[SVN r23663]
2004-07-17 04:33:59 +00:00
Michael Glassford
a82b0c516d Remove line-continuation inside #if (cwpro8 seemed not to like it).
[SVN r23662]
2004-07-17 03:52:59 +00:00
Michael Glassford
43e2192aa2 Proofreading changes.
[SVN r23661]
2004-07-17 03:39:07 +00:00
Michael Glassford
4cd6453cac Fix compile errors: some compilers don't like an enum and the namespace it is in to have the same name.
[SVN r23660]
2004-07-17 03:37:00 +00:00
Michael Glassford
921d4c24c2 Fixed many compile errors.
[SVN r23659]
2004-07-17 03:34:51 +00:00
Michael Glassford
4fc7653b12 Move instructions detailing how to use pthreads-win32 into common file threads.jam.
[SVN r23650]
2004-07-16 20:50:18 +00:00
Michael Glassford
9d0e39a7c2 Move instructions detailing how to use pthreads-win32 into common file threads.jam.
[SVN r23645]
2004-07-16 19:58:32 +00:00
Michael Glassford
7aa979cf5b Add instructions detailing how to use pthreads-win32.
[SVN r23643]
2004-07-16 19:57:59 +00:00
Michael Glassford
0aa50614d7 Add missing typenames, fix duplicate explicit template instantiation.
[SVN r23610]
2004-07-16 02:27:29 +00:00
Michael Glassford
6f402c7362 Add "<sysinclude>$(BOOST_ROOT)" to templates to get boost include files on compiler command line.
[SVN r23603]
2004-07-15 20:41:38 +00:00
Michael Glassford
2bf43a124d Document read_lock, write_lock, and related classes.
[SVN r23590]
2004-07-15 15:29:03 +00:00
Michael Glassford
3573c53eda Add notes about liability of mutex, lock, read/write mutex, nad read/write lock concepts to change; document read_lock, write_lock, and related classes; document throwing promote().
[SVN r23589]
2004-07-15 15:27:39 +00:00
Michael Glassford
4546ec4ef7 Detail newest changes.
[SVN r23587]
2004-07-15 15:22:44 +00:00
Michael Glassford
2f7337aaf6 Remove invalid line ending, "\\r\\n\\n".
[SVN r23555]
2004-07-14 18:49:51 +00:00
Michael Glassford
046698bcc2 Remove invalid typename (accepted by MSVC++ 6 and 7.1, but not by some compilers).
[SVN r23547]
2004-07-14 15:29:30 +00:00
Michael Glassford
06d7bf21d5 Add newline at end of file.
[SVN r23499]
2004-07-13 15:24:11 +00:00
Michael Glassford
e7b9ccdf10 Fix compile error.
[SVN r23498]
2004-07-13 15:18:16 +00:00
Michael Glassford
1e15b043a0 Add hooks for users to provide there own tss cleanup in win32 statically linked builds.
[SVN r23493]
2004-07-13 14:51:23 +00:00
Michael Glassford
6c5f3d76e2 Modify constructors; add promote() that throws exception if it fails; fix enum definition.
[SVN r23492]
2004-07-13 14:42:26 +00:00
Michael Glassford
8679d6f6af Removed enums that will no longer be used.
[SVN r23491]
2004-07-13 14:40:08 +00:00
Michael Glassford
f1c7d0f354 Fix enum definition; add newline at end of file.
[SVN r23490]
2004-07-13 14:39:25 +00:00
Michael Glassford
261e413500 Add promote() that throws exception if it fails; fix enum definition.
[SVN r23489]
2004-07-13 14:38:42 +00:00
Michael Glassford
094e41d7a7 Add newline at end of file.
[SVN r23488]
2004-07-13 14:37:50 +00:00
Michael Glassford
e20299c8ee Add promote() that throws exception if it fails.
[SVN r23487]
2004-07-13 14:36:59 +00:00
Michael Glassford
f8962b7ad2 Changes for WinCE.
[SVN r23486]
2004-07-13 14:34:20 +00:00
Michael Glassford
c34f829c3e Add lock_state and blocking_mode needed by read_write_lock and related classes.
[SVN r23418]
2004-07-09 11:08:54 +00:00
Michael Glassford
46264e4a4a Apply patch for SGI MIPSpro compiler.
[SVN r23406]
2004-07-08 14:42:04 +00:00
Michael Glassford
096df68ea6 Add title.
[SVN r23405]
2004-07-08 13:52:15 +00:00
Vladimir Prus
35f2055a1e Fix some typos. Thanks to Jurgen Hunold for the patch.
[SVN r23404]
2004-07-08 13:46:51 +00:00
Michael Glassford
e1353eefb3 Proofreeding changes.
[SVN r23381]
2004-07-06 18:44:33 +00:00
Michael Glassford
4911a532bf Merge read/write mutex from thread_dev branch.
[SVN r23380]
2004-07-06 17:35:53 +00:00
Michael Glassford
96362e03aa Changes for WinCE.
[SVN r23379]
2004-07-06 17:33:49 +00:00
Michael Glassford
049b4e09fe Changes for WinCE.
[SVN r23378]
2004-07-06 17:28:24 +00:00
Michael Glassford
828c0e28af Win32: use CreateMutexA instead of CreateMutex to prevent compile errors in Unicode builds.
[SVN r23377]
2004-07-06 17:22:21 +00:00
Michael Glassford
15a638edc0 Merge exception class changes thread_dev branch (thread exceptions now have a common base class and methods for reporting the OS error that caused the exception to be thrown, if any).
[SVN r23376]
2004-07-06 17:20:55 +00:00
Michael Glassford
fc8f1b1075 Merge read/write mutex from thread_dev branch.
[SVN r23375]
2004-07-06 17:11:31 +00:00
Michael Glassford
318a8e38c9 Merge exception class changes thread_dev branch (thread exceptions now have a common base class and methods for reporting the OS error that caused the exception to be thrown, if any).
[SVN r23374]
2004-07-06 17:09:11 +00:00
Michael Glassford
f0dbb02a9f Disable auto-link when building static library.
[SVN r23373]
2004-07-06 17:03:43 +00:00
Michael Glassford
649b777b76 Merge from thread_dev branch: convert documentation to BoostBook format.
[SVN r23300]
2004-07-01 14:06:07 +00:00
Michael Glassford
6fad43670a Merge from thread_dev branch: convert documentation to BoostBook format.
[SVN r23299]
2004-07-01 14:01:51 +00:00
Michael Glassford
e24b16229e Cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23197]
2004-06-25 20:46:31 +00:00
Michael Glassford
21b4b81810 Cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23191]
2004-06-25 20:27:13 +00:00
Michael Glassford
1096b1e28e Cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23190]
2004-06-25 20:22:02 +00:00
Michael Glassford
03458fedef Add option to build as static library.
[SVN r23189]
2004-06-25 20:17:19 +00:00
Michael Glassford
c1a2004344 Cleanup: always #include <boost/thread/detail/config.hpp> first; eliminate tabs; etc.
[SVN r23188]
2004-06-25 20:04:34 +00:00
Michael Glassford
2adb13a209 Cleanup: always #include <boost/thread/detail/config.hpp> first; TimedLock concept is a refinement of TryLock.
[SVN r23181]
2004-06-25 14:35:55 +00:00
Michael Glassford
dba194ddb9 Change enumeration from anonymous to xtime_clock_types and remove unused clock types.
[SVN r23150]
2004-06-22 21:25:58 +00:00
Vladimir Prus
8179f041e6 Update V2 Jamfiles
[SVN r23076]
2004-06-10 12:22:55 +00:00
Vladimir Prus
a13c7a4d84 Add newline at the end of file, to stop gcc warning
[SVN r23075]
2004-06-10 12:20:01 +00:00
Michael Glassford
bbf92bb971 Fix gcc 3.3.1 compiler warning.
[SVN r23007]
2004-06-02 18:53:39 +00:00
Victor A. Wagner Jr.
b33f413635 Removed the extra cr from the end of line sequence in the source
[SVN r22982]
2004-05-31 11:48:48 +00:00
Michael Glassford
58ffb2bc16 Win32: use critical section instead of mutex whenever possible; abstract common code into functions.
[SVN r22828]
2004-05-15 02:03:48 +00:00
Michael Glassford
0ed112631c Merge tss changes from thread_dev branch.
[SVN r22560]
2004-03-27 02:03:52 +00:00
Michael Glassford
9cfe8e9422 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
Eric Niebler
7d3fe72970 remove minmax hack from win32.hpp and fix all places that could be affected by the minmax macros
[SVN r22394]
2004-02-26 18:27:02 +00:00
Michael Glassford
ac422138fa Merge barrier from thread_dev branch.
[SVN r22374]
2004-02-23 17:53:56 +00:00
Michael Glassford
bf8746454a Merge barrier from thread_dev branch.
[SVN r22373]
2004-02-23 17:29:40 +00:00
Michael Glassford
b61aa5b4ba Merge changes from thread_dev branch.
[SVN r22323]
2004-02-19 01:24:50 +00:00
Michael Glassford
c2bcd08168 Merge minor changes from thread_dev branch.
[SVN r22322]
2004-02-19 01:16:06 +00:00
Michael Glassford
48593b8868 Merge minor changes from thread_dev branch.
[SVN r22308]
2004-02-18 01:15:36 +00:00
Michael Glassford
83d4dc1831 Merge minor changes from thread_dev branch.
[SVN r22307]
2004-02-18 00:53:09 +00:00
John Maddock
0696f3cc41 Added auto-link code to thread library
[SVN r21575]
2004-01-10 12:16:42 +00:00
Rene Rivera
515590495a Fix tabs in file.
[SVN r21399]
2003-12-26 23:26:49 +00:00
John Maddock
7221bca909 Added <runtime-link>dynamic requirement to dll build.
[SVN r21355]
2003-12-20 12:55:40 +00:00
John Maddock
ed64a8cd12 Changed #errors to use new requires_threads.hpp header instead.
[SVN r21351]
2003-12-20 11:56:37 +00:00
Beman Dawes
cbd30d22ff fix links broken by index.htm to index.html renaming
[SVN r21233]
2003-12-12 00:00:13 +00:00
Dave Abrahams
0c74dbd436 * Fixed Boost.Thread jamfile to add the missing #include paths
* Modified Python testing code to use the facilities of testing.jam,
  so that it can be processed with process_jam_log

* Updated Python library tests to use a test suite

* Added Python test suite to status/Jamfile

* Added --run-all-tests option to force tests to run even when up-to-date.


Also,
boost-base.jam:

    Added some missing rule signatures

    RUN_LD_LIBRARY_PATH became LINK_LIBPATH because it was only really
    used during linking.

    Reformed the movement of path variables up the dependency graph

    Removed the defunct Run rule

    Set up generalized constants for path manipulation

darwin-tools.jam, gcc-tools.jam:

   use LINK_LIBPATH

python.jam:

   Reformed the choice of Python executable

testing.jam:

   Refactored testing code so it could be used for Python

   Now building all environment variable setup code ahead of time

   RUN_TEST became TEST_EXE


[SVN r20815]
2003-11-15 15:41:41 +00:00
Rene Rivera
49356cc931 Add install definitions for new common install configuration.
[SVN r20409]
2003-10-19 19:52:56 +00:00
Vladimir Prus
ceee6e8b17 Add V2 Jamfile
[SVN r20271]
2003-10-07 08:10:42 +00:00
Dave Abrahams
61ab2754d2 Use the import rule
[SVN r19968]
2003-09-08 17:38:49 +00:00
Dave Abrahams
2de3df61e8 Updates for Win32 builds
[SVN r19727]
2003-08-22 03:41:42 +00:00
Dave Abrahams
b84d7aa06d Port "conditin.hpp" typo fix over from Version_1_30_2
[SVN r19725]
2003-08-21 22:51:38 +00:00
Dave Abrahams
ed48f900a3 Compile on Windows; add some requirements and default-build (though
the latter shouldn't be neccessary?!)


[SVN r19715]
2003-08-20 13:51:35 +00:00
Beman Dawes
d197a49707 fix typo
[SVN r19214]
2003-07-19 14:21:00 +00:00
Beman Dawes
b8ccaa3bf6 Add Wirth's view of semaphores
[SVN r19213]
2003-07-19 14:08:32 +00:00
Beman Dawes
507a684b21 Add [Brinch Hansen 02]
[SVN r19212]
2003-07-19 14:07:50 +00:00
Beman Dawes
c969c9387a Expand semaphore FAQ
[SVN r18952]
2003-07-07 00:39:06 +00:00
William E. Kempf
1709db4953 Fixed exception handling bug in once.cpp.
[SVN r18933]
2003-07-03 13:31:27 +00:00
William E. Kempf
4d1c9ba316 Attempted to fix race condition in test_tss.cpp.
[SVN r18838]
2003-06-18 20:50:15 +00:00
William E. Kempf
45b0396355 Removed Borland warnings.
[SVN r17605]
2003-02-23 17:38:11 +00:00
William E. Kempf
1df2169e48 Removed new(nothrow) calls.
[SVN r17586]
2003-02-22 04:54:19 +00:00
William E. Kempf
2c056b3621 Added acknowledgement for Martin Johnson's help with shared library implementation
[SVN r17510]
2003-02-18 17:02:29 +00:00
William E. Kempf
680119006c Unlocked mutex in all control paths in notify_all
[SVN r17509]
2003-02-18 16:59:03 +00:00
Björn Karlsson
c4ac4b7538 Added copyright statement
[SVN r17222]
2003-02-05 08:38:32 +00:00
William E. Kempf
ff5d3b49ca Updated format (removed tabs) and added missing copyrights
[SVN r17214]
2003-02-04 23:23:02 +00:00
William E. Kempf
e101c878f0 Updated format (removed tabs) and added missing copyrights
[SVN r17213]
2003-02-04 23:08:28 +00:00
William E. Kempf
125193dcfa Turned all tests into 'timed_test's.
[SVN r17053]
2003-01-27 22:44:06 +00:00
Beman Dawes
77efa9810d Local include util.inl
[SVN r17041]
2003-01-25 14:23:36 +00:00
William E. Kempf
7f03d1917b Removed accidental sleep
[SVN r17035]
2003-01-24 18:15:22 +00:00
William E. Kempf
55b4ca9350 Added 'timed_test' support to prevent deadlocks in tests
[SVN r17032]
2003-01-24 16:51:13 +00:00
William E. Kempf
7196a0f9d2 Updated build files
[SVN r17021]
2003-01-23 23:23:36 +00:00
William E. Kempf
2caabde5ca Updated Jamfile to use test-suite
[SVN r17014]
2003-01-23 19:47:29 +00:00
Vladimir Prus
137d7663c1 Change use-requirements to usage-requirements in some library Jamfiles.
[SVN r16884]
2003-01-13 12:31:12 +00:00
Vladimir Prus
508b71a921 Update V2 Jamfile for Boost.
[SVN r16882]
2003-01-13 10:05:01 +00:00
Beman Dawes
5d90820005 fix bookmarks
[SVN r16827]
2003-01-09 13:37:41 +00:00
Beman Dawes
84727e90b1 fix invalid bookmarks
[SVN r16825]
2003-01-09 13:22:04 +00:00
William E. Kempf
9a1e3d3320 Added <boost/thread.hpp>.
[SVN r16796]
2003-01-08 15:08:32 +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
134 changed files with 17552 additions and 0 deletions

2
build/.cvsignore Normal file
View File

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

122
build/Jamfile Normal file
View File

@@ -0,0 +1,122 @@
# Copyright 2006 Roland Schwarz.
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
subproject libs/thread/build ;
import ./threads ;
# pthreads is compiled on all platforms when available
if [ threads::is-pthread-available ] {
template pthread_base
: ## sources ##
[ threads::cpp_source ../src/pthread :
thread
mutex
recursive_mutex
condition
exceptions
xtime
once
tss
]
: ## requirements ##
threads::lib-pthread
<sysinclude>$(BOOST_ROOT)
<threading>multi
<define>BOOST_THREAD_POSIX
common-variant-tag
<borland><*><cxxflags>-w-8004
<borland><*><cxxflags>-w-8057
;
lib boost_thread_pthread
: <template>pthread_base
: ## requirements ##
<define>BOOST_THREAD_BUILD_LIB=1
;
dll boost_thread_pthread
: <template>pthread_base
: ## requirements ##
<runtime-link>dynamic
<define>BOOST_THREAD_BUILD_DLL=1
;
stage bin-stage
: <dll>boost_thread_pthread
<lib>boost_thread_pthread
;
install thread_pthread lib
: <dll>boost_thread_pthread
<lib>boost_thread_pthread
;
# the next is true on platforms where pthreads is native threading lib
if [ threads::is-native-on-build-os pthread ] {
lib boost_thread
: <template>pthread_base
: ## requirements ##
<define>BOOST_THREAD_BUILD_LIB=1
;
dll boost_thread
: <template>pthread_base
: ## requirements ##
<runtime-link>dynamic
<define>BOOST_THREAD_BUILD_DLL=1
;
}
}
if [ threads::is-native-on-build-os win32 ] {
template win32_base
: ## sources ##
[ threads::cpp_source ../src/win32 :
thread
exceptions
xtime
tss
tss_hooks
tss_dll
tss_pe
]
: ## requirements ##
<sysinclude>$(BOOST_ROOT)
<threading>multi
common-variant-tag
<borland><*><cxxflags>-w-8004
<borland><*><cxxflags>-w-8057
;
lib boost_thread
: <template>win32_base
: ## requirements ##
<define>BOOST_THREAD_BUILD_LIB=1
;
dll boost_thread
: <template>win32_base
: ## requirements ##
<runtime-link>dynamic
<define>BOOST_THREAD_BUILD_DLL=1
;
}
stage bin-stage
: <dll>boost_thread
<lib>boost_thread
;
install thread lib
: <dll>boost_thread
<lib>boost_thread
;

61
build/Jamfile.v2 Normal file
View File

@@ -0,0 +1,61 @@
# Copyright 2006 Roland Schwarz.
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
import thread ;
project boost/thread
: source-location ../src
: requirements <threading>multi
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
: default-build <threading>multi [ thread.default-api ]
;
# build the pthread based variant
lib boost_thread_pthread
: ## sources ##
pthread/thread.cpp
pthread/mutex.cpp
pthread/recursive_mutex.cpp
pthread/condition.cpp
pthread/exceptions.cpp
pthread/xtime.cpp
pthread/tss.cpp
: ## requirements ##
<define>BOOST_THREAD_POSIX
<thrd-api>pthread
;
# use pthread on platforms where pthread is considered native
lib boost_thread
: ## sources ##
pthread/thread.cpp
pthread/mutex.cpp
pthread/recursive_mutex.cpp
pthread/condition.cpp
pthread/exceptions.cpp
pthread/xtime.cpp
pthread/tss.cpp
: ## requirements ##
<define>BOOST_THREAD_POSIX
<thrd-api>pthread
;
# the win32 native variant
lib boost_thread
: ## sources ##
win32/thread.cpp
win32/exceptions.cpp
win32/xtime.cpp
win32/tss.cpp
win32/tss_hooks.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
: ## requirements ##
<thrd-api>win32
;

70
build/thread.jam Normal file
View File

@@ -0,0 +1,70 @@
# Copyright 2006 Roland Schwarz.
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
import modules ;
import os ;
import feature ;
import property ;
# supported threading api's
feature.feature thrd-api : pthread win32 : symmetric ;
# save a reference to the original lib rule
IMPORT : lib : $(__name__) : type.lib ;
# local override of the global lib rule
rule lib ( name : sources * : requirements * : default-build * : usage-requirements * )
{
if <thrd-api>pthread in $(requirements)
{
if [ os.name ] = "NT"
{
local PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
local PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
if $(PTW32_INCLUDE) && $(PTW32_LIB)
{
requirements =
[ property.refine $(requirements) :
<define>BOOST_HAS_PTHREADS
<include>$(PTW32_INCLUDE)
<library>$(PTW32_LIB)
] ;
}
else
{
requirements += <build>no ;
# it would be nice if this message appears only once ...
# but I cannot figure out how to detectd the second phase.
echo "******************************************************" ;
echo "Building Boost.Thread without pthread support" ;
echo "If you need pthread you should specify the paths." ;
echo "For example:" ;
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib\\pthreadVC2.lib" ;
echo "******************************************************" ;
}
}
}
return [ type.lib $(name) : $(sources) : $(requirements) : $(default-build) : $(usage-requirements) ] ;
}
# auto export of rule lib to calling module only
IMPORT $(__name__) : lib : [ CALLER_MODULE 1 ] : lib ;
rule default-api
{
if [ os.name ] = "NT"
{
return <thrd-api>win32 ;
}
else
{
return <thrd-api>pthread ;
}
}

65
build/threads.jam Normal file
View File

@@ -0,0 +1,65 @@
# Copyright 2006 Roland Schwarz.
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
# find out if pthread is available on current build platform
rule threads::is-pthread-available
{
if $(OS) = "NT" {
if $(PTW32_INCLUDE) && $(PTW32_LIB) {
return true ;
}
else {
ECHO "******************************************************" ;
ECHO "Building Boost.Thread without pthread support" ;
ECHO "If you need pthread you should specify the paths." ;
ECHO "For example:" ;
ECHO "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
ECHO "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib\\pthreadVC2.lib" ;
ECHO "******************************************************" ;
}
}
else if $(OS) = "LINUX" {
return true ;
}
else { ## assume pthread is available on unknown os for now
return true ;
}
}
# find the native library variant for current build os
rule threads::is-native-on-build-os ( libvariant )
{
if $(OS) = "NT" {
if $(libvariant) = win32 { return true ; }
}
else if $(OS) = "LINUX" {
if $(libvariant) = pthread { return true ; }
}
else { ## assume pthread is native on others for now
if $(libvariant) = pthread { return true ; }
}
}
# utility to prepend the source path to the cpp sources
rule threads::cpp_source ( path : sources * )
{
return $(path)/$(sources).cpp ;
}
# impose the pthread library and include path on the requirements
rule threads::lib-pthread ( toolset variant : subvariant-path properties * )
{
if $(OS) = "NT" && $(PTW32_INCLUDE) && $(PTW32_LIB) {
properties = [ impose-requirements $(properties) :
<define>BOOST_HAS_PTHREADS
<include>$(PTW32_INCLUDE)
<library-file>$(PTW32_LIB) ] ;
}
return $(subvariant-path) $(properties) ;
}

6
doc/Jamfile.v2 Normal file
View File

@@ -0,0 +1,6 @@
import toolset ;
toolset.using doxygen ;
boostbook thread : 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, 1973</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>

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

8
doc/index.html Normal file
View File

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

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

@@ -0,0 +1,305 @@
<?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>
<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>
<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>
<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,458 @@
<?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 typedefs,
which <link linkend="threads.concepts.read-write-lock-models">model</link>
the specified locking strategies:
<informaltable>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_read_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_read_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</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_read_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_read_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_write_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 strategies:
<informaltable>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_read_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_try_read_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_read_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_read_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
<row>
<entry>scoped_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</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_read_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_read_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_read_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_read_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_write_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 strategies:
<informaltable>
<tgroup cols="2" align="left">
<thead>
<row>
<entry>Lock Name</entry>
<entry>Lock Concept</entry>
</row>
</thead>
<tbody>
<row>
<entry>scoped_read_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedReadWriteLock">ScopedReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_try_read_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryReadWriteLock">ScopedTryReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_timed_read_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedTimedReadWriteLock">ScopedTimedReadWriteLock</link></entry>
</row>
<row>
<entry>scoped_read_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_read_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
<row>
<entry>scoped_timed_read_lock</entry>
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</link></entry>
</row>
<row>
<entry>scoped_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedLock">ScopedLock</link></entry>
</row>
<row>
<entry>scoped_try_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedTryLock">ScopedTryLock</link></entry>
</row>
<row>
<entry>scoped_timed_write_lock</entry>
<entry><link linkend="threads.concepts.ScopedTimedLock">ScopedTimedLock</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_read_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_read_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_timed_read_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_read_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_read_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_timed_read_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_try_write_lock">
<type><emphasis>implementation-defined</emphasis></type>
</typedef>
<typedef name="scoped_timed_write_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>

144
doc/release_notes.xml Normal file
View File

@@ -0,0 +1,144 @@
<?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>Statically-link build option added</title>
<para>The option to link &Boost.Threads; as a static
library has been added (with some limitations on Win32 platforms).
This feature was originally removed from an earlier version
of Boost 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.
Because this limitation never applied to non-Win32 platforms,
because significant progress has been made in removing
the limitation on Win32 platforms (many thanks to
Aaron LaFramboise and Roland Scwarz!), and because the lack
of static linking is one of the most common complaints of
&Boost.Threads; users, this decision was reversed.</para>
<para>On non-Win32 platforms:
To choose the dynamically linked version of &Boost.Threads;
using Boost's auto-linking feature, #define BOOST_THREAD_USE_DLL;
to choose the statically linked version,
#define BOOST_THREAD_USE_LIB.
If neither symbols is #defined, the default will be chosen.
Currently the default is the statically linked version.</para>
<para>On Win32 platforms using VC++:
Use the same #defines as for non-Win32 platforms
(BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB).
If neither is #defined, the default will be chosen.
Currently the default is the statically linked version
if the VC++ run-time library is set to
"Multi-threaded" or "Multi-threaded Debug", and
the dynamically linked version
if the VC++ run-time library is set to
"Multi-threaded DLL" or "Multi-threaded Debug DLL".</para>
<para>On Win32 platforms using compilers other than VC++:
Use the same #defines as for non-Win32 platforms
(BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB).
If neither is #defined, the default will be chosen.
Currently the default is the dynamically linked version
because it has not yet been possible to implement automatic
tss cleanup in the statically linked version for compilers
other than VC++, although it is hoped that this will be
possible in a future version of &Boost.Threads;.
Note for advanced users: &Boost.Threads; provides several "hook"
functions to allow users to experiment with the statically
linked version on Win32 with compilers other than VC++.
These functions are on_process_enter(), on_process_exit(),
on_thread_enter(), and on_thread_exit(), and are defined
in tls_hooks.cpp. See the comments in that file for more
information.</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.
<note>Since the read/write mutex and related classes are new,
both interface and implementation are liable to change
in future releases of &Boost.Threads;.
The lock concepts and lock promotion in particular are
still under discussion and very likely to change.</note>
</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 id="threads.release_notes.boost_1_32_0.change_log.wince">
<title>Windows CE support improved</title>
<para>Minor changes were made to make Boost.Threads work on Windows CE.</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>

49
doc/thread.xml Normal file
View File

@@ -0,0 +1,49 @@
<?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>

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,52 @@
# Copyright (C) 2006 Roland Schwarz.
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
#
# The threading library is available in two versions.
# Native to the environment or based ontop pthread.
# To select which version to use you need to define
# BOOST_THREAD_POSIX when compiling your sources.
# If BOOST_THREAD_POSIX is defined this will choose
# pthread implementation.
# You also need to specify the correct library version by
# specifying the the <lib> or <dll> tags.
# <lib>@boost/libs/thread/build/boost_thread for static native and
# <lib>@boost/libs/thread/build/boost_thread_pthread static pthread.
# If your compiler does not have the pthread lib in a standard
# include path, you need to specify that too, with <include> and
# <library-file>.
project-root ;
template example
: ## sources ##
<lib>@boost/libs/thread/build/boost_thread
#<lib>@boost/libs/thread/build/boost_thread_pthread
#<dll>@boost/libs/thread/build/boost_thread
#<dll>@boost/libs/thread/build/boost_thread_pthread
: ## requirements ##
<include>$(BOOST_ROOT)
# uncomment below to get pthread on windows
#<define>BOOST_THREAD_POSIX
#<include>$(PTW32_INCLUDE)
#<library-file>$(PTW32_LIB)
: ## default build ##
<threading>multi
;
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
;

53
example/Jamrules Normal file
View File

@@ -0,0 +1,53 @@
# Copyright 2003 William E. Kempf
# Copyright 2006 Roland Schwarz
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
project example ;
# If you move this example from its place in the Boost tree, edit this
# path to point at the root directory of your Boost installation (the
# one containing a subdirectory called "boost/".
path-global BOOST_ROOT : ../../.. ;
# Makes a project id for boost so that other Boost.Build projects can
# refer to it by name.
#
project boost : $(BOOST_ROOT) ;
# Attn: path-global was broken in my version of bbv1, which prevented specifying
# BOOST_ROOT as a relative path. So I needed to apply
# the below fix in allyourbase.jam as shown below:
#
#rule project ( name : location ? )
#{
# if ! $(location)
# {
# gPROJECT($(name)) = $(gPROJECT($(PROJECT))) ;
# PROJECT($(gPROJECT($(name)))) = $(name) ;
# PROJECT = $(name) ;
# }
# else
# {
# gPROJECT($(name)) = [ root-paths $(location) : [ root-paths $($(gTOP)) : [ PWD ] ] ] ;
# # speedsnail
# # Root the path globals to fix a bug which prevented to use them from an external
# # project. The fix is as as uninvasive as possible, as it will only trigger when
# # an external project is declared. So it will not interfere with the build of the
# # boost library. I took this route, as at the time of this fix, the bbv1 is expected
# # to be retired soon.
# # N.B.: The path-globals rule is expected to be invoked from Jamrules files only.
# local val ;
# for val in $(gPATH_GLOBALS) {
# gPATH_GLOBAL_VALUE($(val)) = [ root-paths $(gPATH_GLOBAL_VALUE($(val))) :
# [ root-paths $($(gTOP)) : [ PWD ] ]
# ] ;
# }
# local [ protect-subproject ] ;
# enter-subproject @$(name) ;
# }
#}

22
example/boost-build.jam Executable file
View File

@@ -0,0 +1,22 @@
# Copyright 2006 Roland Schwarz.
# Distributed under the Boost Software License, Version 1.0. (See
# accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
#
# This work is a reimplementation along the design and ideas
# of William E. Kempf.
#
# Edit this path to point at the tools/build/v1 subdirectory of your
# Boost installation.
if --v2 in $(ARGV)
{
JAMFILE = [Bb]uild.jam [Jj]amfile.v2 ;
boost-build ../../../tools/build/v2 ;
}
else
{
boost-build ../../../tools/build/v1 ;
}

75
example/condition.cpp Normal file
View File

@@ -0,0 +1,75 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <iostream>
#include <vector>
#include <boost/utility.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
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;
std::vector<int>::size_type 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;
}

112
example/monitor.cpp Normal file
View File

@@ -0,0 +1,112 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <vector>
#include <iostream>
#include <boost/thread/condition.hpp>
#include <boost/thread/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;
}

47
example/mutex.cpp Normal file
View File

@@ -0,0 +1,47 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/mutex.hpp>
#include <boost/thread/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;
}

31
example/once.cpp Normal file
View File

@@ -0,0 +1,31 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/thread.hpp>
#include <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,49 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/recursive_mutex.hpp>
#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;
}

185
example/starvephil.cpp Normal file
View File

@@ -0,0 +1,185 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <iostream>
#include <time.h>
namespace
{
boost::mutex iomx;
} // namespace
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;
}

135
example/tennis.cpp Normal file
View File

@@ -0,0 +1,135 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/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();
}

26
example/thread_group.cpp Normal file
View File

@@ -0,0 +1,26 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/thread.hpp>
#include <iostream>
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();
}

36
example/tss.cpp Normal file
View File

@@ -0,0 +1,36 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/thread.hpp>
#include <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();
}

16
example/xtime.cpp Normal file
View File

@@ -0,0 +1,16 @@
// Copyright (C) 2001-2003 William E. Kempf
// Distributed under the Boost Software License, Version 1.0 (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt
//
#include <boost/thread/thread.hpp>
#include <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
}

24
include/boost/thread.hpp Normal file
View File

@@ -0,0 +1,24 @@
// 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.
#if !defined(BOOST_THREAD_WEK01082003_HPP)
#define BOOST_THREAD_WEK01082003_HPP
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/tss.hpp>
#include <boost/thread/xtime.hpp>
#endif

View File

@@ -0,0 +1,64 @@
#ifndef BOOST_THREAD_BARRIER_HPP
#define BOOST_THREAD_BARRIER_HPP
// barrier.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstddef>
#include <stdexcept>
#include <boost/thread/detail/platform.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std
{
using ::size_t;
}
#endif
namespace boost
{
class barrier
{
boost::mutex m;
boost::condition cond;
const std::size_t max_count;
std::size_t current_count;
public:
barrier(std::size_t count):
max_count(count),current_count(0)
{
if(!max_count)
{
throw std::invalid_argument("You must specify a non-zero count");
}
}
bool wait()
{
boost::mutex::scoped_lock lock(m);
if(++current_count==max_count)
{
current_count=0;
cond.notify_all();
return true;
}
else
{
cond.wait(lock);
return false;
}
}
};
}
#endif

View File

@@ -0,0 +1,16 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040706_HPP
#define BOOST_THREAD_RS06040706_HPP
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(condition.hpp)
#endif // BOOST_THREAD_RS06040706_HPP

View File

@@ -0,0 +1,72 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040501_HPP
#define BOOST_THREAD_RS06040501_HPP
// fetch compiler and platform configuration
#include <boost/config.hpp>
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
// choose platform
#if defined(linux) || defined(__linux) || defined(__linux__)
# define BOOST_THREAD_LINUX
#elif defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
# define BOOST_THREAD_BSD
#elif defined(sun) || defined(__sun)
# define BOOST_THREAD_SOLARIS
#elif defined(__sgi)
# define BOOST_THREAD_IRIX
#elif defined(__hpux)
# define BOOST_THREAD_HPUX
#elif defined(__CYGWIN__)
# define BOOST_THREAD_CYGWIN
#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
# define BOOST_THREAD_WIN32
#elif defined(__BEOS__)
# define BOOST_THREAD_BEOS
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define BOOST_THREAD_MACOS
#elif defined(__IBMCPP__) || defined(_AIX)
# define BOOST_THREAD_AIX
#elif defined(__amigaos__)
# define BOOST_THREAD_AMIGAOS
#elif defined(__QNXNTO__)
# define BOOST_THREAD_QNXNTO
#elif defined(unix) || defined(__unix) || defined(_XOPEN_SOURCE) || defined(_POSIX_SOURCE)
# if defined(BOOST_HAS_PTHREADS) && !defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_POSIX
# endif
#endif
// For every supported platform add a new entry into the dispatch table below.
// BOOST_THREAD_POSIX is tested first, so on platforms where posix and native
// threading is available, the user may choose, by defining BOOST_THREAD_POSIX
// in her source. If a platform is known to support pthreads and no native
// port of boost_thread is available just specify "pthread" in the
// dispatcher table. If there is no entry for a platform but pthreads is
// available on the platform, pthread is choosen as default. If nothing is
// available the preprocessor will fail with a diagnostic message.
#if defined(BOOST_THREAD_POSIX)
# define BOOST_THREAD_PPFX pthread
#else
# if defined(BOOST_THREAD_WIN32)
# define BOOST_THREAD_PPFX win32
# elif defined(BOOST_HAS_PTHREADS)
# define BOOST_THREAD_PPFX pthread
# else
# error "Sorry, no boost threads are available for this platform."
# endif
#endif
#define BOOST_THREAD_PLATFORM(header) <boost/thread/BOOST_THREAD_PPFX/header>
#endif // BOOST_THREAD_RS06040501_HPP

View File

@@ -0,0 +1,16 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040710_HPP
#define BOOST_THREAD_RS06040710_HPP
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(exceptions.hpp)
#endif // BOOST_THREAD_RS06040710_HPP

View File

@@ -0,0 +1,16 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040704_HPP
#define BOOST_THREAD_RS06040704_HPP
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(mutex.hpp)
#endif // BOOST_THREAD_RS06040704_HPP

View File

@@ -0,0 +1,16 @@
#ifndef BOOST_THREAD_ONCE_HPP
#define BOOST_THREAD_ONCE_HPP
// once.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(once.hpp)
#endif

View File

@@ -0,0 +1,156 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040707_HPP
#define BOOST_THREAD_RS06040707_HPP
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp>
#include <boost/thread/pthread/lock.hpp>
#include <pthread.h>
namespace boost {
struct xtime;
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
namespace detail {
class BOOST_THREAD_DECL condition_impl : private noncopyable
{
friend class condition;
public:
condition_impl();
~condition_impl();
void notify_one();
void notify_all();
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
pthread_cond_t m_condition;
};
} // 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)
{
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);
m_impl.do_wait(state.pmutex);
lock_ops::lock(mutex, state);
#undef lock_ops
}
template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt)
{
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;
ret = m_impl.do_timed_wait(xt, state.pmutex);
lock_ops::lock(mutex, state);
#undef lock_ops
return ret;
}
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif // BOOST_CONDITION_RS06040707_HPP

View File

@@ -0,0 +1,77 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040702_HPP
#define BOOST_THREAD_RS06040702_HPP
#include <boost/config.hpp>
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
#else //Use default
# if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib
# define BOOST_THREAD_USE_LIB
# else
//For compilers not yet supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads dll
# define BOOST_THREAD_USE_DLL
# endif
# else
# define BOOST_THREAD_USE_LIB
# endif
#endif
#if defined(BOOST_HAS_DECLSPEC)
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
# define BOOST_THREAD_DECL __declspec(dllexport)
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
# define BOOST_THREAD_DECL __declspec(dllimport)
# else
# define BOOST_THREAD_DECL
# endif
#else
# define BOOST_THREAD_DECL
#endif // BOOST_HAS_DECLSPEC
//
// 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)
//
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
// once it's done with it:
//
#if defined(BOOST_THREAD_USE_DLL)
# define BOOST_DYN_LINK
#endif
//
// 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_pthread
#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_RS06040702_HPP

View File

@@ -0,0 +1,88 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040709_HPP
#define BOOST_THREAD_RS06040709_HPP
#include <boost/thread/pthread/config.hpp>
#include <string>
#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;
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_RS06040709_HPP

View File

@@ -0,0 +1,205 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040708_HPP
#define BOOST_THREAD_RS06040708_HPP
#include <boost/thread/pthread/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/pthread/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_THREAD_RS06040708_HPP

View File

@@ -0,0 +1,116 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040705_HPP
#define BOOST_THREAD_RS06040705_HPP
#include <boost/thread/pthread/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/pthread/lock.hpp>
#include <pthread.h>
namespace boost {
struct xtime;
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
class BOOST_THREAD_DECL mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<mutex>;
typedef detail::thread::scoped_lock<mutex> scoped_lock;
mutex();
~mutex();
private:
struct cv_state
{
pthread_mutex_t* pmutex;
};
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
pthread_mutex_t m_mutex;
};
class BOOST_THREAD_DECL try_mutex
: private noncopyable
{
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();
~try_mutex();
private:
struct cv_state
{
pthread_mutex_t* pmutex;
};
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
pthread_mutex_t m_mutex;
};
class BOOST_THREAD_DECL timed_mutex
: private noncopyable
{
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();
~timed_mutex();
private:
struct cv_state
{
pthread_mutex_t* pmutex;
};
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);
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
bool m_locked;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif // BOOST_MUTEX_RS06040705_HPP

View File

@@ -0,0 +1,74 @@
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
#define BOOST_THREAD_PTHREAD_ONCE_HPP
// once.hpp
//
// (C) Copyright 2007 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/pthread/config.hpp>
#include <pthread.h>
#include <boost/assert.hpp>
namespace boost {
struct once_flag
{
pthread_mutex_t mutex;
unsigned flag;
};
#define BOOST_ONCE_INIT {PTHREAD_MUTEX_INITIALIZER,0}
namespace detail
{
struct pthread_mutex_scoped_lock
{
pthread_mutex_t * mutex;
explicit pthread_mutex_scoped_lock(pthread_mutex_t* mutex_):
mutex(mutex_)
{
int const res=pthread_mutex_lock(mutex);
BOOST_ASSERT(!res);
}
~pthread_mutex_scoped_lock()
{
int const res=pthread_mutex_unlock(mutex);
BOOST_ASSERT(!res);
}
};
}
template<typename Function>
void call_once(once_flag& flag,Function f)
{
long const function_complete_flag_value=0xc15730e2;
#ifdef BOOST_PTHREAD_HAS_ATOMICS
if(::boost::detail::interlocked_read_acquire(&flag.flag)!=function_complete_flag_value)
{
#endif
detail::pthread_mutex_scoped_lock const lock(&flag.mutex);
if(flag.flag!=function_complete_flag_value)
{
f();
#ifdef BOOST_PTHREAD_HAS_ATOMICS
::boost::detail::interlocked_write_release(&flag.flag,function_complete_flag_value);
#else
flag.flag=function_complete_flag_value;
#endif
}
#ifdef BOOST_PTHREAD_HAS_ATOMICS
}
#endif
}
}
#endif

View File

@@ -0,0 +1,389 @@
#ifndef BOOST_THREAD_PTHREAD_READ_WRITE_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_READ_WRITE_MUTEX_HPP
// (C) Copyright 2006-7 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/xtime.hpp>
namespace boost
{
class read_write_mutex
{
private:
struct state_data
{
unsigned shared_count:10;
unsigned exclusive:1;
unsigned upgradeable:1;
unsigned exclusive_waiting_blocked:1;
};
state_data state;
boost::mutex state_change;
boost::condition shared_cond;
boost::condition exclusive_cond;
boost::condition upgradeable_cond;
void release_waiters()
{
exclusive_cond.notify_one();
shared_cond.notify_all();
}
public:
read_write_mutex()
{
state_data state_={0};
state=state_;
}
~read_write_mutex()
{
}
void lock_shareable()
{
boost::mutex::scoped_lock lock(state_change);
while(true)
{
if(!state.exclusive && !state.exclusive_waiting_blocked)
{
++state.shared_count;
return;
}
shared_cond.wait(lock);
}
}
bool try_lock_shareable()
{
boost::mutex::scoped_lock lock(state_change);
if(state.exclusive || state.exclusive_waiting_blocked)
{
return false;
}
else
{
++state.shared_count;
return true;
}
}
bool timed_lock_shareable(xtime const& timeout)
{
boost::mutex::scoped_lock lock(state_change);
while(true)
{
if(!state.exclusive && !state.exclusive_waiting_blocked)
{
++state.shared_count;
return true;
}
if(!shared_cond.timed_wait(lock,timeout))
{
return false;
}
}
}
void unlock_shareable()
{
boost::mutex::scoped_lock lock(state_change);
bool const last_reader=!--state.shared_count;
if(last_reader)
{
if(state.upgradeable)
{
state.upgradeable=false;
state.exclusive=true;
upgradeable_cond.notify_one();
}
else
{
state.exclusive_waiting_blocked=false;
}
release_waiters();
}
}
void lock()
{
boost::mutex::scoped_lock lock(state_change);
while(true)
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
}
else
{
state.exclusive=true;
return;
}
exclusive_cond.wait(lock);
}
}
bool timed_lock(xtime const& timeout)
{
boost::mutex::scoped_lock lock(state_change);
while(true)
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
}
else
{
state.exclusive=true;
return true;
}
if(!exclusive_cond.timed_wait(lock,timeout))
{
return false;
}
}
}
bool try_lock()
{
boost::mutex::scoped_lock lock(state_change);
if(state.shared_count || state.exclusive)
{
return false;
}
else
{
state.exclusive=true;
return true;
}
}
void unlock()
{
boost::mutex::scoped_lock lock(state_change);
state.exclusive=false;
state.exclusive_waiting_blocked=false;
release_waiters();
}
void lock_upgradeable()
{
boost::mutex::scoped_lock lock(state_change);
while(true)
{
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgradeable)
{
++state.shared_count;
state.upgradeable=true;
return;
}
shared_cond.wait(lock);
}
}
bool timed_lock_upgradeable(xtime const& timeout)
{
boost::mutex::scoped_lock lock(state_change);
while(true)
{
if(!state.exclusive && !state.exclusive_waiting_blocked && !state.upgradeable)
{
++state.shared_count;
state.upgradeable=true;
return true;
}
if(!shared_cond.timed_wait(lock,timeout))
{
return false;
}
}
}
bool try_lock_upgradeable()
{
boost::mutex::scoped_lock lock(state_change);
if(state.exclusive || state.exclusive_waiting_blocked || state.upgradeable)
{
return false;
}
else
{
++state.shared_count;
state.upgradeable=true;
return true;
}
}
void unlock_upgradeable()
{
boost::mutex::scoped_lock lock(state_change);
state.upgradeable=false;
bool const last_reader=!--state.shared_count;
if(last_reader)
{
state.exclusive_waiting_blocked=false;
release_waiters();
}
}
void unlock_upgradeable_and_lock()
{
boost::mutex::scoped_lock lock(state_change);
--state.shared_count;
while(true)
{
if(!state.shared_count)
{
state.upgradeable=false;
state.exclusive=true;
break;
}
upgradeable_cond.wait(lock);
}
}
void unlock_and_lock_upgradeable()
{
boost::mutex::scoped_lock lock(state_change);
state.exclusive=false;
state.upgradeable=true;
++state.shared_count;
state.exclusive_waiting_blocked=false;
release_waiters();
}
void unlock_and_lock_shareable()
{
boost::mutex::scoped_lock lock(state_change);
state.exclusive=false;
++state.shared_count;
state.exclusive_waiting_blocked=false;
release_waiters();
}
void unlock_upgradeable_and_lock_shareable()
{
boost::mutex::scoped_lock lock(state_change);
state.upgradeable=false;
state.exclusive_waiting_blocked=false;
release_waiters();
}
class scoped_read_lock
{
read_write_mutex& m;
public:
scoped_read_lock(read_write_mutex& m_):
m(m_)
{
m.lock_shareable();
}
~scoped_read_lock()
{
m.unlock_shareable();
}
};
class scoped_write_lock
{
read_write_mutex& m;
bool locked;
public:
scoped_write_lock(read_write_mutex& m_):
m(m_),locked(false)
{
lock();
}
void lock()
{
m.lock();
locked=true;
}
void unlock()
{
m.unlock();
locked=false;
}
~scoped_write_lock()
{
if(locked)
{
unlock();
}
}
};
class scoped_upgradeable_lock
{
read_write_mutex& m;
bool locked;
bool upgraded;
public:
scoped_upgradeable_lock(read_write_mutex& m_):
m(m_),
locked(false),upgraded(false)
{
lock();
}
void lock()
{
m.lock_upgradeable();
locked=true;
}
void upgrade()
{
m.unlock_upgradeable_and_lock();
upgraded=true;
}
void unlock()
{
if(upgraded)
{
m.unlock();
}
else
{
m.unlock_upgradeable();
}
}
~scoped_upgradeable_lock()
{
if(locked)
{
unlock();
}
}
};
};
}
#endif

View File

@@ -0,0 +1,136 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_RECURSIVE_MUTEX_RS06092302_HPP
#define BOOST_RECURSIVE_MUTEX_RS06092302_HPP
#include <boost/thread/pthread/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/pthread/lock.hpp>
#include <pthread.h>
namespace boost {
struct xtime;
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
class BOOST_THREAD_DECL recursive_mutex
: private noncopyable
{
public:
friend class detail::thread::lock_ops<recursive_mutex>;
typedef detail::thread::scoped_lock<recursive_mutex> scoped_lock;
recursive_mutex();
~recursive_mutex();
private:
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
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
};
class BOOST_THREAD_DECL recursive_try_mutex
: private noncopyable
{
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();
~recursive_try_mutex();
private:
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
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
};
class BOOST_THREAD_DECL recursive_timed_mutex
: private noncopyable
{
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();
~recursive_timed_mutex();
private:
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
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);
pthread_mutex_t m_mutex;
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
unsigned m_count;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif // BOOST_RECURSIVE_MUTEX_RS06092302_HPP

View File

@@ -0,0 +1,75 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040701_HPP
#define BOOST_THREAD_RS06040701_HPP
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/mutex.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <list>
#include <memory>
#include <pthread.h>
namespace boost {
struct xtime;
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
class BOOST_THREAD_DECL thread : private noncopyable
{
public:
thread();
explicit thread(const function0<void>& threadfunc);
~thread();
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
void join();
static void sleep(const xtime& xt);
static void yield();
private:
pthread_t m_thread;
bool m_joinable;
};
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);
void join_all();
int size();
private:
std::list<thread*> m_threads;
mutex m_mutex;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif // BOOST_THREAD_RS06040701_HPP

View File

@@ -0,0 +1,108 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_TSS_RS06092304_HPP
#define BOOST_TSS_RS06092304_HPP
#include <boost/thread/pthread/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/pthread/exceptions.hpp>
#include <pthread.h>
namespace boost {
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
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);
};
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;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif //BOOST_TSS_RS06092304_HPP

View File

@@ -0,0 +1,56 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040711_HPP
#define BOOST_THREAD_RS06040711_HPP
#include <boost/thread/pthread/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)
typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX
#else
typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX
#endif
typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND
xtime_sec_t sec;
xtime_nsec_t nsec;
};
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
if (xt1.sec == xt2.sec)
return (int)(xt1.nsec - xt2.nsec);
else
return (xt1.sec > xt2.sec) ? 1 : -1;
}
} // namespace boost
#endif //BOOST_THREAD_RS06040711_HPP

View File

@@ -0,0 +1,13 @@
#ifndef BOOST_THREAD_READ_WRITE_MUTEX_HPP
#define BOOST_THREAD_READ_WRITE_MUTEX_HPP
// (C) Copyright 2006 Anthony Williams
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(read_write_mutex.hpp)
#endif

View File

@@ -0,0 +1,16 @@
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
// recursive_mutex.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(recursive_mutex.hpp)
#endif

View File

@@ -0,0 +1,16 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06032802_HPP
#define BOOST_THREAD_RS06032802_HPP
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(thread.hpp)
#endif // BOOST_THREAD_RS06032802_HPP

View File

@@ -0,0 +1,16 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_TSS_RS06092303_HPP
#define BOOST_TSS_RS06092303_HPP
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(tss.hpp)
#endif // BOOST_TSS_RS06092301_HPP

View File

@@ -0,0 +1,140 @@
#ifndef BOOST_BASIC_CHECKED_MUTEX_WIN32_HPP
#define BOOST_BASIC_CHECKED_MUTEX_WIN32_HPP
// basic_checked_mutex_win32.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/assert.hpp>
namespace boost
{
namespace detail
{
struct basic_checked_mutex
{
long locking_thread;
long active_count;
void* semaphore;
BOOST_STATIC_CONSTANT(long,destroyed_mutex_marker=~0);
void initialize()
{
locking_thread=0;
active_count=0;
semaphore=0;
}
void destroy()
{
long const old_locking_thread=BOOST_INTERLOCKED_EXCHANGE(&locking_thread,destroyed_mutex_marker);
BOOST_ASSERT(!old_locking_thread);
void* const old_semaphore=BOOST_INTERLOCKED_EXCHANGE_POINTER(&semaphore,0);
if(old_semaphore)
{
bool const close_handle_succeeded=BOOST_CLOSE_HANDLE(old_semaphore)!=0;
BOOST_ASSERT(close_handle_succeeded);
}
}
bool try_lock()
{
check_mutex_lock();
bool const success=!BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,1,0);
if(success)
{
set_locking_thread();
}
return success;
}
void lock()
{
check_mutex_lock();
if(BOOST_INTERLOCKED_INCREMENT(&active_count)!=1)
{
bool const wait_succeeded=BOOST_WAIT_FOR_SINGLE_OBJECT(get_semaphore(),BOOST_INFINITE)==0;
BOOST_ASSERT(wait_succeeded);
}
set_locking_thread();
}
long get_active_count()
{
return ::boost::detail::interlocked_read(&active_count);
}
void unlock()
{
long const current_thread=BOOST_GET_CURRENT_THREAD_ID();
long const old_locking_thread=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&locking_thread,0,current_thread);
BOOST_ASSERT(old_locking_thread!=destroyed_mutex_marker);
BOOST_ASSERT(old_locking_thread==current_thread);
if(BOOST_INTERLOCKED_DECREMENT(&active_count)!=0)
{
bool const release_succeeded=BOOST_RELEASE_SEMAPHORE(get_semaphore(),1,0)!=0;
BOOST_ASSERT(release_succeeded);
}
}
bool locked()
{
return get_active_count()!=0;
}
private:
void check_mutex_lock()
{
long const current_thread=BOOST_GET_CURRENT_THREAD_ID();
long const current_locking_thread=::boost::detail::interlocked_read(&locking_thread);
BOOST_ASSERT(current_locking_thread!=current_thread);
BOOST_ASSERT(current_locking_thread!=destroyed_mutex_marker);
}
void set_locking_thread()
{
long const old_owner=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&locking_thread,BOOST_GET_CURRENT_THREAD_ID(),0);
BOOST_ASSERT(old_owner==0);
}
void* get_semaphore()
{
void* current_semaphore=::boost::detail::interlocked_read(&semaphore);
if(!current_semaphore)
{
void* const new_semaphore=BOOST_CREATE_SEMAPHORE(0,0,1,0);
BOOST_ASSERT(new_semaphore);
void* const old_semaphore=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&semaphore,new_semaphore,0);
if(old_semaphore!=0)
{
bool const close_succeeded=BOOST_CLOSE_HANDLE(new_semaphore)!=0;
BOOST_ASSERT(close_succeeded);
return old_semaphore;
}
else
{
return new_semaphore;
}
}
return current_semaphore;
}
};
}
}
#define BOOST_BASIC_CHECKED_MUTEX_INITIALIZER {0}
#endif

View File

@@ -0,0 +1,123 @@
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
// basic_recursive_mutex.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/thread/win32/basic_timed_mutex.hpp>
#include <boost/thread/xtime.hpp>
namespace boost
{
namespace detail
{
template<typename underlying_mutex_type>
struct basic_recursive_mutex_impl
{
long recursion_count;
long locking_thread_id;
underlying_mutex_type mutex;
void initialize()
{
recursion_count=0;
locking_thread_id=0;
mutex.initialize();
}
void destroy()
{
mutex.destroy();
}
bool try_lock()
{
long const current_thread_id=win32::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_basic_lock(current_thread_id);
}
void lock()
{
long const current_thread_id=win32::GetCurrentThreadId();
if(!try_recursive_lock(current_thread_id))
{
mutex.lock();
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
recursion_count=1;
}
}
bool timed_lock(::boost::xtime const& target)
{
long const current_thread_id=win32::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
}
long get_active_count()
{
return mutex.get_active_count();
}
void unlock()
{
if(!--recursion_count)
{
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
mutex.unlock();
}
}
bool locked()
{
return mutex.locked();
}
private:
bool try_recursive_lock(long current_thread_id)
{
if(::boost::detail::interlocked_read(&locking_thread_id)==current_thread_id)
{
++recursion_count;
return true;
}
return false;
}
bool try_basic_lock(long current_thread_id)
{
if(mutex.try_lock())
{
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
recursion_count=1;
return true;
}
return false;
}
bool try_timed_lock(long current_thread_id,::boost::xtime const& target)
{
if(mutex.timed_lock(target))
{
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,current_thread_id);
recursion_count=1;
return true;
}
return false;
}
};
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_timed_mutex;
}
}
#define BOOST_BASIC_RECURSIVE_MUTEX_INITIALIZER {0}
#endif

View File

@@ -0,0 +1,158 @@
#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
// basic_timed_mutex_win32.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/thread/win32/xtime.hpp>
#include <boost/thread/win32/xtime_utils.hpp>
namespace boost
{
namespace detail
{
struct basic_timed_mutex
{
BOOST_STATIC_CONSTANT(long,lock_flag_value=0x10000);
long active_count;
void* event;
void initialize()
{
active_count=0;
event=0;
}
void destroy()
{
void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
if(old_event)
{
win32::CloseHandle(old_event);
}
}
bool try_lock()
{
long old_count=0;
while(!(old_count&lock_flag_value))
{
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
if(current_count==old_count)
{
return true;
}
old_count=current_count;
}
return false;
}
void lock()
{
bool const success=timed_lock(::boost::detail::get_xtime_sentinel());
BOOST_ASSERT(success);
}
bool timed_lock(::boost::xtime const& target_time)
{
long old_count=0;
while(true)
{
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,(old_count+1)|lock_flag_value,old_count);
if(current_count==old_count)
{
break;
}
old_count=current_count;
}
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
++old_count; // we're waiting, too
do
{
old_count-=(lock_flag_value+1); // there will be one less active thread on this mutex when it gets unlocked
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until_time(target_time))!=0)
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
do
{
long const current_count=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,old_count|lock_flag_value,old_count);
if(current_count==old_count)
{
break;
}
old_count=current_count;
}
while(!(old_count&lock_flag_value));
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
}
return true;
}
long get_active_count()
{
return ::boost::detail::interlocked_read(&active_count);
}
void unlock()
{
long const offset=lock_flag_value+1;
long old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,-offset);
if(old_count>offset)
{
win32::SetEvent(get_event());
}
}
bool locked()
{
return get_active_count()>=lock_flag_value;
}
private:
void* get_event()
{
void* current_event=::boost::detail::interlocked_read(&event);
if(!current_event)
{
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
if(old_event!=0)
{
win32::CloseHandle(new_event);
return old_event;
}
else
{
return new_event;
}
}
return current_event;
}
};
}
}
#define BOOST_BASIC_TIMED_MUTEX_INITIALIZER {0}
#endif

View File

@@ -0,0 +1,229 @@
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#ifndef CONDITION_HPP
#define CONDITION_HPP
#include "boost/config.hpp"
#include "boost/thread/mutex.hpp"
#include "boost/thread/win32/thread_primitives.hpp"
#include "boost/thread/win32/xtime.hpp"
#include "boost/thread/win32/xtime_utils.hpp"
#include <limits.h>
#include "boost/assert.hpp"
#include <algorithm>
namespace boost
{
template<typename lock_type>
class basic_condition
{
boost::mutex internal_mutex;
struct list_entry
{
detail::win32::handle semaphore;
long count;
bool notified;
};
BOOST_STATIC_CONSTANT(unsigned,generation_count=10);
list_entry generations[generation_count];
detail::win32::handle wake_sem;
static bool no_waiters(list_entry const& entry)
{
return entry.count==0;
}
void shift_generations_down()
{
if(std::remove_if(generations,generations+generation_count,no_waiters)==generations+generation_count)
{
broadcast_entry(generations[generation_count-1],false);
}
std::copy_backward(generations,generations+generation_count,generations+generation_count);
generations[0].semaphore=0;
generations[0].count=0;
generations[0].notified=false;
}
void broadcast_entry(list_entry& entry,bool wake)
{
if(wake)
{
detail::win32::ReleaseSemaphore(wake_sem,entry.count,NULL);
}
detail::win32::ReleaseSemaphore(entry.semaphore,entry.count,NULL);
entry.count=0;
dispose_entry(entry);
}
void dispose_entry(list_entry& entry)
{
BOOST_ASSERT(entry.count==0);
if(entry.semaphore)
{
unsigned long const close_result=detail::win32::CloseHandle(entry.semaphore);
BOOST_ASSERT(close_result);
}
entry.semaphore=0;
entry.notified=false;
}
detail::win32::handle duplicate_handle(detail::win32::handle source)
{
detail::win32::handle const current_process=detail::win32::GetCurrentProcess();
long const same_access_flag=2;
detail::win32::handle new_handle=0;
bool const success=detail::win32::DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
BOOST_ASSERT(success);
return new_handle;
}
bool do_wait(lock_type& lock,::boost::xtime const& target_time)
{
detail::win32::handle local_wake_sem;
detail::win32::handle sem;
bool first_loop=true;
bool woken=false;
while(!woken)
{
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
if(first_loop)
{
lock.unlock();
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(wake_sem);
}
local_wake_sem=duplicate_handle(wake_sem);
if(generations[0].notified)
{
shift_generations_down();
}
if(!generations[0].semaphore)
{
generations[0].semaphore=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(generations[0].semaphore);
}
first_loop=false;
}
++generations[0].count;
sem=duplicate_handle(generations[0].semaphore);
}
unsigned long const notified=detail::win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until_time(target_time));
BOOST_ASSERT(notified==detail::win32::timeout || notified==0);
unsigned long const sem_close_result=detail::win32::CloseHandle(sem);
BOOST_ASSERT(sem_close_result);
if(notified==detail::win32::timeout)
{
break;
}
unsigned long const woken_result=detail::win32::WaitForSingleObject(local_wake_sem,0);
BOOST_ASSERT(woken_result==detail::win32::timeout || woken_result==0);
woken=(woken_result==0);
}
unsigned long const wake_sem_close_result=detail::win32::CloseHandle(local_wake_sem);
BOOST_ASSERT(wake_sem_close_result);
lock.lock();
return woken;
}
public:
basic_condition():
wake_sem(0)
{
for(unsigned i=0;i<generation_count;++i)
{
generations[i]=list_entry();
}
}
~basic_condition()
{
for(unsigned i=0;i<generation_count;++i)
{
dispose_entry(generations[i]);
}
detail::win32::CloseHandle(wake_sem);
}
void wait(lock_type& m)
{
do_wait(m,::boost::detail::get_xtime_sentinel());
}
template<typename predicate_type>
void wait(lock_type& m,predicate_type pred)
{
while(!pred()) wait(m);
}
bool timed_wait(lock_type& m,::boost::xtime const& target_time)
{
return do_wait(m,target_time);
}
template<typename predicate_type>
bool timed_wait(lock_type& m,::boost::xtime const& target_time,predicate_type pred)
{
while (!pred()) { if (!timed_wait(m, target_time)) return false; } return true;
}
void notify_one()
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
if(wake_sem)
{
detail::win32::ReleaseSemaphore(wake_sem,1,NULL);
for(unsigned generation=generation_count;generation!=0;--generation)
{
list_entry& entry=generations[generation-1];
if(entry.count)
{
entry.notified=true;
detail::win32::ReleaseSemaphore(entry.semaphore,1,NULL);
if(!--entry.count)
{
dispose_entry(entry);
}
}
}
}
}
void notify_all()
{
boost::mutex::scoped_lock internal_lock(internal_mutex);
if(wake_sem)
{
for(unsigned generation=generation_count;generation!=0;--generation)
{
list_entry& entry=generations[generation-1];
if(entry.count)
{
broadcast_entry(entry,true);
}
}
}
}
};
typedef basic_condition<boost::mutex::scoped_lock> condition;
}
#endif

View File

@@ -0,0 +1,77 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06041002_HPP
#define BOOST_THREAD_RS06041002_HPP
#include <boost/config.hpp>
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#if defined(BOOST_THREAD_BUILD_DLL) //Build dll
#elif defined(BOOST_THREAD_BUILD_LIB) //Build lib
#elif defined(BOOST_THREAD_USE_DLL) //Use dll
#elif defined(BOOST_THREAD_USE_LIB) //Use lib
#else //Use default
# if defined(BOOST_HAS_WINTHREADS)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib
# define BOOST_THREAD_USE_LIB
# else
//For compilers not yet supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads dll
# define BOOST_THREAD_USE_DLL
# endif
# else
# define BOOST_THREAD_USE_LIB
# endif
#endif
#if defined(BOOST_HAS_DECLSPEC)
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
# define BOOST_THREAD_DECL __declspec(dllexport)
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
# define BOOST_THREAD_DECL __declspec(dllimport)
# else
# define BOOST_THREAD_DECL
# endif
#else
# define BOOST_THREAD_DECL
#endif // BOOST_HAS_DECLSPEC
//
// 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)
//
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
// once it's done with it:
//
#if defined(BOOST_THREAD_USE_DLL)
# define BOOST_DYN_LINK
#endif
//
// 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_RS06041002_HPP

View File

@@ -0,0 +1,91 @@
// (C) Copyright 2005-6 Anthony Williams
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06041003_HPP
#define BOOST_THREAD_RS06041003_HPP
#include <boost/thread/win32/config.hpp>
#include <string>
#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;
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_RS06041003_HPP

View File

@@ -0,0 +1,36 @@
#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
// interlocked_read_win32.hpp
//
// (C) Copyright 2005-7 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/detail/interlocked.hpp>
extern "C" void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
namespace boost
{
namespace detail
{
inline long interlocked_read_acquire(long volatile* x)
{
long const res=*x;
_ReadWriteBarrier();
return res;
}
inline void* interlocked_read_acquire(void* volatile* x)
{
void* const res=*x;
_ReadWriteBarrier();
return res;
}
}
}
#endif

View File

@@ -0,0 +1,201 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06041005_HPP
#define BOOST_THREAD_RS06041005_HPP
#include <boost/thread/win32/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/win32/exceptions.hpp>
namespace boost {
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:
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:
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:
TimedMutex& m_mutex;
bool m_locked;
};
} // namespace thread
} // namespace detail
} // namespace boost
#endif // BOOST_THREAD_RS06041005_HPP

View File

@@ -0,0 +1,272 @@
// (C) Copyright 2005-6 Anthony Williams
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06041004_HPP
#define BOOST_THREAD_RS06041004_HPP
#include <boost/thread/win32/config.hpp>
#include <boost/thread/win32/basic_timed_mutex.hpp>
#include <boost/utility.hpp>
#include <boost/thread/win32/lock.hpp>
#include <boost/thread/win32/xtime.hpp>
#include <boost/thread/win32/exceptions.hpp>
namespace boost
{
namespace detail
{
typedef ::boost::detail::basic_timed_mutex underlying_mutex;
}
class mutex:
noncopyable,
public ::boost::detail::underlying_mutex
{
public:
mutex()
{
initialize();
}
~mutex()
{
destroy();
}
class scoped_lock
{
protected:
mutex& m;
bool is_locked;
public:
scoped_lock(mutex& m_):
m(m_),is_locked(false)
{
lock();
}
scoped_lock(mutex& m_,bool do_lock):
m(m_),is_locked(false)
{
if(do_lock)
{
lock();
}
}
~scoped_lock()
{
if(locked())
{
m.unlock();
}
}
void lock()
{
if(locked())
{
throw boost::lock_error();
}
m.lock();
is_locked=true;
}
void unlock()
{
if(!locked())
{
throw boost::lock_error();
}
m.unlock();
is_locked=false;
}
operator void* () const
{
return is_locked?const_cast<void*>(static_cast<void const*>(this)):0;
}
bool locked() const
{
return is_locked;
}
};
};
class try_mutex:
noncopyable,
protected ::boost::detail::underlying_mutex
{
public:
try_mutex()
{
initialize();
}
~try_mutex()
{
destroy();
}
class scoped_try_lock
{
protected:
try_mutex& m;
bool is_locked;
public:
scoped_try_lock(try_mutex& m_):
m(m_),is_locked(false)
{
lock();
}
scoped_try_lock(try_mutex& m_,bool do_lock):
m(m_),is_locked(false)
{
if(do_lock)
{
lock();
}
}
~scoped_try_lock()
{
if(locked())
{
m.unlock();
}
}
void lock()
{
if(locked())
{
throw boost::lock_error();
}
m.lock();
is_locked=true;
}
bool try_lock()
{
if(locked())
{
throw boost::lock_error();
}
is_locked=m.try_lock();
return is_locked;
}
void unlock()
{
if(!locked())
{
throw boost::lock_error();
}
m.unlock();
is_locked=false;
}
operator void* () const
{
return is_locked?const_cast<void*>(static_cast<void const*>(this)):0;
}
bool locked() const
{
return is_locked;
}
};
typedef scoped_try_lock scoped_lock;
};
class timed_mutex:
noncopyable,
protected ::boost::detail::basic_timed_mutex
{
public:
timed_mutex()
{
initialize();
}
~timed_mutex()
{
destroy();
}
class scoped_timed_lock
{
protected:
timed_mutex& m;
bool is_locked;
public:
scoped_timed_lock(timed_mutex& m_):
m(m_),is_locked(false)
{
lock();
}
scoped_timed_lock(timed_mutex& m_,::boost::xtime const& target):
m(m_),is_locked(false)
{
timed_lock(target);
}
scoped_timed_lock(timed_mutex& m_,bool do_lock):
m(m_),is_locked(false)
{
if(do_lock)
{
lock();
}
}
~scoped_timed_lock()
{
if(locked())
{
m.unlock();
}
}
void lock()
{
if(locked())
{
throw boost::lock_error();
}
m.lock();
is_locked=true;
}
bool try_lock()
{
is_locked=m.try_lock();
return is_locked;
}
bool timed_lock(::boost::xtime const& target)
{
is_locked=m.timed_lock(target);
return is_locked;
}
void unlock()
{
if(!locked())
{
throw boost::lock_error();
}
m.unlock();
is_locked=false;
}
operator void* () const
{
return is_locked?const_cast<void*>(static_cast<void const*>(this)):0;
}
bool locked() const
{
return is_locked;
}
};
typedef scoped_timed_lock scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#endif // BOOST_THREAD_RS06041004_HPP

View File

@@ -0,0 +1,114 @@
#ifndef BOOST_THREAD_WIN32_ONCE_HPP
#define BOOST_THREAD_WIN32_ONCE_HPP
// once.hpp
//
// (C) Copyright 2005-7 Anthony Williams
// (C) Copyright 2005 John Maddock
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <cstring>
#include <cstddef>
#include <boost/assert.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std
{
using ::strlen;
using ::memcpy;
using ::ptrdiff_t;
}
#endif
namespace boost
{
typedef long once_flag;
#define BOOST_ONCE_INIT 0
namespace detail
{
struct win32_mutex_scoped_lock
{
void* const mutex_handle;
explicit win32_mutex_scoped_lock(void* mutex_handle_):
mutex_handle(mutex_handle_)
{
unsigned long const res=win32::WaitForSingleObject(mutex_handle,win32::infinite);
BOOST_ASSERT(!res);
}
~win32_mutex_scoped_lock()
{
bool const success=win32::ReleaseMutex(mutex_handle)!=0;
BOOST_ASSERT(success);
}
};
template <class I>
void int_to_string(I p, char* buf)
{
unsigned i=0;
for(; i < sizeof(I)*2; ++i)
{
buf[i] = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
}
buf[i] = 0;
}
unsigned const once_mutex_name_fixed_length=48;
unsigned const once_mutex_name_fixed_buffer_size=once_mutex_name_fixed_length+1;
unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
// create a named mutex. It doesn't really matter what this name is
// as long as it is unique both to this process, and to the address of "flag":
inline void* create_once_mutex(char (&mutex_name)[once_mutex_name_length],void* flag_address)
{
static const char fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
BOOST_STATIC_ASSERT(sizeof(fixed_mutex_name) == once_mutex_name_fixed_buffer_size);
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
BOOST_ASSERT(sizeof(mutex_name) == std::strlen(mutex_name) + sizeof(void*)*2 + sizeof(unsigned long)*2 + 1);
BOOST_STATIC_ASSERT(sizeof(void*) == sizeof(std::ptrdiff_t));
detail::int_to_string(reinterpret_cast<std::ptrdiff_t>(flag_address), mutex_name + once_mutex_name_fixed_length);
detail::int_to_string(win32::GetCurrentProcessId(), mutex_name + once_mutex_name_fixed_length + sizeof(void*)*2);
BOOST_ASSERT(sizeof(mutex_name) == std::strlen(mutex_name) + 1);
return win32::CreateMutexA(NULL, 0, mutex_name);
}
}
template<typename Function>
void call_once(once_flag& flag,Function f)
{
// Try for a quick win: if the proceedure has already been called
// just skip through:
long const function_complete_flag_value=0xc15730e2;
if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)
{
char mutex_name[::boost::detail::once_mutex_name_length];
void* const mutex_handle(::boost::detail::create_once_mutex(mutex_name,&flag));
BOOST_ASSERT(mutex_handle);
detail::win32::handle_manager const closer(mutex_handle);
detail::win32_mutex_scoped_lock const lock(mutex_handle);
if(flag!=function_complete_flag_value)
{
f();
BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);
}
}
}
}
#endif

View File

@@ -0,0 +1,528 @@
#ifndef BOOST_THREAD_WIN32_READ_WRITE_MUTEX_HPP
#define BOOST_THREAD_WIN32_READ_WRITE_MUTEX_HPP
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/assert.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/thread/win32/thread_primitives.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <boost/static_assert.hpp>
#include <limits.h>
namespace boost
{
class read_write_mutex
{
private:
struct state_data
{
unsigned shared_count:10;
unsigned shared_waiting:10;
unsigned exclusive:1;
unsigned upgradeable:1;
unsigned exclusive_waiting:9;
unsigned exclusive_waiting_blocked:1;
friend bool operator==(state_data const& lhs,state_data const& rhs)
{
return *reinterpret_cast<unsigned const*>(&lhs)==*reinterpret_cast<unsigned const*>(&rhs);
}
};
template<typename T>
T interlocked_compare_exchange(T* target,T new_value,T comparand)
{
BOOST_STATIC_ASSERT(sizeof(T)==sizeof(long));
long const res=BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast<long*>(target),
*reinterpret_cast<long*>(&new_value),
*reinterpret_cast<long*>(&comparand));
return *reinterpret_cast<T const*>(&res);
}
state_data state;
void* semaphores[2];
void* &unlock_sem;
void* &exclusive_sem;
void* upgradeable_sem;
void release_waiters(state_data old_state)
{
if(old_state.exclusive_waiting)
{
bool const success=detail::win32::ReleaseSemaphore(exclusive_sem,1,NULL)!=0;
BOOST_ASSERT(success);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
bool const success=detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),NULL)!=0;
BOOST_ASSERT(success);
}
}
public:
read_write_mutex():
unlock_sem(semaphores[0]),
exclusive_sem(semaphores[1])
{
unlock_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
exclusive_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
upgradeable_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
state_data state_={0};
state=state_;
}
~read_write_mutex()
{
detail::win32::CloseHandle(upgradeable_sem);
detail::win32::CloseHandle(unlock_sem);
detail::win32::CloseHandle(exclusive_sem);
}
bool try_lock_shareable()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
if(!new_state.exclusive && !new_state.exclusive_waiting_blocked)
{
++new_state.shared_count;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
}
void lock_shareable()
{
while(true)
{
state_data old_state=state;
do
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
++new_state.shared_waiting;
}
else
{
++new_state.shared_count;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return;
}
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite);
BOOST_ASSERT(res==0);
}
}
void unlock_shareable()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
if(new_state.upgradeable)
{
new_state.upgradeable=false;
new_state.exclusive=true;
}
else
{
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
}
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
if(last_reader)
{
if(old_state.upgradeable)
{
bool const success=detail::win32::ReleaseSemaphore(upgradeable_sem,1,NULL)!=0;
BOOST_ASSERT(success);
}
else
{
release_waiters(old_state);
}
}
break;
}
old_state=current_state;
}
while(true);
}
void lock()
{
while(true)
{
state_data old_state=state;
do
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
++new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=true;
}
else
{
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
if(!old_state.shared_count && !old_state.exclusive)
{
break;
}
bool const success2=detail::win32::WaitForMultipleObjects(2,semaphores,true,detail::win32::infinite)<2;
BOOST_ASSERT(success2);
}
}
void unlock()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
new_state.exclusive=false;
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
release_waiters(old_state);
}
void lock_upgradeable()
{
while(true)
{
state_data old_state=state;
do
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgradeable)
{
++new_state.shared_waiting;
}
else
{
++new_state.shared_count;
new_state.upgradeable=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgradeable))
{
return;
}
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite);
BOOST_ASSERT(res==0);
}
}
void unlock_upgradeable()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
new_state.upgradeable=false;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
if(last_reader)
{
release_waiters(old_state);
}
break;
}
old_state=current_state;
}
while(true);
}
void unlock_upgradeable_and_lock()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
new_state.upgradeable=false;
new_state.exclusive=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
if(!last_reader)
{
unsigned long const res=detail::win32::WaitForSingleObject(upgradeable_sem,detail::win32::infinite);
BOOST_ASSERT(res==0);
}
break;
}
old_state=current_state;
}
while(true);
}
void unlock_and_lock_upgradeable()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
new_state.exclusive=false;
new_state.upgradeable=true;
++new_state.shared_count;
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
release_waiters(old_state);
}
void unlock_and_lock_shareable()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
new_state.exclusive=false;
++new_state.shared_count;
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
release_waiters(old_state);
}
void unlock_upgradeable_and_lock_shareable()
{
state_data old_state=state;
do
{
state_data new_state=old_state;
new_state.upgradeable=false;
if(new_state.exclusive_waiting)
{
--new_state.exclusive_waiting;
new_state.exclusive_waiting_blocked=false;
}
new_state.shared_waiting=0;
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
while(true);
release_waiters(old_state);
}
class scoped_read_lock
{
read_write_mutex& m;
public:
scoped_read_lock(read_write_mutex& m_):
m(m_)
{
m.lock_shareable();
}
~scoped_read_lock()
{
m.unlock_shareable();
}
};
class scoped_write_lock
{
read_write_mutex& m;
bool locked;
public:
scoped_write_lock(read_write_mutex& m_):
m(m_),locked(false)
{
lock();
}
void lock()
{
m.lock();
locked=true;
}
void unlock()
{
m.unlock();
locked=false;
}
~scoped_write_lock()
{
if(locked)
{
unlock();
}
}
};
class scoped_upgradeable_lock
{
read_write_mutex& m;
bool locked;
bool upgraded;
public:
scoped_upgradeable_lock(read_write_mutex& m_):
m(m_),
locked(false),upgraded(false)
{
lock();
}
void lock()
{
m.lock_upgradeable();
locked=true;
}
void upgrade()
{
m.unlock_upgradeable_and_lock();
upgraded=true;
}
void unlock()
{
if(upgraded)
{
m.unlock();
}
else
{
m.unlock_upgradeable();
}
}
~scoped_upgradeable_lock()
{
if(locked)
{
unlock();
}
}
};
};
}
#endif

View File

@@ -0,0 +1,263 @@
#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP
#define BOOST_RECURSIVE_MUTEX_WIN32_HPP
// recursive_mutex.hpp
//
// (C) Copyright 2006 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/win32/basic_recursive_mutex.hpp>
#include <boost/utility.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/exceptions.hpp>
namespace boost
{
class recursive_mutex:
noncopyable,
protected ::boost::detail::basic_recursive_mutex
{
public:
recursive_mutex()
{
::boost::detail::basic_recursive_mutex::initialize();
}
~recursive_mutex()
{
::boost::detail::basic_recursive_mutex::destroy();
}
class scoped_lock
{
protected:
recursive_mutex& m;
bool is_locked;
public:
scoped_lock(recursive_mutex& m_):
m(m_),is_locked(false)
{
lock();
}
scoped_lock(recursive_mutex& m_,bool do_lock):
m(m_),is_locked(false)
{
if(do_lock)
{
lock();
}
}
~scoped_lock()
{
if(locked())
{
m.unlock();
}
}
void lock()
{
if(locked())
{
throw boost::lock_error();
}
m.lock();
is_locked=true;
}
void unlock()
{
if(!locked())
{
throw boost::lock_error();
}
m.unlock();
is_locked=false;
}
operator void* () const
{
return is_locked?const_cast<void*>(static_cast<void const*>(this)):0;
}
bool locked() const
{
return is_locked;
}
};
};
class recursive_try_mutex:
noncopyable,
protected ::boost::detail::basic_recursive_mutex
{
public:
recursive_try_mutex()
{
::boost::detail::basic_recursive_mutex::initialize();
}
~recursive_try_mutex()
{
::boost::detail::basic_recursive_mutex::destroy();
}
class scoped_try_lock
{
protected:
recursive_try_mutex& m;
bool is_locked;
public:
scoped_try_lock(recursive_try_mutex& m_):
m(m_),is_locked(false)
{
lock();
}
scoped_try_lock(recursive_try_mutex& m_,bool do_lock):
m(m_),is_locked(false)
{
if(do_lock)
{
lock();
}
}
~scoped_try_lock()
{
if(locked())
{
m.unlock();
}
}
void lock()
{
if(locked())
{
throw boost::lock_error();
}
m.lock();
is_locked=true;
}
bool try_lock()
{
if(locked())
{
throw boost::lock_error();
}
is_locked=m.try_lock();
return is_locked;
}
void unlock()
{
if(!locked())
{
throw boost::lock_error();
}
m.unlock();
is_locked=false;
}
operator void* () const
{
return is_locked?const_cast<void*>(static_cast<void const*>(this)):0;
}
bool locked() const
{
return is_locked;
}
};
typedef scoped_try_lock scoped_lock;
};
class recursive_timed_mutex:
noncopyable,
protected ::boost::detail::basic_recursive_timed_mutex
{
public:
recursive_timed_mutex()
{
::boost::detail::basic_recursive_timed_mutex::initialize();
}
~recursive_timed_mutex()
{
::boost::detail::basic_recursive_timed_mutex::destroy();
}
class scoped_timed_lock
{
protected:
recursive_timed_mutex& m;
bool is_locked;
public:
scoped_timed_lock(recursive_timed_mutex& m_):
m(m_),is_locked(false)
{
lock();
}
scoped_timed_lock(recursive_timed_mutex& m_,::boost::xtime const& target):
m(m_),is_locked(false)
{
timed_lock(target);
}
scoped_timed_lock(recursive_timed_mutex& m_,bool do_lock):
m(m_),is_locked(false)
{
if(do_lock)
{
lock();
}
}
~scoped_timed_lock()
{
if(locked())
{
m.unlock();
}
}
void lock()
{
if(locked())
{
throw boost::lock_error();
}
m.lock();
is_locked=true;
}
bool try_lock()
{
is_locked=m.try_lock();
return is_locked;
}
bool timed_lock(::boost::xtime const& target)
{
is_locked=m.timed_lock(target);
return is_locked;
}
void unlock()
{
if(!locked())
{
throw boost::lock_error();
}
m.unlock();
is_locked=false;
}
operator void* () const
{
return is_locked?const_cast<void*>(static_cast<void const*>(this)):0;
}
bool locked() const
{
return is_locked;
}
};
typedef scoped_timed_lock scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#endif

View File

@@ -0,0 +1,77 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06041007_HPP
#define BOOST_THREAD_RS06041007_HPP
#include <boost/thread/win32/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/win32/mutex.hpp>
#include <list>
#include <memory>
namespace boost {
struct xtime;
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
class BOOST_THREAD_DECL thread : private noncopyable
{
public:
thread();
explicit thread(const function0<void>& threadfunc);
~thread();
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
void join();
static void sleep(const xtime& xt);
static void yield();
private:
void* m_thread;
unsigned int m_id;
bool m_joinable;
};
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);
void join_all();
int size();
private:
std::list<thread*> m_threads;
mutex m_mutex;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif // BOOST_THREAD_RS06041007_HPP

View File

@@ -0,0 +1,198 @@
#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
// win32_thread_primitives.hpp
//
// (C) Copyright 2005-6 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/config.hpp>
#include <boost/assert.hpp>
#include <boost/thread/exceptions.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
namespace boost
{
namespace detail
{
namespace win32
{
typedef ULONG_PTR ulong_ptr;
typedef HANDLE handle;
unsigned const infinite=INFINITE;
unsigned const timeout=WAIT_TIMEOUT;
using ::CreateMutexA;
using ::CreateEventA;
using ::CreateSemaphoreA;
using ::CloseHandle;
using ::ReleaseMutex;
using ::ReleaseSemaphore;
using ::SetEvent;
using ::ResetEvent;
using ::WaitForMultipleObjects;
using ::WaitForSingleObject;
using ::GetCurrentProcessId;
using ::GetCurrentThreadId;
using ::GetCurrentThread;
using ::GetCurrentProcess;
using ::DuplicateHandle;
using ::SleepEx;
using ::QueueUserAPC;
}
}
}
#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
namespace boost
{
namespace detail
{
namespace win32
{
# ifdef _WIN64
typedef unsigned __int64 ulong_ptr;
# else
typedef unsigned long ulong_ptr;
# endif
typedef void* handle;
unsigned const infinite=~0U;
unsigned const timeout=258U;
extern "C"
{
struct _SECURITY_ATTRIBUTES;
__declspec(dllimport) void* __stdcall CreateMutexA(_SECURITY_ATTRIBUTES*,int,char const*);
__declspec(dllimport) void* __stdcall CreateSemaphoreA(_SECURITY_ATTRIBUTES*,long,long,char const*);
__declspec(dllimport) void* __stdcall CreateEventA(_SECURITY_ATTRIBUTES*,int,int,char const*);
__declspec(dllimport) int __stdcall CloseHandle(void*);
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
__declspec(dllimport) void* __stdcall GetCurrentThread();
__declspec(dllimport) void* __stdcall GetCurrentProcess();
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
typedef void (__stdcall *queue_user_apc_callback_function)(ulong_ptr);
__declspec(dllimport) unsigned long __stdcall QueueUserAPC(queue_user_apc_callback_function,void*,ulong_ptr);
__declspec(dllimport) int __stdcall SetEvent(void*);
__declspec(dllimport) int __stdcall ResetEvent(void*);
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
}
}
}
}
#else
# error "Win32 functions not available"
#endif
namespace boost
{
namespace detail
{
namespace win32
{
enum event_type
{
auto_reset_event=false,
manual_reset_event=true
};
enum initial_event_state
{
event_initially_reset=false,
event_initially_set=true
};
inline handle create_anonymous_event(event_type type,initial_event_state state)
{
handle const res=CreateEventA(0,type,state,0);
return res?res:throw thread_resource_error();
}
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
handle const res=CreateSemaphoreA(NULL,initial_count,max_count,NULL);
return res?res:throw thread_resource_error();
}
inline handle duplicate_handle(handle source)
{
handle const current_process=GetCurrentProcess();
long const same_access_flag=2;
handle new_handle=0;
bool const success=DuplicateHandle(current_process,source,current_process,&new_handle,0,false,same_access_flag)!=0;
return success?new_handle:throw thread_resource_error();
}
inline void release_semaphore(handle semaphore,long count)
{
bool const success=ReleaseSemaphore(semaphore,count,0)!=0;
BOOST_ASSERT(success);
}
class handle_manager
{
private:
handle handle_to_manage;
handle_manager(handle_manager&);
handle_manager& operator=(handle_manager&);
void cleanup()
{
if(handle_to_manage)
{
unsigned long result=CloseHandle(handle_to_manage);
BOOST_ASSERT(result);
}
}
public:
explicit handle_manager(handle handle_to_manage_):
handle_to_manage(handle_to_manage_)
{}
handle_manager():
handle_to_manage(0)
{}
handle_manager& operator=(handle new_handle)
{
cleanup();
handle_to_manage=new_handle;
}
operator handle() const
{
return handle_to_manage;
}
handle release()
{
handle const res=handle_to_manage;
handle_to_manage=0;
return res;
}
bool operator!() const
{
return !handle_to_manage;
}
~handle_manager()
{
cleanup();
}
};
}
}
}
#endif

View File

@@ -0,0 +1,106 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_TSS_RS06092305_HPP
#define BOOST_TSS_RS06092305_HPP
#include <boost/thread/win32/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/win32/exceptions.hpp>
namespace boost {
// disable warnings about non dll import
// see: http://www.boost.org/more/separate_compilation.html#dlls
#ifdef BOOST_MSVC
# pragma warning(push)
# pragma warning(disable: 4251 4231 4660 4275)
#endif
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);
};
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;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif //BOOST_TSS_RS06092305_HPP

View File

@@ -0,0 +1,74 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) Michael Glassford 2004.
// Copyright (C) 2006 Roland Schwarz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_TLS_HOOKS_RS06092306_HPP
#define BOOST_TLS_HOOKS_RS06092306_HPP
#include <boost/thread/win32/config.hpp>
typedef void (__cdecl *thread_exit_handler)(void);
extern "C" BOOST_THREAD_DECL int at_thread_exit(
thread_exit_handler exit_handler
);
//Add a function to the list of functions that will
//be called when a thread is about to exit.
//Currently only implemented for Win32, but should
//later be implemented for all platforms.
//Used by Win32 implementation of Boost.Threads
//tss to perform cleanup.
//Like the C runtime library atexit() function,
//which it mimics, at_thread_exit() returns
//zero if successful and a nonzero
//value if an error occurs.
extern "C" BOOST_THREAD_DECL void on_process_enter(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
//Should be called only before the first call to
//on_thread_enter().
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_process_exit(void);
//Function to be called when the exe or dll
//that uses Boost.Threads first starts
//or is first loaded.
//Should be called only after the last call to
//on_exit_thread().
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_thread_enter(void);
//Function to be called just after a thread starts
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
//that is starting.
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//May be omitted; may be called multiple times.
extern "C" BOOST_THREAD_DECL void on_thread_exit(void);
//Function to be called just be fore a thread ends
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
//that is ending.
//Called automatically by Boost.Threads when
//a method for doing so has been discovered.
//Must not be omitted; may be called multiple times.
extern "C" void tss_cleanup_implemented(void);
//Dummy function used both to detect whether tss cleanup
//cleanup has been implemented and to force
//it to be linked into the Boost.Threads library.
#endif //BOOST_TLS_HOOKS_RS06092306_HPP

View File

@@ -0,0 +1,56 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06041006_HPP
#define BOOST_THREAD_RS06041006_HPP
#include <boost/thread/win32/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)
typedef int_fast32_t xtime_sec_t; //INT_FAST32_MIN <= sec <= INT_FAST32_MAX
#else
typedef int_fast64_t xtime_sec_t; //INT_FAST64_MIN <= sec <= INT_FAST64_MAX
#endif
typedef int_fast32_t xtime_nsec_t; //0 <= xtime.nsec < NANOSECONDS_PER_SECOND
xtime_sec_t sec;
xtime_nsec_t nsec;
};
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
if (xt1.sec == xt2.sec)
return (int)(xt1.nsec - xt2.nsec);
else
return (xt1.sec > xt2.sec) ? 1 : -1;
}
} // namespace boost
#endif //BOOST_THREAD_RS06041006_HPP

View File

@@ -0,0 +1,85 @@
#ifndef BOOST_THREAD_DETAIL_XTIME_UTILS_HPP
#define BOOST_THREAD_DETAIL_XTIME_UTILS_HPP
// xtime_utils.hpp
//
// (C) Copyright 2005 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/win32/xtime.hpp>
#include <limits>
namespace boost
{
namespace detail
{
inline ::boost::xtime get_xtime_sentinel()
{
boost::xtime const sentinel={
(std::numeric_limits<boost::xtime::xtime_sec_t>::max)(),
(std::numeric_limits<boost::xtime::xtime_nsec_t>::max)()
};
return sentinel;
}
// get the number of milliseconds from now to target
// if target is in the past, return 0
// if target cannot be represented as unsigned long, return
// the maximum instead
// 2006-08-04 <roland>
inline unsigned long get_milliseconds_until_time(::boost::xtime target)
{
if(!boost::xtime_cmp(target,get_xtime_sentinel()))
{
return (std::numeric_limits<unsigned long>::max)();
}
boost::xtime now;
boost::xtime_get(&now, boost::TIME_UTC);
if (target.sec < now.sec)
{
return 0;
}
else
{
boost::xtime::xtime_nsec_t const nanoseconds_per_second=1000000000;
boost::xtime::xtime_nsec_t const milliseconds_per_second=1000;
boost::xtime::xtime_nsec_t const nanoseconds_per_millisecond=nanoseconds_per_second/milliseconds_per_second;
if (target.nsec < now.nsec)
{
if (target.sec == now.sec)
{
return 0;
}
target.nsec += nanoseconds_per_second - now.nsec;
target.sec -= now.sec + 1;
}
else
{
target.nsec -= now.nsec;
target.sec -= now.sec;
}
// we are throwing away some bits, but one second after having
// waited for 49 years does not really matter ...
if (target.sec < (std::numeric_limits<unsigned long>::max)()/milliseconds_per_second)
{
return static_cast<unsigned long>(
target.sec*milliseconds_per_second +
(target.nsec+nanoseconds_per_millisecond/2)/nanoseconds_per_millisecond);
}
else
{
return (std::numeric_limits<unsigned long>::max)();
}
}
}
}
}
#endif

View File

@@ -0,0 +1,16 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#ifndef BOOST_THREAD_RS06040712_HPP
#define BOOST_THREAD_RS06040712_HPP
#include <boost/thread/detail/platform.hpp>
#include BOOST_THREAD_PLATFORM(xtime.hpp)
#endif // BOOST_THREAD_RS06040712_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>

98
src/pthread/condition.cpp Normal file
View File

@@ -0,0 +1,98 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/condition.hpp>
#include <boost/thread/pthread/xtime.hpp>
#include <boost/thread/pthread/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/limits.hpp>
#include <cassert>
#include <limits>
#include <errno.h>
namespace boost {
namespace detail {
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)
{
boost::xtime t;
// normalize, in case user has specified nsec only
if (xt.nsec > 999999999)
{
t.sec = xt.nsec / 1000000000;
t.nsec = xt.nsec % 1000000000;
}
else
{
t.sec = t.nsec = 0;
}
timespec ts;
if (xt.sec < std::numeric_limits<time_t>::max() - t.sec) // avoid overflow
{
ts.tv_sec = static_cast<time_t>(xt.sec + t.sec);
ts.tv_nsec = static_cast<long>(t.nsec);
}
else
{ // saturate to avoid overflow
ts.tv_sec = std::numeric_limits<time_t>::max();
ts.tv_nsec = 999999999; // this should not overflow, or tv_nsec is odd anyways...
}
// to_timespec(xt, ts);
int res = 0;
res = pthread_cond_timedwait(&m_condition, pmutex, &ts);
assert(res == 0 || res == ETIMEDOUT);
return res != ETIMEDOUT;
}
} // namespace detail
} // namespace boost

150
src/pthread/exceptions.cpp Normal file
View File

@@ -0,0 +1,150 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/exceptions.hpp>
#include <cstring>
#include <string>
# ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::strerror; }
# endif
#include <errno.h> // for POSIX error codes
namespace
{
std::string system_message(int sys_err_code)
{
std::string str;
str += std::strerror(errno);
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()
{
}
int thread_exception::native_error() const
{
return m_sys_err;
}
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

278
src/pthread/mutex.cpp Normal file
View File

@@ -0,0 +1,278 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/mutex.hpp>
#include <boost/thread/pthread/xtime.hpp>
#include <boost/thread/pthread/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/limits.hpp>
#include <string>
#include <stdexcept>
#include <cassert>
#include <limits>
#include <errno.h>
namespace boost {
mutex::mutex()
{
int res = 0;
res = pthread_mutex_init(&m_mutex, 0);
if (res != 0)
throw thread_resource_error();
}
mutex::~mutex()
{
int res = 0;
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
}
void mutex::do_lock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
if (res == EDEADLK) throw lock_error();
assert(res == 0);
}
void mutex::do_unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mutex);
if (res == EPERM) throw lock_error();
assert(res == 0);
}
void mutex::do_lock(cv_state&)
{
}
void mutex::do_unlock(cv_state& state)
{
state.pmutex = &m_mutex;
}
try_mutex::try_mutex()
{
int res = 0;
res = pthread_mutex_init(&m_mutex, 0);
if (res != 0)
throw thread_resource_error();
}
try_mutex::~try_mutex()
{
int res = 0;
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
}
void try_mutex::do_lock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
if (res == EDEADLK) throw lock_error();
assert(res == 0);
}
bool try_mutex::do_trylock()
{
int res = 0;
res = pthread_mutex_trylock(&m_mutex);
if (res == EDEADLK) throw lock_error();
assert(res == 0 || res == EBUSY);
return res == 0;
}
void try_mutex::do_unlock()
{
int res = 0;
res = pthread_mutex_unlock(&m_mutex);
if (res == EPERM) throw lock_error();
assert(res == 0);
}
void try_mutex::do_lock(cv_state&)
{
}
void try_mutex::do_unlock(cv_state& state)
{
state.pmutex = &m_mutex;
}
timed_mutex::timed_mutex()
: m_locked(false)
{
int res = 0;
res = pthread_mutex_init(&m_mutex, 0);
if (res != 0)
throw thread_resource_error();
res = pthread_cond_init(&m_condition, 0);
if (res != 0)
{
pthread_mutex_destroy(&m_mutex);
throw thread_resource_error();
}
}
timed_mutex::~timed_mutex()
{
assert(!m_locked);
int res = 0;
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
res = pthread_cond_destroy(&m_condition);
assert(res == 0);
}
void timed_mutex::do_lock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
while (m_locked)
{
res = pthread_cond_wait(&m_condition, &m_mutex);
assert(res == 0);
}
assert(!m_locked);
m_locked = true;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
bool timed_mutex::do_trylock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
bool ret = false;
if (!m_locked)
{
m_locked = true;
ret = true;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
return ret;
}
bool timed_mutex::do_timedlock(const xtime& xt)
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
boost::xtime t;
// normalize, in case user has specified nsec only
if (xt.nsec > 999999999)
{
t.sec = xt.nsec / 1000000000;
t.nsec = xt.nsec % 1000000000;
}
else
{
t.sec = t.nsec = 0;
}
timespec ts;
if (xt.sec < std::numeric_limits<time_t>::max() - t.sec) // avoid overflow
{
ts.tv_sec = static_cast<time_t>(xt.sec + t.sec);
ts.tv_nsec = static_cast<long>(t.nsec);
}
else
{ // saturate to avoid overflow
ts.tv_sec = std::numeric_limits<time_t>::max();
ts.tv_nsec = 999999999; // this should not overflow, or tv_nsec is odd anyways...
}
// to_timespec(xt, ts);
while (m_locked)
{
res = pthread_cond_timedwait(&m_condition, &m_mutex, &ts);
assert(res == 0 || res == ETIMEDOUT);
if (res == ETIMEDOUT)
break;
}
bool ret = false;
if (!m_locked)
{
m_locked = true;
ret = true;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
return ret;
}
void timed_mutex::do_unlock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
assert(m_locked);
m_locked = false;
res = pthread_cond_signal(&m_condition);
assert(res == 0);
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
void timed_mutex::do_lock(cv_state&)
{
int res = 0;
while (m_locked)
{
res = pthread_cond_wait(&m_condition, &m_mutex);
assert(res == 0);
}
assert(!m_locked);
m_locked = true;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
void timed_mutex::do_unlock(cv_state& state)
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
assert(m_locked);
m_locked = false;
res = pthread_cond_signal(&m_condition);
assert(res == 0);
state.pmutex = &m_mutex;
}
} // namespace boost

View File

@@ -0,0 +1,589 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/recursive_mutex.hpp>
#include <boost/thread/pthread/xtime.hpp>
#include <boost/thread/pthread/thread.hpp>
#include <boost/limits.hpp>
#include <string>
#include <stdexcept>
#include <cassert>
#include <limits>
#include <errno.h>
namespace boost {
recursive_mutex::recursive_mutex()
: m_count(0)
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
, m_valid_id(false)
#endif
{
pthread_mutexattr_t attr;
int res = pthread_mutexattr_init(&attr);
assert(res == 0);
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
assert(res == 0);
#endif
res = pthread_mutex_init(&m_mutex, &attr);
{
# ifndef NDEBUG
int res =
# endif
pthread_mutexattr_destroy(&attr);
assert(res == 0);
}
if (res != 0)
throw thread_resource_error();
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
res = pthread_cond_init(&m_unlocked, 0);
if (res != 0)
{
pthread_mutex_destroy(&m_mutex);
throw thread_resource_error();
}
#endif
}
recursive_mutex::~recursive_mutex()
{
int res = 0;
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
res = pthread_cond_destroy(&m_unlocked);
assert(res == 0);
#endif
}
void recursive_mutex::do_lock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
if (++m_count > 1)
{
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
#else
pthread_t tid = pthread_self();
if (m_valid_id && pthread_equal(m_thread_id, tid))
++m_count;
else
{
while (m_valid_id)
{
res = pthread_cond_wait(&m_unlocked, &m_mutex);
assert(res == 0);
}
m_thread_id = tid;
m_valid_id = true;
m_count = 1;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
#endif
}
void recursive_mutex::do_unlock()
{
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
if (--m_count == 0)
{
int res = 0;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
#else
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
pthread_t tid = pthread_self();
if (m_valid_id && !pthread_equal(m_thread_id, tid))
{
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
throw lock_error();
}
if (--m_count == 0)
{
assert(m_valid_id);
m_valid_id = false;
res = pthread_cond_signal(&m_unlocked);
assert(res == 0);
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
#endif
}
void recursive_mutex::do_lock(cv_state& state)
{
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
m_count = state.count;
#else
int res = 0;
while (m_valid_id)
{
res = pthread_cond_wait(&m_unlocked, &m_mutex);
assert(res == 0);
}
m_thread_id = pthread_self();
m_valid_id = true;
m_count = state.count;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
#endif
}
void recursive_mutex::do_unlock(cv_state& state)
{
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
assert(m_valid_id);
m_valid_id = false;
res = pthread_cond_signal(&m_unlocked);
assert(res == 0);
#endif
state.pmutex = &m_mutex;
state.count = m_count;
m_count = 0;
}
recursive_try_mutex::recursive_try_mutex()
: m_count(0)
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
, m_valid_id(false)
#endif
{
pthread_mutexattr_t attr;
int res = pthread_mutexattr_init(&attr);
assert(res == 0);
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
res = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
assert(res == 0);
#endif
res = pthread_mutex_init(&m_mutex, &attr);
{
# ifndef NDEBUG
int res =
# endif
pthread_mutexattr_destroy(&attr);
assert(res == 0);
}
if (res != 0)
throw thread_resource_error();
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
res = pthread_cond_init(&m_unlocked, 0);
if (res != 0)
{
pthread_mutex_destroy(&m_mutex);
throw thread_resource_error();
}
#endif
}
recursive_try_mutex::~recursive_try_mutex()
{
int res = 0;
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
res = pthread_cond_destroy(&m_unlocked);
assert(res == 0);
#endif
}
void recursive_try_mutex::do_lock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
if (++m_count > 1)
{
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
#else
pthread_t tid = pthread_self();
if (m_valid_id && pthread_equal(m_thread_id, tid))
++m_count;
else
{
while (m_valid_id)
{
res = pthread_cond_wait(&m_unlocked, &m_mutex);
assert(res == 0);
}
m_thread_id = tid;
m_valid_id = true;
m_count = 1;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
#endif
}
bool recursive_try_mutex::do_trylock()
{
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
int res = 0;
res = pthread_mutex_trylock(&m_mutex);
assert(res == 0 || res == EBUSY);
if (res == 0)
{
if (++m_count > 1)
{
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
return true;
}
return false;
#else
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
bool ret = false;
pthread_t tid = pthread_self();
if (m_valid_id && pthread_equal(m_thread_id, tid))
{
++m_count;
ret = true;
}
else if (!m_valid_id)
{
m_thread_id = tid;
m_valid_id = true;
m_count = 1;
ret = true;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
return ret;
#endif
}
void recursive_try_mutex::do_unlock()
{
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
if (--m_count == 0)
{
int res = 0;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
#else
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
pthread_t tid = pthread_self();
if (m_valid_id && !pthread_equal(m_thread_id, tid))
{
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
throw lock_error();
}
if (--m_count == 0)
{
assert(m_valid_id);
m_valid_id = false;
res = pthread_cond_signal(&m_unlocked);
assert(res == 0);
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
#endif
}
void recursive_try_mutex::do_lock(cv_state& state)
{
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
m_count = state.count;
#else
int res = 0;
while (m_valid_id)
{
res = pthread_cond_wait(&m_unlocked, &m_mutex);
assert(res == 0);
}
m_thread_id = pthread_self();
m_valid_id = true;
m_count = state.count;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
#endif
}
void recursive_try_mutex::do_unlock(cv_state& state)
{
#if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
assert(m_valid_id);
m_valid_id = false;
res = pthread_cond_signal(&m_unlocked);
assert(res == 0);
#endif
state.pmutex = &m_mutex;
state.count = m_count;
m_count = 0;
}
recursive_timed_mutex::recursive_timed_mutex()
: m_valid_id(false), m_count(0)
{
int res = 0;
res = pthread_mutex_init(&m_mutex, 0);
if (res != 0)
throw thread_resource_error();
res = pthread_cond_init(&m_unlocked, 0);
if (res != 0)
{
pthread_mutex_destroy(&m_mutex);
throw thread_resource_error();
}
}
recursive_timed_mutex::~recursive_timed_mutex()
{
int res = 0;
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
res = pthread_cond_destroy(&m_unlocked);
assert(res == 0);
}
void recursive_timed_mutex::do_lock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
pthread_t tid = pthread_self();
if (m_valid_id && pthread_equal(m_thread_id, tid))
++m_count;
else
{
while (m_valid_id)
{
res = pthread_cond_wait(&m_unlocked, &m_mutex);
assert(res == 0);
}
m_thread_id = tid;
m_valid_id = true;
m_count = 1;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
bool recursive_timed_mutex::do_trylock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
bool ret = false;
pthread_t tid = pthread_self();
if (m_valid_id && pthread_equal(m_thread_id, tid))
{
++m_count;
ret = true;
}
else if (!m_valid_id)
{
m_thread_id = tid;
m_valid_id = true;
m_count = 1;
ret = true;
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
return ret;
}
bool recursive_timed_mutex::do_timedlock(const xtime& xt)
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
bool ret = false;
pthread_t tid = pthread_self();
if (m_valid_id && pthread_equal(m_thread_id, tid))
{
++m_count;
ret = true;
}
else
{
boost::xtime t;
// normalize, in case user has specified nsec only
if (xt.nsec > 999999999)
{
t.sec = xt.nsec / 1000000000;
t.nsec = xt.nsec % 1000000000;
}
else
{
t.sec = t.nsec = 0;
}
timespec ts;
if (xt.sec < std::numeric_limits<time_t>::max() - t.sec) // avoid overflow
{
ts.tv_sec = static_cast<time_t>(xt.sec + t.sec);
ts.tv_nsec = static_cast<long>(t.nsec);
}
else
{
ts.tv_sec = std::numeric_limits<time_t>::max();
ts.tv_nsec = 999999999; // this should not overflow, or tv_nsec is odd anyways...
}
// to_timespec(xt, ts);
while (m_valid_id)
{
res = pthread_cond_timedwait(&m_unlocked, &m_mutex, &ts);
if (res == ETIMEDOUT)
break;
assert(res == 0);
}
if (!m_valid_id)
{
m_thread_id = tid;
m_valid_id = true;
m_count = 1;
ret = true;
}
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
return ret;
}
void recursive_timed_mutex::do_unlock()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
pthread_t tid = pthread_self();
if (m_valid_id && !pthread_equal(m_thread_id, tid))
{
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
throw lock_error();
}
if (--m_count == 0)
{
assert(m_valid_id);
m_valid_id = false;
res = pthread_cond_signal(&m_unlocked);
assert(res == 0);
}
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
void recursive_timed_mutex::do_lock(cv_state& state)
{
int res = 0;
while (m_valid_id)
{
res = pthread_cond_wait(&m_unlocked, &m_mutex);
assert(res == 0);
}
m_thread_id = pthread_self();
m_valid_id = true;
m_count = state.count;
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
void recursive_timed_mutex::do_unlock(cv_state& state)
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
assert(m_valid_id);
m_valid_id = false;
res = pthread_cond_signal(&m_unlocked);
assert(res == 0);
state.pmutex = &m_mutex;
state.count = m_count;
m_count = 0;
}
} // namespace boost

288
src/pthread/thread.cpp Normal file
View File

@@ -0,0 +1,288 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/thread.hpp>
#include <boost/thread/pthread/xtime.hpp>
#include <boost/thread/pthread/condition.hpp>
#include <cassert>
#include <limits>
namespace {
class thread_param
{
public:
thread_param(const boost::function0<void>& threadfunc)
: m_threadfunc(threadfunc), m_started(false)
{
}
void wait()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
while (!m_started)
m_condition.wait(scoped_lock);
}
void started()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
m_started = true;
m_condition.notify_one();
}
boost::mutex m_mutex;
boost::condition m_condition;
const boost::function0<void>& m_threadfunc;
bool m_started;
};
// I am not using a constant for the following, to avoid
// the need to specify a type, which might be to small
// to hold the value.
#ifndef NANOSECONDS_PER_SECOND
#define NANOSECONDS_PER_SECOND 1000000000
#endif
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
{
boost::xtime cur, t;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (xt.sec < cur.sec)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
return;
}
else
{
if (xt.nsec < cur.nsec)
{
if (xt.sec == cur.sec)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
return;
}
t.nsec = xt.nsec + NANOSECONDS_PER_SECOND - cur.nsec;
t.sec = xt.sec - cur.sec + 1;
}
else
{
t.nsec = xt.nsec - cur.nsec;
t.sec = xt.sec - cur.sec;
// guard against wrong user nsec spec.
t.sec += t.nsec / NANOSECONDS_PER_SECOND;
t.nsec %= NANOSECONDS_PER_SECOND;
}
if (t.sec < std::numeric_limits<time_t>::max())
{
// the following casts are safe
ts.tv_sec = static_cast<time_t>(t.sec);
ts.tv_nsec = static_cast<long>(t.nsec);
}
else
{
// on overflow return maximum possible
// (very unlikely case though)
ts.tv_sec = std::numeric_limits<time_t>::max();
ts.tv_nsec = std::numeric_limits<long>::max();
}
}
}
} // unnamed namespace
extern "C" {
static void* thread_proxy(void* param)
{
try
{
thread_param* p = static_cast<thread_param*>(param);
boost::function0<void> threadfunc = p->m_threadfunc;
p->started();
threadfunc();
}
catch (...)
{
}
return 0;
}
}
namespace boost {
thread::thread()
: m_joinable(false)
{
m_thread = pthread_self();
}
thread::thread(const function0<void>& threadfunc)
: m_joinable(true)
{
thread_param param(threadfunc);
int res = 0;
res = pthread_create(&m_thread, 0, &thread_proxy, &param);
if (res != 0)
throw thread_resource_error();
param.wait();
}
thread::~thread()
{
if (m_joinable)
{
pthread_detach(m_thread);
}
}
bool thread::operator==(const thread& other) const
{
return pthread_equal(m_thread, other.m_thread) != 0;
}
bool thread::operator!=(const thread& other) const
{
return !operator==(other);
}
void thread::join()
{
assert(m_joinable); //See race condition comment below
int res = 0;
res = pthread_join(m_thread, 0);
assert(res == 0);
// This isn't a race condition since any race that could occur would
// have us in undefined behavior territory any way.
m_joinable = false;
}
void thread::sleep(const xtime& xt)
{
for (int foo=0; foo < 5; ++foo)
{
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec ts;
to_timespec_duration(xt, ts);
int res = 0;
res = pthread_delay_np(&ts);
assert(res == 0);
# elif defined(BOOST_HAS_NANOSLEEP)
timespec ts;
to_timespec_duration(xt, ts);
// nanosleep takes a timespec that is an offset, not
// an absolute time.
nanosleep(&ts, 0);
# else
mutex mx;
mutex::scoped_lock lock(mx);
condition cond;
cond.timed_wait(lock, xt);
# endif
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) <= 0)
return;
}
}
void thread::yield()
{
# if defined(BOOST_HAS_SCHED_YIELD)
int res = 0;
res = sched_yield();
assert(res == 0);
# elif defined(BOOST_HAS_PTHREAD_YIELD)
int res = 0;
res = pthread_yield();
assert(res == 0);
# else
xtime xt;
xtime_get(&xt, TIME_UTC);
sleep(xt);
# endif
}
thread_group::thread_group()
{
}
thread_group::~thread_group()
{
// We shouldn't have to scoped_lock here, since referencing this object
// from another thread while we're deleting it in the current thread is
// going to lead to undefined behavior any way.
for (std::list<thread*>::iterator it = m_threads.begin();
it != m_threads.end(); ++it)
{
delete (*it);
}
}
thread* thread_group::create_thread(const function0<void>& threadfunc)
{
// No scoped_lock required here since the only "shared data" that's
// modified here occurs inside add_thread which does scoped_lock.
std::auto_ptr<thread> thrd(new thread(threadfunc));
add_thread(thrd.get());
return thrd.release();
}
void thread_group::add_thread(thread* thrd)
{
mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to add a thread object multiple
// times. Should we consider this an error and either throw or return an
// error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it == m_threads.end());
if (it == m_threads.end())
m_threads.push_back(thrd);
}
void thread_group::remove_thread(thread* thrd)
{
mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to remove a thread object that's
// not in the group. Should we consider this an error and either throw or
// return an error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it != m_threads.end());
if (it != m_threads.end())
m_threads.erase(it);
}
void thread_group::join_all()
{
mutex::scoped_lock scoped_lock(m_mutex);
for (std::list<thread*>::iterator it = m_threads.begin();
it != m_threads.end(); ++it)
{
(*it)->join();
}
}
int thread_group::size()
{
return m_threads.size();
}
} // namespace boost

128
src/pthread/timeconv.inl Normal file
View File

@@ -0,0 +1,128 @@
// 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.
namespace {
const int MILLISECONDS_PER_SECOND = 1000;
const int NANOSECONDS_PER_SECOND = 1000000000;
const int NANOSECONDS_PER_MILLISECOND = 1000000;
const int MICROSECONDS_PER_SECOND = 1000000;
const int NANOSECONDS_PER_MICROSECOND = 1000;
inline void to_time(int milliseconds, boost::xtime& xt)
{
int res = 0;
res = boost::xtime_get(&xt, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
NANOSECONDS_PER_MILLISECOND);
if (xt.nsec >= NANOSECONDS_PER_SECOND)
{
++xt.sec;
xt.nsec -= NANOSECONDS_PER_SECOND;
}
}
#if defined(BOOST_HAS_PTHREADS)
inline void to_timespec(const boost::xtime& xt, timespec& ts)
{
ts.tv_sec = static_cast<int>(xt.sec);
ts.tv_nsec = static_cast<int>(xt.nsec);
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
{
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
}
}
inline void to_time(int milliseconds, timespec& ts)
{
boost::xtime xt;
to_time(milliseconds, xt);
to_timespec(xt, ts);
}
inline void to_timespec_duration(const boost::xtime& xt, timespec& ts)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0)
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
}
else
{
ts.tv_sec = xt.sec - cur.sec;
ts.tv_nsec = xt.nsec - cur.nsec;
if( ts.tv_nsec < 0 )
{
ts.tv_sec -= 1;
ts.tv_nsec += NANOSECONDS_PER_SECOND;
}
if(ts.tv_nsec >= NANOSECONDS_PER_SECOND)
{
ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
ts.tv_nsec %= NANOSECONDS_PER_SECOND;
}
}
}
#endif
inline void to_duration(boost::xtime xt, int& milliseconds)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) <= 0)
milliseconds = 0;
else
{
if (cur.nsec > xt.nsec)
{
xt.nsec += NANOSECONDS_PER_SECOND;
--xt.sec;
}
milliseconds = (int)((xt.sec - cur.sec) * MILLISECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MILLISECOND/2)) /
NANOSECONDS_PER_MILLISECOND);
}
}
inline void to_microduration(const boost::xtime& xt, int& microseconds)
{
boost::xtime cur;
int res = 0;
res = boost::xtime_get(&cur, boost::TIME_UTC);
assert(res == boost::TIME_UTC);
if (boost::xtime_get(&cur, boost::TIME_UTC) <= 0)
microseconds = 0;
else
{
microseconds = (int)((xt.sec - cur.sec) * MICROSECONDS_PER_SECOND) +
(((xt.nsec - cur.nsec) + (NANOSECONDS_PER_MICROSECOND/2)) /
NANOSECONDS_PER_MICROSECOND);
}
}
}
// Change Log:
// 1 Jun 01 Initial creation.

150
src/pthread/tss.cpp Normal file
View File

@@ -0,0 +1,150 @@
// Copyright (C) 2001-2003 William E. Kempf
// Copyright (C) 2006 Roland Schwarz
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/tss.hpp>
#ifndef BOOST_THREAD_NO_TSS_CLEANUP
#include <boost/thread/pthread/once.hpp>
#include <boost/thread/pthread/mutex.hpp>
#include <boost/thread/pthread/exceptions.hpp>
#include <vector>
#include <string>
#include <stdexcept>
#include <cassert>
namespace {
typedef std::vector<void*> tss_slots;
struct tss_data_t
{
boost::mutex mutex;
std::vector<boost::function1<void, void*>*> cleanup_handlers;
pthread_key_t native_key;
};
tss_data_t* tss_data = 0;
boost::once_flag tss_data_once = BOOST_ONCE_INIT;
extern "C" void cleanup_slots(void* p)
{
tss_slots* slots = static_cast<tss_slots*>(p);
for (tss_slots::size_type i = 0; i < slots->size(); ++i)
{
boost::mutex::scoped_lock lock(tss_data->mutex);
(*tss_data->cleanup_handlers[i])((*slots)[i]);
(*slots)[i] = 0;
}
delete slots;
}
void init_tss_data()
{
std::auto_ptr<tss_data_t> temp(new tss_data_t);
int res = pthread_key_create(&temp->native_key, &cleanup_slots);
if (res != 0)
return;
// Intentional memory "leak"
// This is the only way to ensure the mutex in the global data
// structure is available when cleanup handlers are run, since the
// execution order of cleanup handlers is unspecified on any platform
// with regards to C++ destructor ordering rules.
tss_data = temp.release();
}
tss_slots* get_slots(bool alloc)
{
tss_slots* slots = 0;
slots = static_cast<tss_slots*>(
pthread_getspecific(tss_data->native_key));
if (slots == 0 && alloc)
{
std::auto_ptr<tss_slots> temp(new tss_slots);
if (pthread_setspecific(tss_data->native_key, temp.get()) != 0)
return 0;
slots = temp.release();
}
return slots;
}
} // namespace
namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
boost::call_once(&init_tss_data, tss_data_once);
if (tss_data == 0)
throw thread_resource_error();
boost::mutex::scoped_lock lock(tss_data->mutex);
try
{
tss_data->cleanup_handlers.push_back(pcleanup);
m_slot = tss_data->cleanup_handlers.size() - 1;
}
catch (...)
{
throw thread_resource_error();
}
}
void* tss::get() const
{
tss_slots* slots = get_slots(false);
if (!slots)
return 0;
if (m_slot >= slots->size())
return 0;
return (*slots)[m_slot];
}
void tss::set(void* value)
{
tss_slots* slots = get_slots(true);
if (!slots)
throw boost::thread_resource_error();
if (m_slot >= slots->size())
{
try
{
slots->resize(m_slot + 1);
}
catch (...)
{
throw boost::thread_resource_error();
}
}
(*slots)[m_slot] = value;
}
void tss::cleanup(void* value)
{
boost::mutex::scoped_lock lock(tss_data->mutex);
(*tss_data->cleanup_handlers[m_slot])(value);
}
} // namespace detail
} // namespace boost
#endif //BOOST_THREAD_NO_TSS_CLEANUP

48
src/pthread/xtime.cpp Normal file
View File

@@ -0,0 +1,48 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/pthread/config.hpp>
#include <boost/thread/pthread/xtime.hpp>
// TODO: xtime possible should be replaced by boost date time
#if defined(BOOST_HAS_GETTIMEOFDAY)
# include <sys/time.h>
#elif ! defined (BOOST_HAS_CLOCK_GETTIME)
# include <time.h>
#endif
namespace boost {
int xtime_get(struct xtime* xtp, int clock_type)
{
if (clock_type == TIME_UTC)
{
#if defined(BOOST_HAS_GETTIMEOFDAY)
struct timeval tv;
gettimeofday(&tv, 0);
xtp->sec = tv.tv_sec;
xtp->nsec = tv.tv_usec * 1000;
return clock_type;
#elif defined(BOOST_HAS_CLOCK_GETTIME)
timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
xtp->sec = ts.tv_sec;
xtp->nsec = ts.tv_nsec;
return clock_type;
#else
time_t t;
time(&t);
xtp->sec = t;
xtp->nsec = 0;
return clock_type;
#endif
}
return 0;
}
} // namespace boost

166
src/win32/exceptions.cpp Normal file
View File

@@ -0,0 +1,166 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/win32/config.hpp>
#include <boost/thread/win32/exceptions.hpp>
#include <cstring>
#include <string>
# ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::strerror; }
# endif
#include "windows.h"
namespace
{
std::string system_message(int sys_err_code)
{
std::string str;
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);
}
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()
{
}
int thread_exception::native_error() const
{
return m_sys_err;
}
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

247
src/win32/thread.cpp Normal file
View File

@@ -0,0 +1,247 @@
// Copyright 2006 Roland Schwarz.
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// This work is a reimplementation along the design and ideas
// of William E. Kempf.
#include <boost/thread/win32/config.hpp>
#include <boost/thread/win32/thread.hpp>
#include <boost/thread/win32/xtime.hpp>
#include <boost/thread/win32/condition.hpp>
#include <cassert>
#include <windows.h>
#if !defined(BOOST_NO_THREADEX)
# include <process.h>
#endif
#include "timeconv.inl"
//#include "boost/thread/win32/tss_hooks.hpp"
namespace {
#if defined(BOOST_NO_THREADEX)
// Windows CE doesn't define _beginthreadex
struct ThreadProxyData
{
typedef unsigned (__stdcall* func)(void*);
func start_address_;
void* arglist_;
ThreadProxyData(func start_address,void* arglist) : start_address_(start_address), arglist_(arglist) {}
};
DWORD WINAPI ThreadProxy(LPVOID args)
{
ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args);
DWORD ret=data->start_address_(data->arglist_);
delete data;
return ret;
}
inline unsigned _beginthreadex(void* security, unsigned stack_size, unsigned (__stdcall* start_address)(void*),
void* arglist, unsigned initflag,unsigned* thrdaddr)
{
DWORD threadID;
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
new ThreadProxyData(start_address,arglist),initflag,&threadID);
if (hthread!=0)
*thrdaddr=threadID;
return reinterpret_cast<unsigned>(hthread);
}
#endif
class thread_param
{
public:
thread_param(const boost::function0<void>& threadfunc)
: m_threadfunc(threadfunc), m_started(false)
{
}
void wait()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
while (!m_started)
m_condition.wait(scoped_lock);
}
void started()
{
boost::mutex::scoped_lock scoped_lock(m_mutex);
m_started = true;
m_condition.notify_one();
}
boost::mutex m_mutex;
boost::condition m_condition;
const boost::function0<void>& m_threadfunc;
bool m_started;
};
} // unnamed namespace
extern "C" {
unsigned __stdcall thread_proxy(void* param)
{
try
{
thread_param* p = static_cast<thread_param*>(param);
boost::function0<void> threadfunc = p->m_threadfunc;
p->started();
threadfunc();
// on_thread_exit();
}
catch (...)
{
// on_thread_exit();
}
return 0;
}
}
namespace boost {
thread::thread()
: m_joinable(false)
{
m_thread = reinterpret_cast<void*>(GetCurrentThread());
m_id = GetCurrentThreadId();
}
thread::thread(const function0<void>& threadfunc)
: m_joinable(true)
{
thread_param param(threadfunc);
m_thread = reinterpret_cast<void*>(_beginthreadex(0, 0, &thread_proxy,
&param, 0, &m_id));
if (!m_thread)
throw thread_resource_error();
param.wait();
}
thread::~thread()
{
if (m_joinable)
{
int res = 0;
res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
assert(res);
}
}
bool thread::operator==(const thread& other) const
{
return other.m_id == m_id;
}
bool thread::operator!=(const thread& other) const
{
return !operator==(other);
}
void thread::join()
{
assert(m_joinable); //See race condition comment below
int res = 0;
res = WaitForSingleObject(reinterpret_cast<HANDLE>(m_thread), INFINITE);
assert(res == WAIT_OBJECT_0);
res = CloseHandle(reinterpret_cast<HANDLE>(m_thread));
assert(res);
// This isn't a race condition since any race that could occur would
// have us in undefined behavior territory any way.
m_joinable = false;
}
void thread::sleep(const xtime& xt)
{
for (int foo=0; foo < 5; ++foo)
{
int milliseconds;
to_duration(xt, milliseconds);
Sleep(milliseconds);
xtime cur;
xtime_get(&cur, TIME_UTC);
if (xtime_cmp(xt, cur) <= 0)
return;
}
}
void thread::yield()
{
Sleep(0);
}
thread_group::thread_group()
{
}
thread_group::~thread_group()
{
// We shouldn't have to scoped_lock here, since referencing this object
// from another thread while we're deleting it in the current thread is
// going to lead to undefined behavior any way.
for (std::list<thread*>::iterator it = m_threads.begin();
it != m_threads.end(); ++it)
{
delete (*it);
}
}
thread* thread_group::create_thread(const function0<void>& threadfunc)
{
// No scoped_lock required here since the only "shared data" that's
// modified here occurs inside add_thread which does scoped_lock.
std::auto_ptr<thread> thrd(new thread(threadfunc));
add_thread(thrd.get());
return thrd.release();
}
void thread_group::add_thread(thread* thrd)
{
mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to add a thread object multiple
// times. Should we consider this an error and either throw or return an
// error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it == m_threads.end());
if (it == m_threads.end())
m_threads.push_back(thrd);
}
void thread_group::remove_thread(thread* thrd)
{
mutex::scoped_lock scoped_lock(m_mutex);
// For now we'll simply ignore requests to remove a thread object that's
// not in the group. Should we consider this an error and either throw or
// return an error value?
std::list<thread*>::iterator it = std::find(m_threads.begin(),
m_threads.end(), thrd);
assert(it != m_threads.end());
if (it != m_threads.end())
m_threads.erase(it);
}
void thread_group::join_all()
{
mutex::scoped_lock scoped_lock(m_mutex);
for (std::list<thread*>::iterator it = m_threads.begin();
it != m_threads.end(); ++it)
{
(*it)->join();
}
}
int thread_group::size()
{
return m_threads.size();
}
} // namespace boost

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