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

Compare commits

...

280 Commits

Author SHA1 Message Date
Nicola Musatti
28d5417cc9 bcbboost branch rebased on current release
[SVN r49389]
2008-10-19 14:43:01 +00:00
Anthony Williams
0997fad8ec Merged Boost.Thread changes from trunk
[SVN r49324]
2008-10-13 20:30:13 +00:00
Nicola Musatti
73715bd096 Merge from trunk
[SVN r49137]
2008-10-05 08:23:27 +00:00
Nicola Musatti
372ba84c40 Merge from trunk
[SVN r49113]
2008-10-02 17:47:30 +00:00
Nicola Musatti
6b562eab48 Merge from trunk
[SVN r49053]
2008-09-29 22:02:20 +00:00
Nicola Musatti
2f53e5d440 Patches for Codegear C++ Builder 2009
[SVN r48981]
2008-09-27 08:59:20 +00:00
Anthony Williams
8fd0dd0cc0 Define a raw DLL main which is called by the C runtime if we're statically linked into a DLL --- fix for issue #2199
[SVN r48537]
2008-09-02 16:56:57 +00:00
Anthony Williams
8eea5811ba Don't allocate TLS Key unless we need it; deallocate it on process exit --- partial fix for bug #2199
[SVN r48536]
2008-09-02 16:54:56 +00:00
Anthony Williams
a154c2adab Removed locked and get_active_count
[SVN r48531]
2008-09-02 10:38:17 +00:00
Anthony Williams
10bf4ed576 Removed locked and get_active_count
[SVN r48530]
2008-09-02 10:38:04 +00:00
Anthony Williams
60d12dd395 Added recursive_mutex/condition::wait() change to list of breaking changes
[SVN r48528]
2008-09-02 10:22:06 +00:00
Anthony Williams
b4e9be3c52 Added missing relative time constructor to unique_lock
[SVN r48213]
2008-08-19 10:26:53 +00:00
Anthony Williams
dcebae6d4a Renamed internal bind stuff to invoker, as more expressive
[SVN r48209]
2008-08-19 07:03:22 +00:00
Anthony Williams
8749696538 Merged Thread doc changes from trunk
[SVN r48038]
2008-08-08 20:38:50 +00:00
Anthony Williams
0d776bcd26 Updated changes list
[SVN r48037]
2008-08-08 20:37:30 +00:00
Anthony Williams
2d6ed47cf2 Updated signature of create_thread
[SVN r48036]
2008-08-08 20:21:29 +00:00
Anthony Williams
9beea23f63 Merged thread doc changes from trunk
[SVN r47827]
2008-07-26 08:39:51 +00:00
Anthony Williams
ea06434425 Doc updates missed by previous checkin
[SVN r47826]
2008-07-26 08:37:55 +00:00
Anthony Williams
6508eff95e Added note about max number of arguments
[SVN r47818]
2008-07-25 22:22:58 +00:00
Anthony Williams
69930684a9 Added a description for the new thread constructors that allow functions with arguments.
[SVN r47817]
2008-07-25 22:21:05 +00:00
Anthony Williams
b1931a3eda Fix for trac issue #2118
[SVN r47816]
2008-07-25 22:01:04 +00:00
Anthony Williams
63b44d4e32 Added documentation for the lock and try_lock free functions
[SVN r47815]
2008-07-25 21:57:33 +00:00
Anthony Williams
f7cb8d8141 Added a description for the scoped_try_lock typedefs
[SVN r47814]
2008-07-25 21:30:37 +00:00
Anthony Williams
48c857e02c Fix for issue #2105: specify which header to include for each class or function
[SVN r47810]
2008-07-25 21:12:29 +00:00
Anthony Williams
2978d43a5d Merged thread doc changes from trunk
[SVN r47701]
2008-07-23 09:37:02 +00:00
Anthony Williams
a264766584 Merged changes over from trunk
[SVN r47700]
2008-07-23 09:35:40 +00:00
Anthony Williams
442dc58e0f Use sysconf(_SC_NPROCESSORS_ONLN) where it is available, as a fallback
[SVN r47654]
2008-07-21 10:39:50 +00:00
Anthony Williams
25460c652c Use sysconf to detect number of processors on AIX too
[SVN r47653]
2008-07-21 10:25:08 +00:00
Anthony Williams
31a98f0a1e BOOST_NO_SFINAE isn't enough to identify compilers that can't auto-detect mutexes, so create a new macro for that, and add IBM and Sun compilers to list
[SVN r47652]
2008-07-21 10:04:26 +00:00
Anthony Williams
36c44b6f45 Borland-specific fixes should apply to all compilers for which enable_if is broken: check for BOOST_NO_SFINAE instead
[SVN r47554]
2008-07-18 13:42:10 +00:00
Anthony Williams
27426b18d1 Split lock and try_lock into mutex and range overloads without using enable_if, so it works on Borland compilers
[SVN r47472]
2008-07-16 14:41:09 +00:00
Anthony Williams
3ea9ce1c8c Fixes to make basic thread functionality work with Borland compilers again
[SVN r47471]
2008-07-16 13:19:43 +00:00
Anthony Williams
f03a9bfcf3 Merged thread changes from trunk
[SVN r47211]
2008-07-08 07:44:55 +00:00
Anthony Williams
4dfc636c84 test and fix for issue #2080
[SVN r47199]
2008-07-07 22:19:28 +00:00
Anthony Williams
5fe4312c6c test and fix for issue #2081
[SVN r47197]
2008-07-07 22:04:10 +00:00
Anthony Williams
63e675a6bb Corrected description to avoid reference to arguments
[SVN r47172]
2008-07-07 07:30:27 +00:00
Anthony Williams
e92aeac7d7 Added notify functions to class synopsis
[SVN r47171]
2008-07-07 07:28:32 +00:00
Anthony Williams
f1f7eac1f2 Backwards compatibility with xtime --- test and fix for issue #2052
[SVN r47149]
2008-07-06 21:58:11 +00:00
Anthony Williams
eff0c84553 Test and fix for issue #2076
[SVN r47120]
2008-07-05 21:55:36 +00:00
Anthony Williams
58c8ce61c7 Fix for issue #2065
[SVN r47077]
2008-07-04 15:45:52 +00:00
Anthony Williams
6ac5e6953a Qualify everything with boost:: to try and avoid name clashes on AIX
[SVN r47070]
2008-07-04 07:30:35 +00:00
Anthony Williams
5d9ad59af2 Use rvalue refs for move semantics of unique_lock where available
[SVN r47033]
2008-07-03 09:16:49 +00:00
Anthony Williams
3c48a05437 Added try_lock_upgrade to shared_mutex: second half of #1867 fix
[SVN r46961]
2008-07-01 16:28:06 +00:00
Anthony Williams
4462124ff2 Added try_lock_upgrade to shared_mutex: second half of #1867 fix
[SVN r46960]
2008-07-01 16:27:59 +00:00
Anthony Williams
373f557ef7 Reduced thread counts to make tests run faster
[SVN r46958]
2008-07-01 16:22:47 +00:00
Anthony Williams
495e561398 Partial fix for issue #1867 - ensure boost::shared_mutex supports try_lock
[SVN r46956]
2008-07-01 16:04:51 +00:00
Anthony Williams
d24a579033 Partial fix for issue #1867 - ensure boost::shared_mutex supports try_lock
[SVN r46955]
2008-07-01 16:04:43 +00:00
Anthony Williams
77130424b4 Removed tabs from source files
[SVN r46706]
2008-06-26 06:43:30 +00:00
Anthony Williams
eb30688937 Added license and copyright to docs
[SVN r46705]
2008-06-26 06:41:00 +00:00
Anthony Williams
880bac0633 Added missing include of detail/config.hpp
[SVN r46624]
2008-06-23 12:14:58 +00:00
Anthony Williams
60fdcddcb5 Merge of new boost.thread code along with required changes from boost.bind
[SVN r46474]
2008-06-18 13:01:08 +00:00
Anthony Williams
851d6a987f Correctly remove the reference type when copying the thread function into the thread data area so we don't end up with a dangling reference
[SVN r46295]
2008-06-10 15:29:35 +00:00
Anthony Williams
9bebd7b35f Disable general templated thread constructor for movable types, in order to prevent it trying to act as a thread copy constructor for EDG based compilers
[SVN r46273]
2008-06-09 14:00:03 +00:00
Anthony Williams
309acb9597 Don't try and use _interlockedbittestandset primitives if we don't know they're present
[SVN r46219]
2008-06-07 20:54:19 +00:00
Anthony Williams
a56887167e Added swap for try_lock_wrapper
[SVN r46164]
2008-06-05 12:25:58 +00:00
Anthony Williams
e984dff4e4 Combined TSS header for pthread and win32, #1958 now fixed for pthread too
[SVN r46162]
2008-06-05 11:19:06 +00:00
Anthony Williams
685e4d446b Test and fix for bug #1958 on Win32
[SVN r46161]
2008-06-05 11:16:05 +00:00
Anthony Williams
8af680f307 Added swap for unique_lock
[SVN r46160]
2008-06-05 10:39:08 +00:00
Anthony Williams
6c60cce60d Removed partial initializer for res: both values will be assigned later, so no need to initialize either
[SVN r46124]
2008-06-04 16:05:29 +00:00
Anthony Williams
5882a675bb Added extra initializer to timeout to try and eliminate warnings with some compilers
[SVN r46123]
2008-06-04 16:03:51 +00:00
Anthony Williams
a5e95845b3 Added documentation for swap()
[SVN r46122]
2008-06-04 16:00:13 +00:00
Anthony Williams
5b83d81e40 Added free function swap() for threads
[SVN r46121]
2008-06-04 15:50:34 +00:00
Anthony Williams
c8e5ad564d basic_condition_variable::lock_entry extracted to basic_cv_lock_entry in order to try and eliminate problems on Borland compiler
[SVN r46094]
2008-06-03 20:56:39 +00:00
Anthony Williams
5edfa273ff removed unused header
[SVN r46093]
2008-06-03 20:55:40 +00:00
Anthony Williams
4db57bcb10 Move thread_data to detail namespace rather than have it as a nested type of boost::thread, to try and help compilers that have problems with the partial specializations for reference_wrapper
[SVN r45912]
2008-05-29 15:38:08 +00:00
Anthony Williams
3f13340903 Don't construct function objects directly in boost::thread constructor as some compilers can't handle that.
[SVN r45911]
2008-05-29 15:36:52 +00:00
Anthony Williams
6abb53c9d3 Move definition of constructor and destructor of condition_variable into condition_variable_fwd.hpp, so they are always available
[SVN r45909]
2008-05-29 15:16:55 +00:00
Anthony Williams
fdd20a519e Use wrapper functions in try_lock_wrapper rather than using declarations, as the latter confuse some compilers
[SVN r45908]
2008-05-29 15:16:04 +00:00
Anthony Williams
67cc49f333 More tests for generic locks, and a new range version
[SVN r45897]
2008-05-29 09:02:05 +00:00
Anthony Williams
31a34cd0b5 Added missing "no"
[SVN r45870]
2008-05-28 14:50:25 +00:00
Anthony Williams
ef8c08ba99 Removed surplus "the"
[SVN r45869]
2008-05-28 12:55:30 +00:00
Anthony Williams
2991ca6c6f Added abi prefix and suffix headers
[SVN r45865]
2008-05-28 11:02:06 +00:00
Anthony Williams
52bace18b2 hardware_concurrency works for CYGWIN
[SVN r45860]
2008-05-28 09:38:14 +00:00
Anthony Williams
767d14ae4f Added documentation for time support in the thread library
[SVN r45859]
2008-05-28 09:00:32 +00:00
Anthony Williams
1a5c911e36 Added documentation for time support in the thread library
[SVN r45858]
2008-05-28 09:00:23 +00:00
Anthony Williams
6e42a04e43 Added note about move support
[SVN r45856]
2008-05-28 08:09:07 +00:00
Anthony Williams
28be2cfeef intrusive_ptr_add_ref and intrusive_ptr_release need to be inline if defined in the header
[SVN r45809]
2008-05-27 06:32:05 +00:00
Anthony Williams
8be168fd87 Basic tests for lock() when other thread is acquiring locks in same or opposite order
[SVN r45767]
2008-05-26 08:59:48 +00:00
Anthony Williams
eee95fef57 Initial test for generic lock functions
[SVN r45766]
2008-05-26 08:40:21 +00:00
Anthony Williams
9ea179b052 Initial test for generic lock functions
[SVN r45765]
2008-05-26 08:40:13 +00:00
Anthony Williams
6868280409 Try and avoid compile errors in test_thread_callable_object_one_argument
[SVN r45764]
2008-05-26 07:36:16 +00:00
Anthony Williams
e00b764454 The signature of _interlockedbittestandset changes between MSVC 2005 and MSVC 2008
[SVN r45689]
2008-05-23 19:53:06 +00:00
Anthony Williams
999613c686 Added note about mutex not being recursive
[SVN r45688]
2008-05-23 19:33:18 +00:00
Anthony Williams
c2661d7eb5 define intrusive_ptr_add_ref and intrusive_ptr_release at namespace scope rather than inline as friends in order to try and avoid compiler problems
[SVN r45682]
2008-05-23 15:18:19 +00:00
Anthony Williams
4d21dd1f47 try_lock_wrapper implements operator! in order to try and avoid compiler problems
[SVN r45681]
2008-05-23 15:17:14 +00:00
Anthony Williams
a0a0e57527 Fixed #ifdef to actually use BTS primitives on MSVC 9
[SVN r45676]
2008-05-23 13:16:01 +00:00
Anthony Williams
d8af0d0b4e Reset thread_info on move rather than assigning 0
[SVN r45672]
2008-05-23 10:48:07 +00:00
Anthony Williams
113288e3b0 tidying up move
[SVN r45661]
2008-05-22 16:33:34 +00:00
Anthony Williams
afecfd7c2d Refactored boost::thread code to try and remove duplication
[SVN r45647]
2008-05-22 11:49:48 +00:00
Anthony Williams
94d89aac5f more rvalue reference stuff
[SVN r45626]
2008-05-21 21:11:30 +00:00
Anthony Williams
8831b13efc Use lock_guard<> instead of unique_lock<> internally. Clear out generations after notify_all, as they're all notified
[SVN r45625]
2008-05-21 21:10:45 +00:00
Peter Dimov
01f99da03a Extended boost::thread to 9 arguments, hopefully fixed member function ambiguity.
[SVN r45621]
2008-05-21 20:44:08 +00:00
Anthony Williams
080654e3ef New tests for a normal function with one argument, and a member function with 0 or 1 arguments
[SVN r45607]
2008-05-21 13:38:04 +00:00
Anthony Williams
2ac2eb2a61 try_lock_wrapper has its own operator bool_type to avoid problems with a using declaration
[SVN r45602]
2008-05-21 10:39:47 +00:00
Anthony Williams
61b940b705 Renamed namespace user to user_test_ns to try and avoid a name clash on some platforms
[SVN r45601]
2008-05-21 09:51:53 +00:00
Anthony Williams
4a4f87e017 support for a generic lock() function
[SVN r45481]
2008-05-18 09:10:20 +00:00
Anthony Williams
6d5e7f63a7 Added beginnings of real rvalue-reference support
[SVN r45479]
2008-05-18 08:45:44 +00:00
Anthony Williams
f77285f375 Updated docs to make it explicit that terminate is called if a thread function throws an exception
[SVN r45294]
2008-05-12 09:04:02 +00:00
Anthony Williams
dc5d03a6dc Cleaned up to remove warnings
[SVN r45244]
2008-05-09 07:59:57 +00:00
Anthony Williams
ea0961b7f6 Fixed type truncation warning
[SVN r45243]
2008-05-09 07:49:22 +00:00
Anthony Williams
33d9f9774c Test and fix for bug #1905
[SVN r45242]
2008-05-09 07:48:44 +00:00
Anthony Williams
86097fa038 Use _WIN32 rather than WIN32 to prevent include of <unistd.h>
[SVN r45241]
2008-05-09 07:47:14 +00:00
Anthony Williams
70d9dbc45a Added default constructor to lock types
[SVN r45212]
2008-05-08 14:34:40 +00:00
Anthony Williams
3926fd3a20 Added docs for native_handle
[SVN r45211]
2008-05-08 12:59:59 +00:00
Anthony Williams
7861cf1146 Added native_handle to mutex types where possible
[SVN r45210]
2008-05-08 12:59:10 +00:00
Anthony Williams
0516b86a6e new BTS-based mutex implementation on win32
[SVN r45119]
2008-05-04 22:39:52 +00:00
Anthony Williams
ec735d3e9b Simplified move support
[SVN r45108]
2008-05-04 09:52:54 +00:00
Anthony Williams
1c5c070983 Updated locks.hpp to work with gcc as well as msvc
[SVN r44846]
2008-04-28 12:26:27 +00:00
Anthony Williams
a5c02b73dc Added entry to breaking changes about default-constructed threads and the current thread: issue #1835
[SVN r44840]
2008-04-28 09:10:38 +00:00
Anthony Williams
918b920670 Added detail::try_lock_wrapper for use as scoped_try_lock typedefs, to fix issue #1873
[SVN r44838]
2008-04-28 09:00:58 +00:00
Anthony Williams
de67d2e27e Fixed g++ compile error
[SVN r44773]
2008-04-26 07:34:46 +00:00
Anthony Williams
bc89df04cb Revamped condition variable to try and fix swallowed-notify problems (trac issue #1834)
[SVN r44699]
2008-04-21 16:22:16 +00:00
Anthony Williams
c26a4cf082 added private copy assignment operator and copy constructor to remove warnings
[SVN r44698]
2008-04-21 16:20:31 +00:00
Anthony Williams
6e1a866b13 Fix for issue #1657
[SVN r44424]
2008-04-14 21:04:33 +00:00
Anthony Williams
f91986ad0d Added extended adopt/defer/try constructors to upgrade_lock
[SVN r44370]
2008-04-13 15:50:08 +00:00
Anthony Williams
795cc23f3e Added test and fix for win32 condition_variable broadcast bug similar to #1803
[SVN r44168]
2008-04-11 08:52:09 +00:00
Anthony Williams
a3695bd4a0 Updated thread.hpp as catch-all header
[SVN r44153]
2008-04-10 18:34:42 +00:00
Anthony Williams
08dc521daf Added native_handle to condition_variable on pthreads
[SVN r44152]
2008-04-10 15:52:01 +00:00
Anthony Williams
8b916d21b1 added tests for plain timed_lock on shared_mutex
[SVN r44150]
2008-04-10 14:15:26 +00:00
Anthony Williams
c40f47a78a added overloads of timed_lock_shared with a relative timeout to shared_mutex
[SVN r44149]
2008-04-10 14:07:39 +00:00
Anthony Williams
e9fb470b06 Added native_handle to thread on posix platforms
[SVN r44148]
2008-04-10 13:35:07 +00:00
Anthony Williams
343d049772 fix for trac ticket #1804
[SVN r44147]
2008-04-10 13:27:44 +00:00
Anthony Williams
86f9480da4 fix for notify problem in trac ticket #1803
[SVN r44146]
2008-04-10 13:14:43 +00:00
Anthony Williams
8696b610ca Added test for trac ticket #1803: condition_variable::notify_one may fail to wake a waiting thread on win32
[SVN r44136]
2008-04-09 19:33:06 +00:00
Anthony Williams
6f13227eda Added locked-> owns_lock change to breaking changes
[SVN r44089]
2008-04-07 13:09:36 +00:00
Anthony Williams
525d190f91 removed declaration of undefined type exclusive_lock
[SVN r43850]
2008-03-25 07:59:58 +00:00
Anthony Williams
58d5110e61 removed forward declaration for undefined type exclusive_lock
[SVN r43847]
2008-03-24 21:44:36 +00:00
Anthony Williams
1e0154335b Imported revision #43730 from trunk to eliminate some warnings
[SVN r43743]
2008-03-21 15:04:10 +00:00
Anthony Williams
76e53c7bc5 Removed some warnings: those from issue #1640 and others
[SVN r43730]
2008-03-19 17:25:13 +00:00
Anthony Williams
413c29a5e4 New documentation for thread library imported from trunk revision 43671
[SVN r43674]
2008-03-17 13:59:17 +00:00
Anthony Williams
30bb6143c1 Test and fix for bug #1693 to ensure thread_specific_ptr::release works as desired imported from trunk changeset 43666
[SVN r43673]
2008-03-17 13:46:19 +00:00
Anthony Williams
cfb08be1a8 New documentation for new thread library
[SVN r43671]
2008-03-17 10:29:27 +00:00
Anthony Williams
b5bbb7fb1c Test and fix for bug #1693 to ensure thread_specific_ptr works as desired
[SVN r43666]
2008-03-17 08:36:09 +00:00
Anthony Williams
a76c33f8cc made the callable_no_args function object a named object rather than a temporary, in order to avoid gratuitous breakage on some compilers
[SVN r43528]
2008-03-06 07:59:16 +00:00
Anthony Williams
991ac727c6 Imported changeset 43461 to fix issue #1665
[SVN r43520]
2008-03-05 20:47:56 +00:00
Anthony Williams
810306b8f3 thread constructor now accepts up to three additional arguments to pass to thread function
[SVN r43464]
2008-03-03 10:52:44 +00:00
Anthony Williams
6c22bdb3bd Test and fix for issue #1665
[SVN r43461]
2008-03-03 08:44:42 +00:00
Daniel James
569a78649f Merged revisions 43211,43214-43219,43222-43225,43227-43238,43242,43244-43245,43249-43250,43257-43259,43261,43263,43265,43267-43268,43270-43271,43273,43275-43279,43284-43289,43291,43295,43297-43298,43304-43305,43307,43313,43315,43324,43326-43327,43331,43333,43339-43343,43345,43348,43350,43352-43353,43355-43356,43358,43360,43366-43367,43369-43370,43372-43376,43378-43389,43394,43396-43398,43400-43401,43403-43404,43406-43408,43413-43415,43417-43418,43420,43422-43423 via svnmerge from
https://svn.boost.org/svn/boost/trunk

........
  r43417 | danieljames | 2008-02-26 22:04:55 +0000 (Tue, 26 Feb 2008) | 2 lines
  
  Fix a link to Boost.Bimap.
........
  r43418 | danieljames | 2008-02-26 22:07:25 +0000 (Tue, 26 Feb 2008) | 2 lines
  
  Change another link that's no longer in the repository to link to the website.
........
  r43422 | danieljames | 2008-02-27 18:51:14 +0000 (Wed, 27 Feb 2008) | 1 line
  
  Fix broken copyright urls. Fixes #1573.
........
  r43423 | danieljames | 2008-02-27 19:22:01 +0000 (Wed, 27 Feb 2008) | 1 line
  
  Fix incorrect links to copyright of the form 'http:#www.boost.org
........


[SVN r43425]
2008-02-27 20:00:24 +00:00
Daniel James
6a0d3e98bc Fix broken copyright urls. Fixes #1573.
[SVN r43422]
2008-02-27 18:51:14 +00:00
Anthony Williams
7caec1ec33 Fix for ticket #1547 --- Change use of NULL to 0
[SVN r43268]
2008-02-15 17:56:13 +00:00
Anthony Williams
7fd3fb48b1 Pulling changeset 43094 over from trunk
[SVN r43227]
2008-02-12 20:49:56 +00:00
Anthony Williams
3809321037 added test for duration overloads of timed_lock, and added missing implementation to win32 version
[SVN r43094]
2008-02-04 13:16:32 +00:00
Anthony Williams
eef695bdf0 Provide tss_cleanup_implemented as a dummy function on Windows CE to allow tests to run
[SVN r42818]
2008-01-16 15:23:36 +00:00
Anthony Williams
ab01ab1e4d removed references to NULL
[SVN r42657]
2008-01-10 14:19:36 +00:00
Anthony Williams
a32a3b37db Merged latest changes to boost.thread over from trunk
[SVN r42230]
2007-12-21 11:51:05 +00:00
Anthony Williams
c8d8a108a7 Updated thread ID test
[SVN r42228]
2007-12-21 10:54:59 +00:00
Anthony Williams
7afd9efcc5 added hardware_concurrency support for apple, freebsd and sun platforms
[SVN r42195]
2007-12-20 08:37:02 +00:00
Anthony Williams
56ded87ad2 added missing parentheses
[SVN r42194]
2007-12-20 07:46:00 +00:00
Anthony Williams
82e503339b Implement hardware_concurrency for pthread
[SVN r42168]
2007-12-19 10:45:01 +00:00
Anthony Williams
713d0c7ace Updated thread ID, and added tests
[SVN r42166]
2007-12-19 10:39:45 +00:00
Anthony Williams
25ad6e3f8f boost::move support for locks
[SVN r42118]
2007-12-17 12:52:50 +00:00
Anthony Williams
df0197b617 Updated move function test to be fair to Borland
[SVN r42117]
2007-12-17 11:24:13 +00:00
Anthony Williams
a89c4f01ad explicit move functions for threads, with a test
[SVN r42087]
2007-12-15 22:36:43 +00:00
Anthony Williams
ae67099633 added timed_wait overloads that take a duration
[SVN r42086]
2007-12-15 22:34:30 +00:00
Anthony Williams
57542d3a5c fixed order of comparison in timeout check
[SVN r41819]
2007-12-07 08:11:11 +00:00
Anthony Williams
9a1da14116 improved timeout checks
[SVN r41741]
2007-12-05 10:58:45 +00:00
Anthony Williams
ed050d753d added missing include of detail/config.hpp
[SVN r41738]
2007-12-05 08:27:44 +00:00
Anthony Williams
8bec363710 changed order of declaration to eliminate warnings
[SVN r41687]
2007-12-04 14:07:01 +00:00
Anthony Williams
7c68e190a9 Added test for thread move constructor; implemented move on pthreads
[SVN r41686]
2007-12-04 13:02:58 +00:00
Anthony Williams
7ebf5ea3d1 add explicit casts to remove warnings
[SVN r41684]
2007-12-04 12:08:38 +00:00
Anthony Williams
11e0435a4b don't dllexport/dllimport inline functions
[SVN r41683]
2007-12-04 11:44:25 +00:00
Anthony Williams
d15ee57cd1 split shared mutex tests in two to take less time
[SVN r41682]
2007-12-04 10:04:30 +00:00
Anthony Williams
56d660b7fd changed boost::move to boost::detail::thread_move to fix issue #1492
[SVN r41681]
2007-12-04 09:15:37 +00:00
Anthony Williams
792958e693 fixed typo in condition_variable_any::timed_wait
[SVN r41679]
2007-12-04 07:57:23 +00:00
Anthony Williams
914e67dc04 check predicate before returning if we time out on a predicated version of timed_wait
[SVN r41668]
2007-12-03 22:00:26 +00:00
Anthony Williams
b50a7ccb61 interruptible_wait (and hence condition timed_wait) now uses a WaitableTimer where possible, to be robust in the face of clock changes
[SVN r41505]
2007-11-30 18:38:21 +00:00
Anthony Williams
f827709d42 add support for relative timeouts to condition timed_wait
[SVN r41413]
2007-11-27 14:24:29 +00:00
Anthony Williams
36abb42175 reverted accidental checkin of new timed_wait functions on condition_variable
[SVN r41405]
2007-11-26 21:15:04 +00:00
Anthony Williams
40f3b1b4c8 once_flag uses zero-initialization on POSIX as well as windows
[SVN r41401]
2007-11-26 17:01:08 +00:00
Anthony Williams
4f35e25688 fixed import/export declarations so new once code works with pthread-win32
[SVN r41398]
2007-11-26 15:44:07 +00:00
Anthony Williams
270e88edd7 Don't compare native_handle_t against 0 --- do appropriate checks in create_native_thread for platforms where pthread_t is not comparable
[SVN r41396]
2007-11-26 13:29:15 +00:00
Anthony Williams
5ded171247 workaround for Borland compiler
[SVN r41395]
2007-11-26 12:17:45 +00:00
Beman Dawes
88f6076f3c Full merge from trunk at revision 41356 of entire boost-root tree.
[SVN r41370]
2007-11-25 18:38:02 +00:00
Beman Dawes
b4d12e08dd Full merge from trunk at revision 41356 of entire boost-root tree.
[SVN r41369]
2007-11-25 18:07:19 +00:00
Anthony Williams
332dd988e4 Integrate TSS with thread data; test to ensure cleanup done for native threads as well as boost::thread-launched threads now runs for pthread API as well as win32 API
[SVN r41320]
2007-11-23 23:09:36 +00:00
Anthony Williams
bce8db41d7 Removed thread::self in favour of allowing interruption through a thread::id; no longer requires DuplicateHandle
[SVN r41311]
2007-11-22 22:01:30 +00:00
Anthony Williams
f6fd70245d changed platform split to allow bjam to track includes and check dependencies
[SVN r41273]
2007-11-21 10:44:22 +00:00
Anthony Williams
4ff0a055d6 added copyright
[SVN r41226]
2007-11-19 14:29:22 +00:00
Anthony Williams
c9140267a5 fixed problems with TSS cleanup when using LoadLibrary and when threads finish after thread_specific_ptr instance has been destroyed
[SVN r41223]
2007-11-19 12:29:14 +00:00
Anthony Williams
72fcee4e5e fixed TSS cleanup on 64-bit Windows
[SVN r41222]
2007-11-19 12:17:31 +00:00
Beman Dawes
9c8e512edd // Add or correct comment identifying Boost library this header is associated with.
[SVN r41173]
2007-11-17 20:13:16 +00:00
Anthony Williams
3c191af34a New implementation of pthread_once based on Mike Burrows' algorithm
[SVN r41160]
2007-11-16 22:51:52 +00:00
Beman Dawes
5e0b2d7370 Get rid of .cvsignore files
[SVN r41107]
2007-11-15 15:20:27 +00:00
Anthony Williams
5994abd453 fixes for pthread implementation
[SVN r41090]
2007-11-14 14:49:58 +00:00
Anthony Williams
67a2d119c0 interrupt and join all threads in a group if an exception is thrown during a test
[SVN r41087]
2007-11-14 12:17:41 +00:00
Anthony Williams
114215088a interrupt and join all threads in a group if an exception is thrown during a test
[SVN r41084]
2007-11-14 11:56:53 +00:00
Anthony Williams
a78e2b793e ignore and join all threads in group on exception
[SVN r41083]
2007-11-14 11:08:09 +00:00
Anthony Williams
519ed3834e Integrated TSS with storage of thread data; cleaned up the heap allocation functions to throw bad_alloc if they run out of memory
[SVN r41056]
2007-11-13 09:27:11 +00:00
Roland Schwarz
22647135fa Added static linking support for mingw compiler on windows.
[SVN r40999]
2007-11-10 19:25:45 +00:00
Roland Schwarz
58c741e9ca Reverted the previous commit, until I find a better solution...
[SVN r40959]
2007-11-09 09:28:29 +00:00
Roland Schwarz
ef9083089e Force static linking for toolsets mingw and boorland.
[SVN r40958]
2007-11-09 08:31:45 +00:00
Anthony Williams
5de1582a0a Added missing licence and copyright
[SVN r40884]
2007-11-07 12:10:17 +00:00
Anthony Williams
39c864e31f use condition so we know when threads have unblocked, to avoid hard-coding a delay
[SVN r40846]
2007-11-06 17:15:50 +00:00
Anthony Williams
320cb63df4 Use BOOST_VERIFY instead of BOOST_ASSERT in many places in order to avoid unused variable warnings
[SVN r40792]
2007-11-05 16:47:25 +00:00
Roland Schwarz
c246222ded Cosmetic change to please gcc.
[SVN r40791]
2007-11-05 16:22:17 +00:00
Roland Schwarz
b7edb2873c Usage requirements added.
[SVN r40790]
2007-11-05 16:12:49 +00:00
Anthony Williams
89f2032c0d Use pthread_equal for comparing pthread_t IDs; use BOOST_VERIFY instead of BOOST_ASSERT in many places in order to avoid unused variable warnings
[SVN r40787]
2007-11-05 14:16:21 +00:00
Anthony Williams
d2f8230093 threadapi is a composite feature again
[SVN r40774]
2007-11-05 10:15:24 +00:00
Roland Schwarz
9f6b5d169a Get rid of "unsused variable" warnings by making use of BOOST_VERIFY.
This changeset is for pthread only.


[SVN r40742]
2007-11-04 17:17:01 +00:00
Anthony Williams
e56708d4aa added missing include
[SVN r40730]
2007-11-03 22:00:12 +00:00
Anthony Williams
304156c20e Fixed typo with interruption change
[SVN r40692]
2007-11-02 18:19:49 +00:00
Anthony Williams
31e1566e1d renamed cancellation to interruption
[SVN r40685]
2007-11-02 14:58:48 +00:00
Anthony Williams
3908637056 rewrite xtime_get in terms of get_system_time to ensure clock consistency, and fix Borland test failures
[SVN r40680]
2007-11-02 11:47:56 +00:00
Anthony Williams
abee301f3d Added changes from David Deakins to enable compilation on Windows CE
[SVN r40679]
2007-11-02 09:17:02 +00:00
Roland Schwarz
9b1d3f8f3c New thread Jamfile. Requirement <threading>multi now correctly handled, even when requested with <threading>single. New project specific feature <threadapi> with values win32 and pthread available.
[SVN r40677]
2007-11-02 08:40:11 +00:00
Anthony Williams
3513eaf701 added timed_join to thread
[SVN r40653]
2007-11-01 18:04:55 +00:00
Anthony Williams
08a840afe4 shared_mutex lock functions are not cancellation points
[SVN r40650]
2007-11-01 17:18:54 +00:00
Anthony Williams
370f5d461c condition wait and sleep are now cancellation points
[SVN r40647]
2007-11-01 17:07:47 +00:00
Anthony Williams
8efc8458e1 Added specialization for reference_wrapper to allow use of boost::ref with boost::thread (again)
[SVN r40609]
2007-10-30 17:16:24 +00:00
Anthony Williams
6485717c52 improved lifetime management of thread data
[SVN r40478]
2007-10-26 10:46:01 +00:00
Anthony Williams
1d5bbd11a8 disable_cancellation and restore_cancellation need to be declared BOOST_THREAD_DECL to work with DLLs with pthread-win32
[SVN r40477]
2007-10-26 09:53:10 +00:00
Anthony Williams
bc403742b5 disable_cancellation and restore_cancellation need to be declared BOOST_THREAD_DECL to work with DLLs
[SVN r40476]
2007-10-26 09:45:46 +00:00
Vladimir Prus
c7f963f57e Make sure every library can be installed by using
bjam stage|install

in libs/<library>/build.


[SVN r40475]
2007-10-26 09:04:25 +00:00
Anthony Williams
afb6684bde added tests for cancellation
[SVN r40472]
2007-10-26 07:33:22 +00:00
Anthony Williams
ee3d772235 thread move constructor is not explicit, so self() compiles for MSVC8 and Intel; thread_exit_callback_node constructor added to remove warnings on MSVC8; thread destructor no longer calls cancel
[SVN r40456]
2007-10-25 07:17:20 +00:00
Anthony Williams
1af08f7085 updated pthreads code to support move and multiple joins
[SVN r40424]
2007-10-24 15:39:14 +00:00
Anthony Williams
ccf23fa273 updated thread move semantics to work with Borland
[SVN r40412]
2007-10-24 12:00:14 +00:00
Anthony Williams
f701defc5f thrd-api is no longer a symmetric feature
[SVN r40407]
2007-10-24 09:36:51 +00:00
Anthony Williams
c606f05bf8 added real default constructor to condition::list_entry
[SVN r40406]
2007-10-24 09:32:29 +00:00
Anthony Williams
a646153615 platform split for pthread and win32 builds so can use pthread-win32 library on Windows with <thrd-api>pthread feature; new C++0x-alike thread class interface on win32.
[SVN r40348]
2007-10-23 08:57:17 +00:00
Markus Schöpflin
60380afe15 Fix compilation.
[SVN r40277]
2007-10-22 07:54:08 +00:00
Anthony Williams
d4b0a977c9 New condition_variable and condition_variable_any as per proposed C++0x interface
[SVN r40191]
2007-10-19 17:40:04 +00:00
Anthony Williams
f86156ad10 more tweaks to remove warnings
[SVN r40189]
2007-10-19 15:31:35 +00:00
Anthony Williams
1836ee854f small changes to reduce warnings; extracted pthread_mutex_scoped_lock to its own file
[SVN r40187]
2007-10-19 14:52:52 +00:00
Anthony Williams
c37cdeec9f removed lock_ops as no longer needed
[SVN r40080]
2007-10-16 11:08:17 +00:00
Anthony Williams
b0b2b17908 added missing include to basic_timed_mutex.hpp
[SVN r40041]
2007-10-15 09:18:32 +00:00
Nicola Musatti
bf46b2ee96 Merge from trunk
[SVN r39987]
2007-10-13 21:25:29 +00:00
Anthony Williams
2918732481 read_write_mutex makes a comeback --- as shared_mutex
[SVN r39891]
2007-10-10 15:33:49 +00:00
Nicola Musatti
bfaeda36c7 Merge from trunk
[SVN r39861]
2007-10-09 20:52:02 +00:00
Anthony Williams
5a4d5ddb9d fixed more has-timed-lock backwards conditions
[SVN r39841]
2007-10-09 14:44:37 +00:00
Anthony Williams
55afcf678d fixed typo in pthread_cond_timedwait and ETIMEDOUT
[SVN r39839]
2007-10-09 14:08:22 +00:00
Anthony Williams
16c7cf9b5e fixed typo in pthread_cond_timedwait and ETIMEDOUT
[SVN r39838]
2007-10-09 12:45:46 +00:00
Anthony Williams
432bd29c1c fixed direction of conditional
[SVN r39836]
2007-10-09 12:23:09 +00:00
Anthony Williams
a87914ef23 added missing move.hpp header
[SVN r39832]
2007-10-09 06:59:14 +00:00
Anthony Williams
041530a953 added backwards-compatibility overload for call_once
[SVN r39785]
2007-10-08 15:44:13 +00:00
Anthony Williams
9d4c55161a New mutex implementations, more akin to C++0x
[SVN r39784]
2007-10-08 15:41:05 +00:00
Anthony Williams
a706d1df00 call_once passes exceptions to caller and leaves flag unset
[SVN r39781]
2007-10-08 09:55:56 +00:00
Anthony Williams
b15b2e666f added extended test for new call_once
[SVN r39780]
2007-10-08 09:48:57 +00:00
Anthony Williams
5d4678364e Use InterlockedCompareExchange when _ReadWriteBarrier not available
[SVN r39777]
2007-10-08 07:18:27 +00:00
Nicola Musatti
ffe0e489d9 Merge from trunk
[SVN r39768]
2007-10-07 20:10:53 +00:00
Beman Dawes
1c0f470032 Starting point for releases
[SVN r39706]
2007-10-05 14:25:06 +00:00
Anthony Williams
9590526430 include config header from right place for pthread/once.hpp
[SVN r39705]
2007-10-05 12:50:29 +00:00
Anthony Williams
1c6dfda83c added platform dispatcher
[SVN r39703]
2007-10-05 12:21:55 +00:00
Anthony Williams
a8be12940e added platform-specific call_once implementations
[SVN r39702]
2007-10-05 12:20:50 +00:00
Anthony Williams
4b5046366b Changed call_once to header-only template that takes arbitrary function objects; this changes parameter order
[SVN r39701]
2007-10-05 12:10:06 +00:00
Anthony Williams
a0fff90c26 Updated in line with RC 1.34
[SVN r39693]
2007-10-05 09:46:00 +00:00
Nicola Musatti
4c165ab173 Branch for CodeGear (Borland) specific fixes
[SVN r39356]
2007-09-17 20:28:43 +00:00
Vladimir Prus
a8daedac5e Revive V1 Jamfile to please asio
[SVN r38837]
2007-08-22 12:40:34 +00:00
Vladimir Prus
5fa26fb3ac Update to V2
[SVN r38531]
2007-08-08 19:47:16 +00:00
Vladimir Prus
ea3e297175 Remove V1 Jamfiles
[SVN r38516]
2007-08-08 19:02:26 +00:00
nobody
92b8789532 This commit was manufactured by cvs2svn to create tag
'Version_1_34_1'.

[SVN r38286]
2007-07-24 19:28:14 +00:00
Thomas Witt
8f61694057 Fix #1039.
[SVN r37948]
2007-06-08 18:48:50 +00:00
Thomas Witt
67f7de5305 Fix #996.
[SVN r37815]
2007-05-29 17:12:59 +00:00
Anthony Williams
6faecefb73 Fix for ticket #906
[SVN r37740]
2007-05-22 15:38:58 +00:00
Rene Rivera
a11bd6ebd9 Put in the build support for using the doxproc, Python based, Doxygen to BoostBook translator.
[SVN r37457]
2007-04-17 04:44:59 +00:00
Roland Schwarz
9889bf50a2 FAQ Entry: Passing parameters during thread creation.
[SVN r36922]
2007-02-11 13:52:28 +00:00
Roland Schwarz
d75fb2deda Applying long outstanding patch.
See:http://thread.gmane.org/gmane.comp.lib.boost.devel/118863/focus=118912


[SVN r36920]
2007-02-11 12:00:38 +00:00
Roland Schwarz
6355a5b28d Changes for WINCE
[SVN r36484]
2006-12-22 09:40:17 +00:00
Roland Schwarz
595bbee41e Converted back to CHECK since warnings not showing up in regression tables.
[SVN r36386]
2006-12-14 17:49:21 +00:00
Roland Schwarz
cb3f3a1f64 Fixed the missing tss_nul file for testing.
[SVN r36331]
2006-12-11 19:22:40 +00:00
Vladimir Prus
0e44838905 Allow building of shared versions of some Boost.Test libraries.
Adjust tests to use always use static linking to Boost.Test, since
linking to the shared version requires test changes.

Patch from Juergen Hunold.


[SVN r35989]
2006-11-10 19:09:56 +00:00
Roland Schwarz
64cd268fc7 Get rid of dll import warnings for nocopyable classes
[SVN r35796]
2006-10-30 19:27:51 +00:00
Roland Schwarz
f048dd81f2 Merged changes from RC_1_34_0
[SVN r35616]
2006-10-15 10:27:28 +00:00
Roland Schwarz
5746f2214c cosmetics
[SVN r35615]
2006-10-15 10:10:47 +00:00
Roland Schwarz
099af669d4 Made fail of cleanup test for native API a warning.
[SVN r35614]
2006-10-15 10:03:35 +00:00
Roland Schwarz
79cac706a7 Unified spelling of thread library in documentation. (singular)
[SVN r35590]
2006-10-13 16:48:50 +00:00
Roland Schwarz
df229074ac Made size() a constant member function.
[SVN r35589]
2006-10-13 16:41:51 +00:00
Anthony Williams
191c27e856 Added missing #include
[SVN r35577]
2006-10-12 16:30:27 +00:00
Anthony Williams
e5ee01b43c Remove spurious #endif
[SVN r35576]
2006-10-12 14:52:43 +00:00
Anthony Williams
c46b040f6f Applied some of David Deakins' patches for WinCE
[SVN r35532]
2006-10-10 07:34:48 +00:00
Roland Schwarz
72e4794f5b Removed the "intentional memory leak" of the TSS implementation
[SVN r35426]
2006-09-29 19:24:19 +00:00
Anthony Williams
c30b65a0ea Added #ifdef _WIN64 around a direct call to InterlockedCompareExchange rather than the existing call through ice_wrapper. The
platform SDK library for Win64 doesn't include a library version of InterlockedCompareExchange which the ice_wrapper code requires.


[SVN r35340]
2006-09-26 16:31:41 +00:00
Hartmut Kaiser
1cb08ff60c Changed Boost.Thread to use the Boost license.
[SVN r35115]
2006-09-14 23:02:29 +00:00
Anthony Williams
d3d7fd9317 Added call to TlsFree
[SVN r34843]
2006-08-07 16:34:54 +00:00
Peter Dimov
acf0f97663 Simplification, avoids a false leak report
[SVN r34706]
2006-07-24 19:00:30 +00:00
Peter Dimov
34bd87cea7 Moved the on_thread_exit call to a destructor
[SVN r34469]
2006-07-06 19:47:12 +00:00
Peter Dimov
228f11262e Removed the infamous catch(...)
[SVN r34467]
2006-07-06 13:45:13 +00:00
Anthony Williams
9683e0f1cc Added patch from http://lists.boost.org/Archives/boost/2005/05/86395.php to fix bug
https://sourceforge.net/tracker/index.php?func=detail&aid=1424965&group_id=7586&atid=107586


[SVN r33802]
2006-04-25 10:06:38 +00:00
Vladimir Prus
674ae6d571 Remove declaration of 'pthread'. It was hack
[SVN r33596]
2006-04-07 14:00:27 +00:00
Vladimir Prus
690d44e2e6 Setup usage requirements for dllimport/dllexport.
[SVN r33431]
2006-03-22 08:49:42 +00:00
106 changed files with 17355 additions and 3133 deletions

View File

@@ -1,39 +1,208 @@
# (C) Copyright Vladimir Prus, David Abrahams, Michael Stevens, Hartmut Kaiser,
# William E Kempf 2002-2006
# Use, modification and distribution are subject to the
# Boost Software License, Version 1.0. (See accompanying file
# LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
# $Id$
# Copyright 2006-2007 Roland Schwarz.
# 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)
#########################################################################
# The boost threading library can be built on top of different API's
# Currently this is the win32 API and the pthreads API.
# Pthread is native on unix variants.
# To get pthread on windows you need the pthread win32 library
# http://sourceware.org/pthreads-win32 which is available under LGPL.
#
# You need to provide the include path and lib path in the variables
# PTW32_INCLUDE and PTW32_LIB respectively. You can specify these
# paths in site-config.jam, user-config.jam or in the environment.
# A new feature is provided to request a specific API:
# <threadapi>win32 and <threadapi)pthread.
#
# The naming of the resulting libraries is mostly the same for the
# variant native to the build platform, i.e.
# boost_thread and the boost specific tagging.
# For the library variant that is not native on the build platform
# an additional tag is applied:
# boost_thread_pthread for the pthread variant on windows, and
# boost_thread_win32 for the win32 variant (likely when built on cygwin).
#
# To request the pthread variant on windows, from boost root you would
# say e.g:
# bjam msvc-8.0 --with-thread install threadapi=pthread
#########################################################################
import os ;
import feature ;
import indirect ;
import path ;
project boost/thread
: source-location ../src
: requirements <link>shared:<define>BOOST_THREAD_BUILD_DLL=1 <threading>multi
: source-location ../src
: requirements <threading>multi
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
<link>shared:<define>BOOST_THREAD_BUILD_DLL=1
-<tag>@$(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
<tag>@$(__name__).tag
: default-build <threading>multi
;
CPP_SOURCES =
barrier
condition
exceptions
mutex
once
recursive_mutex
# read_write_mutex
thread
tss_hooks
tss_dll
tss_pe
tss
xtime
local rule default_threadapi ( )
{
local api = pthread ;
if [ os.name ] = "NT" { api = win32 ; }
return $(api) ;
}
feature.feature threadapi : pthread win32 : propagated ;
feature.set-default threadapi : [ default_threadapi ] ;
rule tag ( name : type ? : property-set )
{
local result = $(name) ;
if $(type) in STATIC_LIB SHARED_LIB IMPORT_LIB
{
local api = [ $(property-set).get <threadapi> ] ;
# non native api gets additional tag
if $(api) != [ default_threadapi ] {
result = $(result)_$(api) ;
}
}
# forward to the boost tagging rule
return [ indirect.call $(BOOST_JAMROOT_MODULE)%$(BOOST_JAMROOT_MODULE).tag
$(result) : $(type) : $(property-set) ] ;
}
rule win32_pthread_paths ( properties * )
{
local result ;
local PTW32_INCLUDE ;
local PTW32_LIB ;
PTW32_INCLUDE = [ modules.peek : PTW32_INCLUDE ] ;
PTW32_LIB = [ modules.peek : PTW32_LIB ] ;
PTW32_INCLUDE ?= [ modules.peek user-config : PTW32_INCLUDE ] ;
PTW32_LIB ?= [ modules.peek user-config : PTW32_LIB ] ;
PTW32_INCLUDE ?= [ modules.peek site-config : PTW32_INCLUDE ] ;
PTW32_LIB ?= [ modules.peek site-config : PTW32_LIB ] ;
if ! ( $(PTW32_INCLUDE) && $(PTW32_LIB) )
{
if ! $(.notified)
{
echo "************************************************************" ;
echo "Trying to build Boost.Thread with pthread support." ;
echo "If you need pthread you should specify the paths." ;
echo "You can specify them in site-config.jam, user-config.jam" ;
echo "or in the environment." ;
echo "For example:" ;
echo "PTW32_INCLUDE=C:\\Program Files\\ptw32\\Pre-built2\\include" ;
echo "PTW32_LIB=C:\\Program Files\\ptw32\\Pre-built2\\lib" ;
echo "************************************************************" ;
.notified = true ;
}
}
else
{
local include_path = [ path.make $(PTW32_INCLUDE) ] ;
local lib_path = [ path.make $(PTW32_LIB) ] ;
local libname = pthread ;
if <toolset>msvc in $(properties)
{
libname = $(libname)VC2.lib ;
}
if <toolset>gcc in $(properties)
{
libname = lib$(libname)GC2.a ;
}
lib_path = [ path.glob $(lib_path) : $(libname) ] ;
if ! $(lib_path)
{
if ! $(.notified)
{
echo "************************************************************" ;
echo "Trying to build Boost.Thread with pthread support." ;
echo "But the library" $(libname) "could not be found in path" ;
echo $(PTW32_LIB) ;
echo "************************************************************" ;
.notified = true ;
}
}
else
{
result += <include>$(include_path) ;
result += <library>$(lib_path) ;
}
}
return $(result) ;
}
rule usage-requirements ( properties * )
{
local result ;
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
if <target-os>windows in $(properties)
{
result += [ win32_pthread_paths $(properties) ] ;
# TODO: What is for static linking? Is the <library> also needed
# in that case?
}
}
return $(result) ;
}
rule requirements ( properties * )
{
local result ;
if <threadapi>pthread in $(properties)
{
result += <define>BOOST_THREAD_POSIX ;
if <target-os>windows in $(properties)
{
local paths = [ win32_pthread_paths $(properties) ] ;
if $(paths)
{
result += $(paths) ;
}
else
{
result = <build>no ;
}
}
}
return $(result) ;
}
alias thread_sources
: ## win32 sources ##
win32/thread.cpp
win32/exceptions.cpp
win32/tss_dll.cpp
win32/tss_pe.cpp
: ## requirements ##
<threadapi>win32
;
alias thread_sources
: ## pthread sources ##
pthread/thread.cpp
pthread/exceptions.cpp
pthread/once.cpp
: ## requirements ##
<threadapi>pthread
;
explicit thread_sources ;
lib boost_thread
: $(CPP_SOURCES).cpp
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
: # default build
: <link>shared:<define>BOOST_THREAD_BUILD_DLL=1
<link>static:<define>BOOST_THREAD_BUILD_LIB=1
;
: thread_sources
: <conditional>@requirements
:
: <link>shared:<define>BOOST_THREAD_USE_DLL=1
<link>static:<define>BOOST_THREAD_USE_LIB=1
<conditional>@usage-requirements
;

View File

@@ -1,11 +1,55 @@
# Copyright (C) 2001-2003
# William E. Kempf
# (C) Copyright 2008 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)
import toolset ;
toolset.using doxygen ;
path-constant boost-images : ../../../doc/src/images ;
boostbook thread : thread.xml ;
xml thread : thread.qbk ;
boostbook standalone
:
thread
:
# HTML options first:
# Use graphics not text for navigation:
<xsl:param>navig.graphics=1
# How far down we chunk nested sections, basically all of them:
<xsl:param>chunk.section.depth=3
# Don't put the first section on the same page as the TOC:
<xsl:param>chunk.first.sections=1
# How far down sections get TOC's
<xsl:param>toc.section.depth=10
# Max depth in each TOC:
<xsl:param>toc.max.depth=3
# How far down we go with TOC's
<xsl:param>generate.section.toc.level=10
# Path for links to Boost:
<xsl:param>boost.root=../../../..
# Path for libraries index:
<xsl:param>boost.libraries=../../../../libs/libraries.htm
# Use the main Boost stylesheet:
<xsl:param>html.stylesheet=../../../../doc/html/boostbook.css
# PDF Options:
# TOC Generation: this is needed for FOP-0.9 and later:
#<xsl:param>fop1.extensions=1
# Or enable this if you're using XEP:
<xsl:param>xep.extensions=1
# TOC generation: this is needed for FOP 0.2, but must not be set to zero for FOP-0.9!
<xsl:param>fop.extensions=0
# No indent on body text:
<xsl:param>body.start.indent=0pt
# Margin size:
<xsl:param>page.margin.inner=0.5in
# Margin size:
<xsl:param>page.margin.outer=0.5in
# Yes, we want graphics for admonishments:
<xsl:param>admon.graphics=1
# Set this one for PDF generation *only*:
# default pnd graphics are awful in PDF form,
# better use SVG's instead:
<format>pdf:<xsl:param>admon.graphics.extension=".svg"
<format>pdf:<xsl:param>admon.graphics.path=$(boost-images)/
;

23
doc/acknowledgements.qbk Normal file
View File

@@ -0,0 +1,23 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:acknowledgements Acknowledgments]
The original implementation of __boost_thread__ was written by William Kempf, with contributions from numerous others. This new
version initially grew out of an attempt to rewrite __boost_thread__ to William Kempf's design with fresh code that could be
released under the Boost Software License. However, as the C++ Standards committee have been actively discussing standardizing a
thread library for C++, this library has evolved to reflect the proposals, whilst retaining as much backwards-compatibility as
possible.
Particular thanks must be given to Roland Schwarz, who contributed a lot of time and code to the original __boost_thread__ library,
and who has been actively involved with the rewrite. The scheme for dividing the platform-specific implementations into separate
directories was devised by Roland, and his input has contributed greatly to improving the quality of the current implementation.
Thanks also must go to Peter Dimov, Howard Hinnant, Alexander Terekhov, Chris Thomasson and others for their comments on the
implementation details of the code.
[endsect]

72
doc/barrier.qbk Normal file
View File

@@ -0,0 +1,72 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:barriers Barriers]
A barrier is a simple concept. Also known as a ['rendezvous], it is a synchronization point between multiple threads. The barrier is
configured for a particular number of threads (`n`), and as threads reach the barrier they must wait until all `n` threads have
arrived. Once the `n`-th thread has reached the barrier, all the waiting threads can proceed, and the barrier is reset.
[section:barrier Class `barrier`]
#include <boost/thread/barrier.hpp>
class barrier
{
public:
barrier(unsigned int count);
~barrier();
bool wait();
};
Instances of __barrier__ are not copyable or movable.
[heading Constructor]
barrier(unsigned int count);
[variablelist
[[Effects:] [Construct a barrier for `count` threads.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
]
[heading Destructor]
~barrier();
[variablelist
[[Precondition:] [No threads are waiting on `*this`.]]
[[Effects:] [Destroys `*this`.]]
[[Throws:] [Nothing.]]
]
[heading Member function `wait`]
bool wait();
[variablelist
[[Effects:] [Block until `count` threads have called `wait` on `*this`. When the `count`-th thread calls `wait`, all waiting threads
are unblocked, and the barrier is reset. ]]
[[Returns:] [`true` for exactly one thread from each batch of waiting threads, `false` otherwise.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
]
[endsect]
[endsect]

83
doc/changes.qbk Normal file
View File

@@ -0,0 +1,83 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:changes Changes since boost 1.35]
The 1.36.0 release of Boost includes a few new features in the thread library:
* New generic __lock_multiple_ref__ and __try_lock_multiple_ref__ functions for locking multiple mutexes at once.
* Rvalue reference support for move semantics where the compilers supports it.
* A few bugs fixed and missing functions added (including the serious win32 condition variable bug).
* `scoped_try_lock` types are now backwards-compatible with Boost 1.34.0 and previous releases.
* Support for passing function arguments to the thread function by supplying additional arguments to the __thread__ constructor.
* Backwards-compatibility overloads added for `timed_lock` and `timed_wait` functions to allow use of `xtime` for timeouts.
[heading Changes since boost 1.34]
Almost every line of code in __boost_thread__ has been changed since the 1.34 release of boost. However, most of the interface
changes have been extensions, so the new code is largely backwards-compatible with the old code. The new features and breaking
changes are described below.
[heading New Features]
* Instances of __thread__ and of the various lock types are now movable.
* Threads can be interrupted at __interruption_points__.
* Condition variables can now be used with any type that implements the __lockable_concept__, through the use of
`boost::condition_variable_any` (`boost::condition` is a `typedef` to `boost::condition_variable_any`, provided for backwards
compatibility). `boost::condition_variable` is provided as an optimization, and will only work with
`boost::unique_lock<boost::mutex>` (`boost::mutex::scoped_lock`).
* Thread IDs are separated from __thread__, so a thread can obtain it's own ID (using `boost::this_thread::get_id()`), and IDs can
be used as keys in associative containers, as they have the full set of comparison operators.
* Timeouts are now implemented using the Boost DateTime library, through a typedef `boost::system_time` for absolute timeouts, and
with support for relative timeouts in many cases. `boost::xtime` is supported for backwards compatibility only.
* Locks are implemented as publicly accessible templates `boost::lock_guard`, `boost::unique_lock`, `boost::shared_lock`, and
`boost::upgrade_lock`, which are templated on the type of the mutex. The __lockable_concept__ has been extended to include publicly
available __lock_ref__ and __unlock_ref__ member functions, which are used by the lock types.
[heading Breaking Changes]
The list below should cover all changes to the public interface which break backwards compatibility.
* __try_mutex__ has been removed, and the functionality subsumed into __mutex__. __try_mutex__ is left as a `typedef`,
but is no longer a separate class.
* __recursive_try_mutex__ has been removed, and the functionality subsumed into
__recursive_mutex__. __recursive_try_mutex__ is left as a `typedef`, but is no longer a separate class.
* `boost::detail::thread::lock_ops` has been removed. Code that relies on the `lock_ops` implementation detail will no longer work,
as this has been removed, as it is no longer necessary now that mutex types now have public __lock_ref__ and __unlock_ref__ member
functions.
* `scoped_lock` constructors with a second parameter of type `bool` are no longer provided. With previous boost releases,
``boost::mutex::scoped_lock some_lock(some_mutex,false);`` could be used to create a lock object that was associated with a mutex,
but did not lock it on construction. This facility has now been replaced with the constructor that takes a
`boost::defer_lock_type` as the second parameter: ``boost::mutex::scoped_lock some_lock(some_mutex,boost::defer_lock);``
* The `locked()` member function of the `scoped_lock` types has been renamed to __owns_lock_ref__.
* You can no longer obtain a __thread__ instance representing the current thread: a default-constructed __thread__ object is not
associated with any thread. The only use for such a thread object was to support the comparison operators: this functionality has
been moved to __thread_id__.
* The broken `boost::read_write_mutex` has been replaced with __shared_mutex__.
* __mutex__ is now never recursive. For Boost releases prior to 1.35 __mutex__ was recursive on Windows and not on POSIX platforms.
* When using a __recursive_mutex__ with a call to [cond_any_wait_link `boost::condition_variable_any::wait()`], the mutex is only
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
[endsect]

513
doc/condition_variables.qbk Normal file
View File

@@ -0,0 +1,513 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:condvar_ref Condition Variables]
[heading Synopsis]
The classes `condition_variable` and `condition_variable_any` provide a
mechanism for one thread to wait for notification from another thread that a
particular condition has become true. The general usage pattern is that one
thread locks a mutex and then calls `wait` on an instance of
`condition_variable` or `condition_variable_any`. When the thread is woken from
the wait, then it checks to see if the appropriate condition is now true, and
continues if so. If the condition is not true, then the thread then calls `wait`
again to resume waiting. In the simplest case, this condition is just a boolean
variable:
boost::condition_variable cond;
boost::mutex mut;
bool data_ready;
void process_data();
void wait_for_data_to_process()
{
boost::unique_lock<boost::mutex> lock(mut);
while(!data_ready)
{
cond.wait(lock);
}
process_data();
}
Notice that the `lock` is passed to `wait`: `wait` will atomically add the
thread to the set of threads waiting on the condition variable, and unlock the
mutex. When the thread is woken, the mutex will be locked again before the call
to `wait` returns. This allows other threads to acquire the mutex in order to
update the shared data, and ensures that the data associated with the condition
is correctly synchronized.
In the mean time, another thread sets the condition to `true`, and then calls
either `notify_one` or `notify_all` on the condition variable to wake one
waiting thread or all the waiting threads respectively.
void retrieve_data();
void prepare_data();
void prepare_data_for_processing()
{
retrieve_data();
prepare_data();
{
boost::lock_guard<boost::mutex> lock(mut);
data_ready=true;
}
cond.notify_one();
}
Note that the same mutex is locked before the shared data is updated, but that
the mutex does not have to be locked across the call to `notify_one`.
This example uses an object of type `condition_variable`, but would work just as
well with an object of type `condition_variable_any`: `condition_variable_any`
is more general, and will work with any kind of lock or mutex, whereas
`condition_variable` requires that the lock passed to `wait` is an instance of
`boost::unique_lock<boost::mutex>`. This enables `condition_variable` to make
optimizations in some cases, based on the knowledge of the mutex type;
`condition_variable_any` typically has a more complex implementation than
`condition_variable`.
[section:condition_variable Class `condition_variable`]
#include <boost/thread/condition_variable.hpp>
namespace boost
{
class condition_variable
{
public:
condition_variable();
~condition_variable();
void notify_one();
void notify_all();
void wait(boost::unique_lock<boost::mutex>& lock);
template<typename predicate_type>
void wait(boost::unique_lock<boost::mutex>& lock,predicate_type predicate);
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time);
template<typename duration_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time);
template<typename predicate_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time,predicate_type predicate);
template<typename duration_type,typename predicate_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time,predicate_type predicate);
// backwards compatibility
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time);
template<typename predicate_type>
bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::xtime const& abs_time,predicate_type predicate);
};
}
[section:constructor `condition_variable()`]
[variablelist
[[Effects:] [Constructs an object of class `condition_variable`.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
]
[endsect]
[section:destructor `~condition_variable()`]
[variablelist
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
`notify_one` or `notify_all` (though the respective calls to `wait` or
`timed_wait` need not have returned).]]
[[Effects:] [Destroys the object.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:notify_one `void notify_one()`]
[variablelist
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
to `wait` or `timed_wait`, unblocks one of those threads.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:notify_all `void notify_all()`]
[variablelist
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
to `wait` or `timed_wait`, unblocks all of those threads.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:wait `void wait(boost::unique_lock<boost::mutex>& lock)`]
[variablelist
[[Precondition:] [`lock` is locked by the current thread, and either no other
thread is currently waiting on `*this`, or the execution of the `mutex()` member
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
in all the threads currently waiting on `*this` would return the same value as
`lock->mutex()` for this call to `wait`.]]
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
reason), the lock is reacquired by invoking `lock.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
function exits with an exception.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
[[Throws:] [__thread_resource_error__ if an error
occurs. __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
]
[endsect]
[section:wait_predicate `template<typename predicate_type> void wait(boost::unique_lock<boost::mutex>& lock, predicate_type pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
wait(lock);
}
``]]
]
[endsect]
[section:timed_wait `bool timed_wait(boost::unique_lock<boost::mutex>& lock,boost::system_time const& abs_time)`]
[variablelist
[[Precondition:] [`lock` is locked by the current thread, and either no other
thread is currently waiting on `*this`, or the execution of the `mutex()` member
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
in all the threads currently waiting on `*this` would return the same value as
`lock->mutex()` for this call to `wait`.]]
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
would be equal to or later than the specified `abs_time`, or spuriously. When
the thread is unblocked (for whatever reason), the lock is reacquired by
invoking `lock.lock()` before the call to `wait` returns. The lock is also
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
[[Returns:] [`false` if the call is returning because the time specified by
`abs_time` was reached, `true` otherwise.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
[[Throws:] [__thread_resource_error__ if an error
occurs. __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
]
[endsect]
[section:timed_wait_rel `template<typename duration_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock,duration_type const& rel_time)`]
[variablelist
[[Precondition:] [`lock` is locked by the current thread, and either no other
thread is currently waiting on `*this`, or the execution of the `mutex()` member
function on the `lock` objects supplied in the calls to `wait` or `timed_wait`
in all the threads currently waiting on `*this` would return the same value as
`lock->mutex()` for this call to `wait`.]]
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, after the period of time indicated by the `rel_time`
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
reason), the lock is reacquired by invoking `lock.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
function exits with an exception.]]
[[Returns:] [`false` if the call is returning because the time period specified
by `rel_time` has elapsed, `true` otherwise.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
[[Throws:] [__thread_resource_error__ if an error
occurs. __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
]
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
[endsect]
[section:timed_wait_predicate `template<typename predicate_type> bool timed_wait(boost::unique_lock<boost::mutex>& lock, boost::system_time const& abs_time, predicate_type pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
if(!timed_wait(lock,abs_time))
{
return pred();
}
}
return true;
``]]
]
[endsect]
[endsect]
[section:condition_variable_any Class `condition_variable_any`]
#include <boost/thread/condition_variable.hpp>
namespace boost
{
class condition_variable_any
{
public:
condition_variable_any();
~condition_variable_any();
void notify_one();
void notify_all();
template<typename lock_type>
void wait(lock_type& lock);
template<typename lock_type,typename predicate_type>
void wait(lock_type& lock,predicate_type predicate);
template<typename lock_type>
bool timed_wait(lock_type& lock,boost::system_time const& abs_time);
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& lock,duration_type const& rel_time);
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& lock,boost::system_time const& abs_time,predicate_type predicate);
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& lock,duration_type const& rel_time,predicate_type predicate);
// backwards compatibility
template<typename lock_type>
bool timed_wait(lock_type>& lock,boost::xtime const& abs_time);
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& lock,boost::xtime const& abs_time,predicate_type predicate);
};
}
[section:constructor `condition_variable_any()`]
[variablelist
[[Effects:] [Constructs an object of class `condition_variable_any`.]]
[[Throws:] [__thread_resource_error__ if an error occurs.]]
]
[endsect]
[section:destructor `~condition_variable_any()`]
[variablelist
[[Precondition:] [All threads waiting on `*this` have been notified by a call to
`notify_one` or `notify_all` (though the respective calls to `wait` or
`timed_wait` need not have returned).]]
[[Effects:] [Destroys the object.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:notify_one `void notify_one()`]
[variablelist
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
to `wait` or `timed_wait`, unblocks one of those threads.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:notify_all `void notify_all()`]
[variablelist
[[Effects:] [If any threads are currently __blocked__ waiting on `*this` in a call
to `wait` or `timed_wait`, unblocks all of those threads.]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:wait `template<typename lock_type> void wait(lock_type& lock)`]
[variablelist
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, or spuriously. When the thread is unblocked (for whatever
reason), the lock is reacquired by invoking `lock.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
function exits with an exception.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
[[Throws:] [__thread_resource_error__ if an error
occurs. __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
]
[endsect]
[section:wait_predicate `template<typename lock_type,typename predicate_type> void wait(lock_type& lock, predicate_type pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
wait(lock);
}
``]]
]
[endsect]
[section:timed_wait `template<typename lock_type> bool timed_wait(lock_type& lock,boost::system_time const& abs_time)`]
[variablelist
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, when the time as reported by `boost::get_system_time()`
would be equal to or later than the specified `abs_time`, or spuriously. When
the thread is unblocked (for whatever reason), the lock is reacquired by
invoking `lock.lock()` before the call to `wait` returns. The lock is also
reacquired by invoking `lock.lock()` if the function exits with an exception.]]
[[Returns:] [`false` if the call is returning because the time specified by
`abs_time` was reached, `true` otherwise.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
[[Throws:] [__thread_resource_error__ if an error
occurs. __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
]
[endsect]
[section:timed_wait_rel `template<typename lock_type,typename duration_type> bool timed_wait(lock_type& lock,duration_type const& rel_time)`]
[variablelist
[[Effects:] [Atomically call `lock.unlock()` and blocks the current thread. The
thread will unblock when notified by a call to `this->notify_one()` or
`this->notify_all()`, after the period of time indicated by the `rel_time`
argument has elapsed, or spuriously. When the thread is unblocked (for whatever
reason), the lock is reacquired by invoking `lock.lock()` before the call to
`wait` returns. The lock is also reacquired by invoking `lock.lock()` if the
function exits with an exception.]]
[[Returns:] [`false` if the call is returning because the time period specified
by `rel_time` has elapsed, `true` otherwise.]]
[[Postcondition:] [`lock` is locked by the current thread.]]
[[Throws:] [__thread_resource_error__ if an error
occurs. __thread_interrupted__ if the wait was interrupted by a call to
__interrupt__ on the __thread__ object associated with the current thread of execution.]]
]
[note The duration overload of timed_wait is difficult to use correctly. The overload taking a predicate should be preferred in most cases.]
[endsect]
[section:timed_wait_predicate `template<typename lock_type,typename predicate_type> bool timed_wait(lock_type& lock, boost::system_time const& abs_time, predicate_type pred)`]
[variablelist
[[Effects:] [As-if ``
while(!pred())
{
if(!timed_wait(lock,abs_time))
{
return pred();
}
}
return true;
``]]
]
[endsect]
[endsect]
[section:condition Typedef `condition`]
#include <boost/thread/condition.hpp>
typedef condition_variable_any condition;
The typedef `condition` is provided for backwards compatibility with previous boost releases.
[endsect]
[endsect]

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 Beman Dawes, William E. Kempf.
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<html>
<head>

1119
doc/mutex_concepts.qbk Normal file

File diff suppressed because it is too large Load Diff

224
doc/mutexes.qbk Normal file
View File

@@ -0,0 +1,224 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:mutex_types Mutex Types]
[section:mutex Class `mutex`]
#include <boost/thread/mutex.hpp>
class mutex:
boost::noncopyable
{
public:
mutex();
~mutex();
void lock();
bool try_lock();
void unlock();
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
typedef unique_lock<mutex> scoped_lock;
typedef unspecified-type scoped_try_lock;
};
__mutex__ implements the __lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the lock on a given
instance of __mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and __unlock_ref__ shall be permitted.
[section:nativehandle Member function `native_handle()`]
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
[variablelist
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:try_mutex Typedef `try_mutex`]
#include <boost/thread/mutex.hpp>
typedef mutex try_mutex;
__try_mutex__ is a `typedef` to __mutex__, provided for backwards compatibility with previous releases of boost.
[endsect]
[section:timed_mutex Class `timed_mutex`]
#include <boost/thread/mutex.hpp>
class timed_mutex:
boost::noncopyable
{
public:
timed_mutex();
~timed_mutex();
void lock();
void unlock();
bool try_lock();
bool timed_lock(system_time const & abs_time);
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef unspecified-type scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
__timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership mutex. At most one thread can own the
lock on a given instance of __timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__,
__timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted.
[section:nativehandle Member function `native_handle()`]
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
[variablelist
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:recursive_mutex Class `recursive_mutex`]
#include <boost/thread/recursive_mutex.hpp>
class recursive_mutex:
boost::noncopyable
{
public:
recursive_mutex();
~recursive_mutex();
void lock();
bool try_lock();
void unlock();
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
typedef unique_lock<recursive_mutex> scoped_lock;
typedef unspecified-type scoped_try_lock;
};
__recursive_mutex__ implements the __lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one thread can
own the lock on a given instance of __recursive_mutex__ at any time. Multiple concurrent calls to __lock_ref__, __try_lock_ref__ and
__unlock_ref__ shall be permitted. A thread that already has exclusive ownership of a given __recursive_mutex__ instance can call
__lock_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be called once for
each level of ownership acquired by a single thread before ownership can be acquired by another thread.
[section:nativehandle Member function `native_handle()`]
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
[variablelist
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[section:recursive_try_mutex Typedef `recursive_try_mutex`]
#include <boost/thread/recursive_mutex.hpp>
typedef recursive_mutex recursive_try_mutex;
__recursive_try_mutex__ is a `typedef` to __recursive_mutex__, provided for backwards compatibility with previous releases of boost.
[endsect]
[section:recursive_timed_mutex Class `recursive_timed_mutex`]
#include <boost/thread/recursive_mutex.hpp>
class recursive_timed_mutex:
boost::noncopyable
{
public:
recursive_timed_mutex();
~recursive_timed_mutex();
void lock();
bool try_lock();
void unlock();
bool timed_lock(system_time const & abs_time);
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time);
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
typedef unique_lock<recursive_timed_mutex> scoped_lock;
typedef unspecified-type scoped_try_lock;
typedef scoped_lock scoped_timed_lock;
};
__recursive_timed_mutex__ implements the __timed_lockable_concept__ to provide an exclusive-ownership recursive mutex. At most one
thread can own the lock on a given instance of __recursive_timed_mutex__ at any time. Multiple concurrent calls to __lock_ref__,
__try_lock_ref__, __timed_lock_ref__, __timed_lock_duration_ref__ and __unlock_ref__ shall be permitted. A thread that already has
exclusive ownership of a given __recursive_timed_mutex__ instance can call __lock_ref__, __timed_lock_ref__,
__timed_lock_duration_ref__ or __try_lock_ref__ to acquire an additional level of ownership of the mutex. __unlock_ref__ must be
called once for each level of ownership acquired by a single thread before ownership can be acquired by another thread.
[section:nativehandle Member function `native_handle()`]
typedef platform-specific-type native_handle_type;
native_handle_type native_handle();
[variablelist
[[Effects:] [Returns an instance of `native_handle_type` that can be used with platform-specific APIs to manipulate the underlying
implementation. If no such instance exists, `native_handle()` and `native_handle_type` are not present.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[include shared_mutex_ref.qbk]
[endsect]

View File

@@ -65,25 +65,23 @@ void init()
void thread_proc()
{
boost::call_once(&amp;init, once);
boost::call_once(once, &amp;init);
}</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>
<parameter name="func">
<paramtype>Function func</paramtype>
</parameter>
<effects>As if (in an atomic fashion):
<code>if (flag == BOOST_ONCE_INIT) func();</code></effects>
<code>if (flag == BOOST_ONCE_INIT) func();</code>. If <code>func()</code> throws an exception, it shall be as if this
thread never invoked <code>call_once</code></effects>
<postconditions><code>flag != BOOST_ONCE_INIT</code>
<postconditions><code>flag != BOOST_ONCE_INIT</code> unless <code>func()</code> throws an exception.
</postconditions>
</function>
</namespace>

56
doc/once.qbk Normal file
View File

@@ -0,0 +1,56 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:once One-time Initialization]
`boost::call_once` provides a mechanism for ensuring that an initialization routine is run exactly once without data races or deadlocks.
[section:once_flag Typedef `once_flag`]
#include <boost/thread/once.hpp>
typedef platform-specific-type once_flag;
#define BOOST_ONCE_INIT platform-specific-initializer
Objects of type `boost::once_flag` shall be initialized with `BOOST_ONCE_INIT`:
boost::once_flag f=BOOST_ONCE_INIT;
[endsect]
[section:call_once Non-member function `call_once`]
#include <boost/thread/once.hpp>
template<typename Callable>
void call_once(once_flag& flag,Callable func);
[variablelist
[[Requires:] [`Callable` is `CopyConstructible`. Copying `func` shall have no side effects, and the effect of calling the copy shall
be equivalent to calling the original. ]]
[[Effects:] [Calls to `call_once` on the same `once_flag` object are serialized. If there has been no prior effective `call_once` on
the same `once_flag` object, the argument `func` (or a copy thereof) is called as-if by invoking `func()`, and the invocation of
`call_once` is effective if and only if `func()` returns without exception. If an exception is thrown, the exception is
propagated to the caller. If there has been a prior effective `call_once` on the same `once_flag` object, the `call_once` returns
without invoking `func`. ]]
[[Synchronization:] [The completion of an effective `call_once` invocation on a `once_flag` object, synchronizes with
all subsequent `call_once` invocations on the same `once_flag` object. ]]
[[Throws:] [`thread_resource_error` when the effects cannot be achieved. or any exception propagated from `func`.]]
]
void call_once(void (*func)(),once_flag& flag);
This second overload is provided for backwards compatibility. The effects of `call_once(func,flag)` shall be the same as those of
`call_once(flag,func)`.
[endsect]
[endsect]

30
doc/overview.qbk Normal file
View File

@@ -0,0 +1,30 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:overview Overview]
__boost_thread__ enables the use of multiple threads of execution with shared data in portable C++ code. It provides classes and
functions for managing the threads themselves, along with others for synchronizing data between the threads or providing separate
copies of data specific to individual threads.
The __boost_thread__ library was originally written and designed by William E. Kempf. This version is a major rewrite designed to
closely follow the proposals presented to the C++ Standards Committee, in particular
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2497.html N2497],
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2320.html N2320],
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2184.html N2184],
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2139.html N2139], and
[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2094.html N2094]
In order to use the classes and functions described here, you can
either include the specific headers specified by the descriptions of
each class or function, or include the master thread library header:
#include <boost/thread.hpp>
which includes all the other headers in turn.
[endsect]

View File

@@ -37,6 +37,16 @@
<purpose>
<para>The <classname>read_write_mutex</classname> class is a model of the
<link linkend="thread.concepts.ReadWriteMutex">ReadWriteMutex</link> concept.</para>
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
some serious problems. So it was decided not to put this implementation into
release grade code. Also discussions on the mailing list led to the
conclusion that the current concepts need to be rethought. In particular
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
Inter-Class Scheduling Policies</link> are deemed unnecessary.
There seems to be common belief that a fair scheme suffices.
The following documentation has been retained however, to give
readers of this document the opportunity to study the original design.
</note>
</purpose>
<description>
@@ -160,6 +170,16 @@
<purpose>
<para>The <classname>try_read_write_mutex</classname> class is a model of the
<link linkend="thread.concepts.TryReadWriteMutex">TryReadWriteMutex</link> concept.</para>
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
some serious problems. So it was decided not to put this implementation into
release grade code. Also discussions on the mailing list led to the
conclusion that the current concepts need to be rethought. In particular
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
Inter-Class Scheduling Policies</link> are deemed unnecessary.
There seems to be common belief that a fair scheme suffices.
The following documentation has been retained however, to give
readers of this document the opportunity to study the original design.
</note>
</purpose>
<description>
@@ -302,6 +322,16 @@
<purpose>
<para>The <classname>timed_read_write_mutex</classname> class is a model of the
<link linkend="thread.concepts.TimedReadWriteMutex">TimedReadWriteMutex</link> concept.</para>
<note> Unfortunately it turned out that the current implementation of Read/Write Mutex has
some serious problems. So it was decided not to put this implementation into
release grade code. Also discussions on the mailing list led to the
conclusion that the current concepts need to be rethought. In particular
the schedulings <link linkend="thread.concepts.read-write-scheduling-policies.inter-class">
Inter-Class Scheduling Policies</link> are deemed unnecessary.
There seems to be common belief that a fair scheme suffices.
The following documentation has been retained however, to give
readers of this document the opportunity to study the original design.
</note>
</purpose>
<description>

44
doc/shared_mutex_ref.qbk Normal file
View File

@@ -0,0 +1,44 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:shared_mutex Class `shared_mutex`]
#include <boost/thread/shared_mutex.hpp>
class shared_mutex
{
public:
shared_mutex();
~shared_mutex();
void lock_shared();
bool try_lock_shared();
bool timed_lock_shared(system_time const& timeout);
void unlock_shared();
void lock();
bool try_lock();
bool timed_lock(system_time const& timeout);
void unlock();
void lock_upgrade();
void unlock_upgrade();
void unlock_upgrade_and_lock();
void unlock_and_lock_upgrade();
void unlock_and_lock_shared();
void unlock_upgrade_and_lock_shared();
};
The class `boost::shared_mutex` provides an implementation of a multiple-reader / single-writer mutex. It implements the
__upgrade_lockable_concept__.
Multiple concurrent calls to __lock_ref__, __try_lock_ref__, __timed_lock_ref__, __lock_shared_ref__, __try_lock_shared_ref__ and
__timed_lock_shared_ref__ shall be permitted.
[endsect]

167
doc/thread.qbk Normal file
View File

@@ -0,0 +1,167 @@
[/
(C) Copyright 2007-8 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).
]
[article Thread
[quickbook 1.4]
[authors [Williams, Anthony]]
[copyright 2007-8 Anthony Williams]
[purpose C++ Library for launching threads and synchronizing data between them]
[category text]
[license
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
[@http://www.boost.org/LICENSE_1_0.txt])
]
]
[template lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.lockable [link_text]]]
[def __lockable_concept__ [lockable_concept_link `Lockable` concept]]
[def __lockable_concept_type__ [lockable_concept_link `Lockable`]]
[template timed_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable [link_text]]]
[def __timed_lockable_concept__ [timed_lockable_concept_link `TimedLockable` concept]]
[def __timed_lockable_concept_type__ [timed_lockable_concept_link `TimedLockable`]]
[template shared_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable [link_text]]]
[def __shared_lockable_concept__ [shared_lockable_concept_link `SharedLockable` concept]]
[def __shared_lockable_concept_type__ [shared_lockable_concept_link `SharedLockable`]]
[template upgrade_lockable_concept_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable [link_text]]]
[def __upgrade_lockable_concept__ [upgrade_lockable_concept_link `UpgradeLockable` concept]]
[def __upgrade_lockable_concept_type__ [upgrade_lockable_concept_link `UpgradeLockable`]]
[template lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.lock [link_text]]]
[def __lock_ref__ [lock_ref_link `lock()`]]
[template lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.lock_multiple [link_text]]]
[def __lock_multiple_ref__ [lock_multiple_ref_link `lock()`]]
[template try_lock_multiple_ref_link[link_text] [link thread.synchronization.lock_functions.try_lock_multiple [link_text]]]
[def __try_lock_multiple_ref__ [try_lock_multiple_ref_link `try_lock()`]]
[template unlock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.unlock [link_text]]]
[def __unlock_ref__ [unlock_ref_link `unlock()`]]
[template try_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.lockable.try_lock [link_text]]]
[def __try_lock_ref__ [try_lock_ref_link `try_lock()`]]
[template timed_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock [link_text]]]
[def __timed_lock_ref__ [timed_lock_ref_link `timed_lock()`]]
[template timed_lock_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.timed_lockable.timed_lock_duration [link_text]]]
[def __timed_lock_duration_ref__ [timed_lock_duration_ref_link `timed_lock()`]]
[template lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.lock_shared [link_text]]]
[def __lock_shared_ref__ [lock_shared_ref_link `lock_shared()`]]
[template unlock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.unlock_shared [link_text]]]
[def __unlock_shared_ref__ [unlock_shared_ref_link `unlock_shared()`]]
[template try_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.try_lock_shared [link_text]]]
[def __try_lock_shared_ref__ [try_lock_shared_ref_link `try_lock_shared()`]]
[template timed_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared [link_text]]]
[def __timed_lock_shared_ref__ [timed_lock_shared_ref_link `timed_lock_shared()`]]
[template timed_lock_shared_duration_ref_link[link_text] [link thread.synchronization.mutex_concepts.shared_lockable.timed_lock_shared_duration [link_text]]]
[def __timed_lock_shared_duration_ref__ [timed_lock_shared_duration_ref_link `timed_lock_shared()`]]
[template lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.lock_upgrade [link_text]]]
[def __lock_upgrade_ref__ [lock_upgrade_ref_link `lock_upgrade()`]]
[template unlock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade [link_text]]]
[def __unlock_upgrade_ref__ [unlock_upgrade_ref_link `unlock_upgrade()`]]
[template unlock_upgrade_and_lock_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock [link_text]]]
[def __unlock_upgrade_and_lock_ref__ [unlock_upgrade_and_lock_ref_link `unlock_upgrade_and_lock()`]]
[template unlock_and_lock_upgrade_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_and_lock_upgrade [link_text]]]
[def __unlock_and_lock_upgrade_ref__ [unlock_and_lock_upgrade_ref_link `unlock_and_lock_upgrade()`]]
[template unlock_upgrade_and_lock_shared_ref_link[link_text] [link thread.synchronization.mutex_concepts.upgrade_lockable.unlock_upgrade_and_lock_shared [link_text]]]
[def __unlock_upgrade_and_lock_shared_ref__ [unlock_upgrade_and_lock_shared_ref_link `unlock_upgrade_and_lock_shared()`]]
[template owns_lock_ref_link[link_text] [link thread.synchronization.locks.unique_lock.owns_lock [link_text]]]
[def __owns_lock_ref__ [owns_lock_ref_link `owns_lock()`]]
[template owns_lock_shared_ref_link[link_text] [link thread.synchronization.locks.shared_lock.owns_lock [link_text]]]
[def __owns_lock_shared_ref__ [owns_lock_shared_ref_link `owns_lock()`]]
[template mutex_func_ref_link[link_text] [link thread.synchronization.locks.unique_lock.mutex [link_text]]]
[def __mutex_func_ref__ [mutex_func_ref_link `mutex()`]]
[def __boost_thread__ [*Boost.Thread]]
[def __not_a_thread__ ['Not-a-Thread]]
[def __interruption_points__ [link interruption_points ['interruption points]]]
[def __mutex__ [link thread.synchronization.mutex_types.mutex `boost::mutex`]]
[def __try_mutex__ [link thread.synchronization.mutex_types.try_mutex `boost::try_mutex`]]
[def __timed_mutex__ [link thread.synchronization.mutex_types.timed_mutex `boost::timed_mutex`]]
[def __recursive_mutex__ [link thread.synchronization.mutex_types.recursive_mutex `boost::recursive_mutex`]]
[def __recursive_try_mutex__ [link thread.synchronization.mutex_types.recursive_try_mutex `boost::recursive_try_mutex`]]
[def __recursive_timed_mutex__ [link thread.synchronization.mutex_types.recursive_timed_mutex `boost::recursive_timed_mutex`]]
[def __shared_mutex__ [link thread.synchronization.mutex_types.shared_mutex `boost::shared_mutex`]]
[template unique_lock_link[link_text] [link thread.synchronization.locks.unique_lock [link_text]]]
[def __lock_guard__ [link thread.synchronization.locks.lock_guard `boost::lock_guard`]]
[def __unique_lock__ [unique_lock_link `boost::unique_lock`]]
[def __shared_lock__ [link thread.synchronization.locks.shared_lock `boost::shared_lock`]]
[def __upgrade_lock__ [link thread.synchronization.locks.upgrade_lock `boost::upgrade_lock`]]
[def __upgrade_to_unique_lock__ [link thread.synchronization.locks.upgrade_to_unique_lock `boost::upgrade_to_unique_lock`]]
[def __thread__ [link thread.thread_management.thread `boost::thread`]]
[def __thread_id__ [link thread.thread_management.thread.id `boost::thread::id`]]
[template join_link[link_text] [link thread.thread_management.thread.join [link_text]]]
[def __join__ [join_link `join()`]]
[template timed_join_link[link_text] [link thread.thread_management.thread.timed_join [link_text]]]
[def __timed_join__ [timed_join_link `timed_join()`]]
[def __detach__ [link thread.thread_management.thread.detach `detach()`]]
[def __interrupt__ [link thread.thread_management.thread.interrupt `interrupt()`]]
[def __sleep__ [link thread.thread_management.this_thread.sleep `boost::this_thread::sleep()`]]
[def __interruption_enabled__ [link thread.thread_management.this_thread.interruption_enabled `boost::this_thread::interruption_enabled()`]]
[def __interruption_requested__ [link thread.thread_management.this_thread.interruption_requested `boost::this_thread::interruption_requested()`]]
[def __interruption_point__ [link thread.thread_management.this_thread.interruption_point `boost::this_thread::interruption_point()`]]
[def __disable_interruption__ [link thread.thread_management.this_thread.disable_interruption `boost::this_thread::disable_interruption`]]
[def __restore_interruption__ [link thread.thread_management.this_thread.restore_interruption `boost::this_thread::restore_interruption`]]
[def __thread_resource_error__ `boost::thread_resource_error`]
[def __thread_interrupted__ `boost::thread_interrupted`]
[def __barrier__ [link thread.synchronization.barriers.barrier `boost::barrier`]]
[template cond_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.wait [link_text]]]
[def __cond_wait__ [cond_wait_link `wait()`]]
[template cond_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable.timed_wait [link_text]]]
[def __cond_timed_wait__ [cond_timed_wait_link `timed_wait()`]]
[template cond_any_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.wait [link_text]]]
[def __cond_any_wait__ [cond_any_wait_link `wait()`]]
[template cond_any_timed_wait_link[link_text] [link thread.synchronization.condvar_ref.condition_variable_any.timed_wait [link_text]]]
[def __cond_any_timed_wait__ [cond_any_timed_wait_link `timed_wait()`]]
[def __blocked__ ['blocked]]
[include overview.qbk]
[include changes.qbk]
[include thread_ref.qbk]
[section:synchronization Synchronization]
[include mutex_concepts.qbk]
[include mutexes.qbk]
[include condition_variables.qbk]
[include once.qbk]
[include barrier.qbk]
[endsect]
[include tss.qbk]
[include time.qbk]
[include acknowledgements.qbk]

1064
doc/thread_ref.qbk Normal file

File diff suppressed because it is too large Load Diff

75
doc/time.qbk Normal file
View File

@@ -0,0 +1,75 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section:time Date and Time Requirements]
As of Boost 1.35.0, the __boost_thread__ library uses the [link date_time Boost.Date_Time] library for all operations that require a
time out. These include (but are not limited to):
* __sleep__
* __timed_join__
* __cond_timed_wait__
* __timed_lock_ref__
For the overloads that accept an absolute time parameter, an object of type [link thread.time.system_time `boost::system_time`] is
required. Typically, this will be obtained by adding a duration to the current time, obtained with a call to [link
thread.time.get_system_time `boost::get_system_time()`]. e.g.
boost::system_time const timeout=boost::get_system_time() + boost::posix_time::milliseconds(500);
extern bool done;
extern boost::mutex m;
extern boost::condition_variable cond;
boost::unique_lock<boost::mutex> lk(m);
while(!done)
{
if(!cond.timed_wait(lk,timeout))
{
throw "timed out";
}
}
For the overloads that accept a ['TimeDuration] parameter, an object of any type that meets the [link
date_time.posix_time.time_duration Boost.Date_Time Time Duration requirements] can be used, e.g.
boost::this_thread::sleep(boost::posix_time::milliseconds(25));
boost::mutex m;
if(m.timed_lock(boost::posix_time::nanoseconds(100)))
{
// ...
}
[section:system_time Typedef `system_time`]
#include <boost/thread/thread_time.hpp>
typedef boost::posix_time::ptime system_time;
See the documentation for [link date_time.posix_time.ptime_class `boost::posix_time::ptime`] in the Boost.Date_Time library.
[endsect]
[section:get_system_time Non-member function `get_system_time()`]
#include <boost/thread/thread_time.hpp>
system_time get_system_time();
[variablelist
[[Returns:] [The current time.]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]

184
doc/tss.qbk Normal file
View File

@@ -0,0 +1,184 @@
[/
(C) Copyright 2007-8 Anthony Williams.
Distributed under the Boost Software License, Version 1.0.
(See accompanying file LICENSE_1_0.txt or copy at
http://www.boost.org/LICENSE_1_0.txt).
]
[section Thread Local Storage]
[heading Synopsis]
Thread local storage allows multi-threaded applications to have a separate instance of a given data item for each thread. Where a
single-threaded application would use static or global data, this could lead to contention, deadlock or data corruption in a
multi-threaded application. One example is the C `errno` variable, used for storing the error code related to functions from the
Standard C library. It is common practice (and required by POSIX) for compilers that support multi-threaded applications to provide
a separate instance of `errno` for each thread, in order to avoid different threads competing to read or update the value.
Though compilers often provide this facility in the form of extensions to the declaration syntax (such as `__declspec(thread)` or
`__thread` annotations on `static` or namespace-scope variable declarations), such support is non-portable, and is often limited in
some way, such as only supporting POD types.
[heading Portable thread-local storage with `boost::thread_specific_ptr`]
`boost::thread_specific_ptr` provides a portable mechanism for thread-local storage that works on all compilers supported by
__boost_thread__. Each instance of `boost::thread_specific_ptr` represents a pointer to an object (such as `errno`) where each
thread must have a distinct value. The value for the current thread can be obtained using the `get()` member function, or by using
the `*` and `->` pointer deference operators. Initially the pointer has a value of `NULL` in each thread, but the value for the
current thread can be set using the `reset()` member function.
If the value of the pointer for the current thread is changed using `reset()`, then the previous value is destroyed by calling the
cleanup routine. Alternatively, the stored value can be reset to `NULL` and the prior value returned by calling the `release()`
member function, allowing the application to take back responsibility for destroying the object.
[heading Cleanup at thread exit]
When a thread exits, the objects associated with each `boost::thread_specific_ptr` instance are destroyed. By default, the object
pointed to by a pointer `p` is destroyed by invoking `delete p`, but this can be overridden for a specific instance of
`boost::thread_specific_ptr` by providing a cleanup routine to the constructor. In this case, the object is destroyed by invoking
`func(p)` where `func` is the cleanup routine supplied to the constructor. The cleanup functions are called in an unspecified
order. If a cleanup routine sets the value of associated with an instance of `boost::thread_specific_ptr` that has already been
cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of
`boost::thread_specific_ptr` with values.
[section:thread_specific_ptr Class `thread_specific_ptr`]
#include <boost/thread/tss.hpp>
template <typename T>
class thread_specific_ptr
{
public:
thread_specific_ptr();
explicit thread_specific_ptr(void (*cleanup_function)(T*));
~thread_specific_ptr();
T* get() const;
T* operator->() const;
T& operator*() const;
T* release();
void reset(T* new_value=0);
};
[section:default_constructor `thread_specific_ptr();`]
[variablelist
[[Requires:] [`delete this->get()` is well-formed.]]
[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
default `delete`-based cleanup function will be used to destroy any thread-local objects when `reset()` is called, or the thread
exits.]]
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
]
[endsect]
[section:constructor_with_custom_cleanup `explicit thread_specific_ptr(void (*cleanup_function)(T*));`]
[variablelist
[[Requires:] [`cleanup_function(this->get())` does not throw any exceptions.]]
[[Effects:] [Construct a `thread_specific_ptr` object for storing a pointer to an object of type `T` specific to each thread. The
supplied `cleanup_function` will be used to destroy any thread-local objects when `reset()` is called, or the thread exits.]]
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
]
[endsect]
[section:destructor `~thread_specific_ptr();`]
[variablelist
[[Effects:] [Calls `this->reset()` to clean up the associated value for the current thread, and destroys `*this`.]]
[[Throws:] [Nothing.]]
]
[note Care needs to be taken to ensure that any threads still running after an instance of `boost::thread_specific_ptr` has been
destroyed do not call any member functions on that instance.]
[endsect]
[section:get `T* get() const;`]
[variablelist
[[Returns:] [The pointer associated with the current thread.]]
[[Throws:] [Nothing.]]
]
[note The initial value associated with an instance of `boost::thread_specific_ptr` is `NULL` for each thread.]
[endsect]
[section:operator_arrow `T* operator->() const;`]
[variablelist
[[Returns:] [`this->get()`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:operator_star `T& operator*() const;`]
[variablelist
[[Requires:] [`this->get` is not `NULL`.]]
[[Returns:] [`*(this->get())`]]
[[Throws:] [Nothing.]]
]
[endsect]
[section:reset `void reset(T* new_value=0);`]
[variablelist
[[Effects:] [If `this->get()!=new_value` and `this->get()` is non-`NULL`, invoke `delete this->get()` or
`cleanup_function(this->get())` as appropriate. Store `new_value` as the pointer associated with the current thread.]]
[[Postcondition:] [`this->get()==new_value`]]
[[Throws:] [`boost::thread_resource_error` if an error occurs.]]
]
[endsect]
[section:release `T* release();`]
[variablelist
[[Effects:] [Return `this->get()` and store `NULL` as the pointer associated with the current thread without invoking the cleanup
function.]]
[[Postcondition:] [`this->get()==0`]]
[[Throws:] [Nothing.]]
]
[endsect]
[endsect]
[endsect]

View File

@@ -46,11 +46,16 @@ private:
bounded_buffer buf(2);
boost::mutex io_mutex;
void sender() {
int n = 0;
while (n < 100) {
buf.send(n);
std::cout << "sent: " << n << std::endl;
{
boost::mutex::scoped_lock io_lock(io_mutex);
std::cout << "sent: " << n << std::endl;
}
++n;
}
buf.send(-1);
@@ -60,7 +65,10 @@ void receiver() {
int n;
do {
n = buf.receive();
std::cout << "received: " << n << std::endl;
{
boost::mutex::scoped_lock io_lock(io_mutex);
std::cout << "received: " << n << std::endl;
}
} while (n != -1); // -1 indicates end of buffer
}

View File

@@ -1,19 +1,25 @@
// Copyright (C) 2001-2003
// William E. Kempf
// (C) Copyright 2008 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)
// See www.boost.org/libs/thread for documentation.
#if !defined(BOOST_THREAD_WEK01082003_HPP)
#define BOOST_THREAD_WEK01082003_HPP
#include <boost/thread/thread.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/condition_variable.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>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/barrier.hpp>
#endif

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2002-2003
// David Moore, William E. Kempf
// Copyright (C) 2007-8 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)
@@ -10,35 +11,53 @@
#include <boost/thread/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/condition_variable.hpp>
#include <string>
#include <stdexcept>
namespace boost {
#include <boost/config/abi_prefix.hpp>
class BOOST_THREAD_DECL barrier
namespace boost
{
public:
barrier(unsigned int count);
~barrier();
bool wait();
class barrier
{
public:
barrier(unsigned int count)
: m_threshold(count), m_count(count), m_generation(0)
{
if (count == 0)
throw std::invalid_argument("count cannot be zero.");
}
bool wait()
{
boost::mutex::scoped_lock lock(m_mutex);
unsigned int gen = m_generation;
if (--m_count == 0)
{
m_generation++;
m_count = m_threshold;
m_cond.notify_all();
return true;
}
private:
mutex m_mutex;
// 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
condition m_cond;
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
};
while (gen == m_generation)
m_cond.wait(lock);
return false;
}
private:
mutex m_mutex;
condition_variable m_cond;
unsigned int m_threshold;
unsigned int m_count;
unsigned int m_generation;
};
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,201 +1,16 @@
// Copyright (C) 2001-2003
// William E. Kempf
#ifndef BOOST_THREAD_CONDITION_HPP
#define BOOST_THREAD_CONDITION_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)
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_CONDITION_WEK070601_HPP
#define BOOST_CONDITION_WEK070601_HPP
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
namespace boost {
struct xtime;
// 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
namespace boost
{
friend class condition;
typedef condition_variable_any condition;
}
public:
condition_impl();
~condition_impl();
void notify_one();
void notify_all();
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
void enter_wait();
void do_wait();
bool do_timed_wait(const xtime& xt);
#elif defined(BOOST_HAS_PTHREADS)
void do_wait(pthread_mutex_t* pmutex);
bool do_timed_wait(const xtime& xt, pthread_mutex_t* pmutex);
#endif
#if defined(BOOST_HAS_WINTHREADS)
void* m_gate;
void* m_queue;
void* m_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#elif defined(BOOST_HAS_PTHREADS)
pthread_cond_t m_condition;
#elif defined(BOOST_HAS_MPTASKS)
MPSemaphoreID m_gate;
MPSemaphoreID m_queue;
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
unsigned m_gone; // # threads that timed out and never made it to m_queue
unsigned long m_blocked; // # threads blocked on the condition
unsigned m_waiting; // # threads no longer waiting for the condition but
// still waiting to be removed from m_queue
#endif
};
} // namespace detail
class condition : private noncopyable
{
public:
condition() { }
~condition() { }
void notify_one() { m_impl.notify_one(); }
void notify_all() { m_impl.notify_all(); }
template <typename L>
void wait(L& lock)
{
if (!lock)
throw lock_error();
do_wait(lock.m_mutex);
}
template <typename L, typename Pr>
void wait(L& lock, Pr pred)
{
if (!lock)
throw lock_error();
while (!pred())
do_wait(lock.m_mutex);
}
template <typename L>
bool timed_wait(L& lock, const xtime& xt)
{
if (!lock)
throw lock_error();
return do_timed_wait(lock.m_mutex, xt);
}
template <typename L, typename Pr>
bool timed_wait(L& lock, const xtime& xt, Pr pred)
{
if (!lock)
throw lock_error();
while (!pred())
{
if (!do_timed_wait(lock.m_mutex, xt))
return false;
}
return true;
}
private:
detail::condition_impl m_impl;
template <typename M>
void do_wait(M& mutex)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
#if defined(BOOST_HAS_PTHREADS)
m_impl.do_wait(state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.do_wait();
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
}
template <typename M>
bool do_timed_wait(M& mutex, const xtime& xt)
{
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
m_impl.enter_wait();
#endif
typedef detail::thread::lock_ops<M>
#if defined(__HP_aCC) && __HP_aCC <= 33900 && !defined(BOOST_STRICT_CONFIG)
# define lock_ops lock_ops_ // HP confuses lock_ops witht the template
#endif
lock_ops;
typename lock_ops::lock_state state;
lock_ops::unlock(mutex, state);
bool ret = false;
#if defined(BOOST_HAS_PTHREADS)
ret = m_impl.do_timed_wait(xt, state.pmutex);
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
ret = m_impl.do_timed_wait(xt);
#endif
lock_ops::lock(mutex, state);
#undef lock_ops
return ret;
}
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs.
// 23 May 01 WEKEMPF Removed "duration" timed_waits, as they are too
// difficult to use with spurious wakeups.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_CONDITION_WEK070601_HPP

View File

@@ -0,0 +1,21 @@
#ifndef BOOST_THREAD_CONDITION_VARIABLE_HPP
#define BOOST_THREAD_CONDITION_VARIABLE_HPP
// condition_variable.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/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/condition_variable.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/condition_variable.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -17,8 +17,7 @@
# pragma warn -8066 // Unreachable code
#endif
// insist on threading support being available:
#include <boost/config/requires_threads.hpp>
#include "platform.hpp"
// compatibility with the rest of Boost's auto-linking code:
#if defined(BOOST_THREAD_DYN_DLL) || defined(BOOST_ALL_DYN_LINK)
@@ -31,7 +30,7 @@
#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_THREAD_PLATFORM_WIN32)
# if defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)
//For compilers supporting auto-tss cleanup
//with Boost.Threads lib, use Boost.Threads lib

View File

@@ -0,0 +1,60 @@
// Distributed under the 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-8 Anthony Williams
#ifndef BOOST_THREAD_MOVE_HPP
#define BOOST_THREAD_MOVE_HPP
#ifndef BOOST_NO_SFINAE
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_convertible.hpp>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
template<typename T>
struct thread_move_t
{
T& t;
explicit thread_move_t(T& t_):
t(t_)
{}
T& operator*() const
{
return t;
}
T* operator->() const
{
return &t;
}
private:
void operator=(thread_move_t&);
};
}
#ifndef BOOST_NO_SFINAE
template<typename T>
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, T >::type move(T& t)
{
return T(detail::thread_move_t<T>(t));
}
#endif
template<typename T>
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
{
return t;
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,71 @@
// Copyright 2006 Roland Schwarz.
// (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)
//
// 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_PLATFORM_PTHREAD
#else
# if defined(BOOST_THREAD_WIN32)
# define BOOST_THREAD_PLATFORM_WIN32
# elif defined(BOOST_HAS_PTHREADS)
# define BOOST_THREAD_PLATFORM_PTHREAD
# else
# error "Sorry, no boost threads are available for this platform."
# endif
#endif
#endif // BOOST_THREAD_RS06040501_HPP

View File

@@ -0,0 +1,575 @@
#ifndef BOOST_THREAD_THREAD_COMMON_HPP
#define BOOST_THREAD_THREAD_COMMON_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/exceptions.hpp>
#include <ostream>
#include <boost/thread/detail/move.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/utility.hpp>
#include <boost/assert.hpp>
#include <list>
#include <algorithm>
#include <boost/ref.hpp>
#include <boost/cstdint.hpp>
#include <boost/bind.hpp>
#include <stdlib.h>
#include <memory>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4251)
#endif
namespace boost
{
namespace detail
{
template<typename F>
class thread_data:
public detail::thread_data_base
{
public:
#ifdef BOOST_HAS_RVALUE_REFS
thread_data(F&& f_):
f(static_cast<F&&>(f_))
{}
#else
thread_data(F f_):
f(f_)
{}
thread_data(detail::thread_move_t<F> f_):
f(f_)
{}
#endif
void run()
{
f();
}
private:
F f;
void operator=(thread_data&);
thread_data(thread_data&);
};
template<typename F>
class thread_data<boost::reference_wrapper<F> >:
public detail::thread_data_base
{
private:
F& f;
void operator=(thread_data&);
thread_data(thread_data&);
public:
thread_data(boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
template<typename F>
class thread_data<const boost::reference_wrapper<F> >:
public detail::thread_data_base
{
private:
F& f;
void operator=(thread_data&);
thread_data(thread_data&);
public:
thread_data(const boost::reference_wrapper<F> f_):
f(f_)
{}
void run()
{
f();
}
};
}
class BOOST_THREAD_DECL thread
{
private:
thread(thread&);
thread& operator=(thread&);
void release_handle();
mutable boost::mutex thread_info_mutex;
detail::thread_data_ptr thread_info;
void start_thread();
explicit thread(detail::thread_data_ptr data);
detail::thread_data_ptr get_thread_info() const;
#ifdef BOOST_HAS_RVALUE_REFS
template<typename F>
static inline detail::thread_data_ptr make_thread_info(F&& f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<typename boost::remove_reference<F>::type> >(static_cast<F&&>(f)));
}
static inline detail::thread_data_ptr make_thread_info(void (*f)())
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<void(*)()> >(f));
}
#else
template<typename F>
static inline detail::thread_data_ptr make_thread_info(F f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
}
template<typename F>
static inline detail::thread_data_ptr make_thread_info(boost::detail::thread_move_t<F> f)
{
return detail::thread_data_ptr(detail::heap_new<detail::thread_data<F> >(f));
}
struct dummy;
#endif
public:
thread();
~thread();
#ifdef BOOST_HAS_RVALUE_REFS
template <class F>
thread(F&& f):
thread_info(make_thread_info(static_cast<F&&>(f)))
{
start_thread();
}
thread(thread&& other)
{
thread_info.swap(other.thread_info);
}
thread& operator=(thread&& other)
{
thread_info=other.thread_info;
other.thread_info.reset();
return *this;
}
thread&& move()
{
return static_cast<thread&&>(*this);
}
#else
#ifdef BOOST_NO_SFINAE
template <class F>
explicit thread(F f):
thread_info(make_thread_info(f))
{
start_thread();
}
#else
template <class F>
explicit thread(F f,typename disable_if<boost::is_convertible<F&,detail::thread_move_t<F> >, dummy* >::type=0):
thread_info(make_thread_info(f))
{
start_thread();
}
#endif
template <class F>
explicit thread(detail::thread_move_t<F> f):
thread_info(make_thread_info(f))
{
start_thread();
}
thread(detail::thread_move_t<thread> x)
{
thread_info=x->thread_info;
x->thread_info.reset();
}
thread& operator=(detail::thread_move_t<thread> x)
{
thread new_thread(x);
swap(new_thread);
return *this;
}
operator detail::thread_move_t<thread>()
{
return move();
}
detail::thread_move_t<thread> move()
{
detail::thread_move_t<thread> x(*this);
return x;
}
#endif
template <class F,class A1>
thread(F f,A1 a1):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1)))
{
start_thread();
}
template <class F,class A1,class A2>
thread(F f,A1 a1,A2 a2):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2)))
{
start_thread();
}
template <class F,class A1,class A2,class A3>
thread(F f,A1 a1,A2 a2,A3 a3):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8)))
{
start_thread();
}
template <class F,class A1,class A2,class A3,class A4,class A5,class A6,class A7,class A8,class A9>
thread(F f,A1 a1,A2 a2,A3 a3,A4 a4,A5 a5,A6 a6,A7 a7,A8 a8,A9 a9):
thread_info(make_thread_info(boost::bind(boost::type<void>(),f,a1,a2,a3,a4,a5,a6,a7,a8,a9)))
{
start_thread();
}
void swap(thread& x)
{
thread_info.swap(x.thread_info);
}
class id;
id get_id() const;
bool joinable() const;
void join();
bool timed_join(const system_time& wait_until);
template<typename TimeDuration>
inline bool timed_join(TimeDuration const& rel_time)
{
return timed_join(get_system_time()+rel_time);
}
void detach();
static unsigned hardware_concurrency();
typedef detail::thread_data_base::native_handle_type native_handle_type;
native_handle_type native_handle();
// backwards compatibility
bool operator==(const thread& other) const;
bool operator!=(const thread& other) const;
static inline void yield()
{
this_thread::yield();
}
static inline void sleep(const system_time& xt)
{
this_thread::sleep(xt);
}
// extensions
void interrupt();
bool interruption_requested() const;
};
inline void swap(thread& lhs,thread& rhs)
{
return lhs.swap(rhs);
}
#ifdef BOOST_HAS_RVALUE_REFS
inline thread&& move(thread&& t)
{
return t;
}
#else
inline thread move(detail::thread_move_t<thread> t)
{
return thread(t);
}
#endif
namespace this_thread
{
class BOOST_THREAD_DECL disable_interruption
{
disable_interruption(const disable_interruption&);
disable_interruption& operator=(const disable_interruption&);
bool interruption_was_enabled;
friend class restore_interruption;
public:
disable_interruption();
~disable_interruption();
};
class BOOST_THREAD_DECL restore_interruption
{
restore_interruption(const restore_interruption&);
restore_interruption& operator=(const restore_interruption&);
public:
explicit restore_interruption(disable_interruption& d);
~restore_interruption();
};
thread::id BOOST_THREAD_DECL get_id();
void BOOST_THREAD_DECL interruption_point();
bool BOOST_THREAD_DECL interruption_enabled();
bool BOOST_THREAD_DECL interruption_requested();
inline void sleep(xtime const& abs_time)
{
sleep(system_time(abs_time));
}
}
class thread::id
{
private:
detail::thread_data_ptr thread_data;
id(detail::thread_data_ptr thread_data_):
thread_data(thread_data_)
{}
friend class thread;
friend id this_thread::get_id();
public:
id():
thread_data()
{}
bool operator==(const id& y) const
{
return thread_data==y.thread_data;
}
bool operator!=(const id& y) const
{
return thread_data!=y.thread_data;
}
bool operator<(const id& y) const
{
return thread_data<y.thread_data;
}
bool operator>(const id& y) const
{
return y.thread_data<thread_data;
}
bool operator<=(const id& y) const
{
return !(y.thread_data<thread_data);
}
bool operator>=(const id& y) const
{
return !(thread_data<y.thread_data);
}
template<class charT, class traits>
friend std::basic_ostream<charT, traits>&
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
{
if(x.thread_data)
{
return os<<x.thread_data;
}
else
{
return os<<"{Not-any-thread}";
}
}
};
inline bool thread::operator==(const thread& other) const
{
return get_id()==other.get_id();
}
inline bool thread::operator!=(const thread& other) const
{
return get_id()!=other.get_id();
}
namespace detail
{
struct thread_exit_function_base
{
virtual ~thread_exit_function_base()
{}
virtual void operator()() const=0;
};
template<typename F>
struct thread_exit_function:
thread_exit_function_base
{
F f;
thread_exit_function(F f_):
f(f_)
{}
void operator()() const
{
f();
}
};
void add_thread_exit_function(thread_exit_function_base*);
}
namespace this_thread
{
template<typename F>
void at_thread_exit(F f)
{
detail::thread_exit_function_base* const thread_exit_func=detail::heap_new<detail::thread_exit_function<F> >(f);
detail::add_thread_exit_function(thread_exit_func);
}
}
class thread_group:
private noncopyable
{
public:
~thread_group()
{
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
delete *it;
}
}
template<typename F>
thread* create_thread(F threadfunc)
{
boost::lock_guard<mutex> guard(m);
std::auto_ptr<thread> new_thread(new thread(threadfunc));
threads.push_back(new_thread.get());
return new_thread.release();
}
void add_thread(thread* thrd)
{
if(thrd)
{
boost::lock_guard<mutex> guard(m);
threads.push_back(thrd);
}
}
void remove_thread(thread* thrd)
{
boost::lock_guard<mutex> guard(m);
std::list<thread*>::iterator const it=std::find(threads.begin(),threads.end(),thrd);
if(it!=threads.end())
{
threads.erase(it);
}
}
void join_all()
{
boost::lock_guard<mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->join();
}
}
void interrupt_all()
{
boost::lock_guard<mutex> guard(m);
for(std::list<thread*>::iterator it=threads.begin(),end=threads.end();
it!=end;
++it)
{
(*it)->interrupt();
}
}
size_t size() const
{
boost::lock_guard<mutex> guard(m);
return threads.size();
}
private:
std::list<thread*> threads;
mutable mutex m;
};
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,23 @@
#ifndef BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
#define BOOST_THREAD_THREAD_HEAP_ALLOC_HPP
// thread_heap_alloc.hpp
//
// (C) Copyright 2008 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>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/thread_heap_alloc.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/thread_heap_alloc.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -8,6 +8,8 @@
#include <boost/thread/detail/config.hpp>
#include <boost/config/abi_prefix.hpp>
#if defined(BOOST_HAS_WINTHREADS)
typedef void (__cdecl *thread_exit_handler)(void);
@@ -59,7 +61,7 @@
//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);
extern "C" BOOST_THREAD_DECL void __cdecl on_thread_exit(void);
//Function to be called just be fore a thread ends
//in an exe or dll that uses Boost.Threads.
//Must be called in the context of the thread
@@ -67,7 +69,7 @@
//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
@@ -75,4 +77,6 @@
#endif //defined(BOOST_HAS_WINTHREADS)
#include <boost/config/abi_suffix.hpp>
#endif //!defined(BOOST_TLS_HOOKS_HPP)

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007-8 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)
@@ -18,7 +19,13 @@
#include <string>
#include <stdexcept>
namespace boost {
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class BOOST_THREAD_DECL thread_interrupted
{};
class BOOST_THREAD_DECL thread_exception : public std::exception
{
@@ -35,6 +42,17 @@ private:
int m_sys_err;
};
class condition_error:
public std::exception
{
public:
const char* what() const throw()
{
return "Condition error";
}
};
class BOOST_THREAD_DECL lock_error : public thread_exception
{
public:
@@ -87,6 +105,8 @@ public:
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif // BOOST_THREAD_CONFIG_PDM070801_H
// Change log:

File diff suppressed because it is too large Load Diff

View File

@@ -1,170 +1,21 @@
// Copyright (C) 2001-2003
// William E. Kempf
#ifndef BOOST_THREAD_MUTEX_HPP
#define BOOST_THREAD_MUTEX_HPP
// mutex.hpp
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 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)
#ifndef BOOST_MUTEX_WEK070601_HPP
#define BOOST_MUTEX_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#if defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
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:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
class BOOST_THREAD_DECL try_mutex
: private noncopyable
{
public:
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:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
class BOOST_THREAD_DECL timed_mutex
: private noncopyable
{
public:
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:
#if defined(BOOST_HAS_WINTHREADS)
typedef void* cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
pthread_mutex_t* pmutex;
};
#elif defined(BOOST_HAS_MPTASKS)
struct cv_state
{
};
#endif
void do_lock();
bool do_trylock();
bool do_timedlock(const xtime& xt);
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
pthread_cond_t m_condition;
bool m_locked;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
#endif
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 22 May 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.
#endif // BOOST_MUTEX_WEK070601_HPP

View File

@@ -1,37 +1,33 @@
// Copyright (C) 2001-2003
// William E. Kempf
#ifndef BOOST_THREAD_ONCE_HPP
#define BOOST_THREAD_ONCE_HPP
// once.hpp
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 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)
#ifndef BOOST_ONCE_WEK080101_HPP
#define BOOST_ONCE_WEK080101_HPP
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/once.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/once.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
namespace boost {
#include <boost/config/abi_prefix.hpp>
#if defined(BOOST_HAS_PTHREADS)
namespace boost
{
inline void call_once(void (*func)(),once_flag& flag)
{
call_once(flag,func);
}
}
typedef pthread_once_t once_flag;
#define BOOST_ONCE_INIT PTHREAD_ONCE_INIT
#elif (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef long once_flag;
#define BOOST_ONCE_INIT 0
#include <boost/config/abi_suffix.hpp>
#endif
void BOOST_THREAD_DECL call_once(void (*func)(), once_flag& flag);
} // namespace boost
// Change Log:
// 1 Aug 01 WEKEMPF Initial version.
#endif // BOOST_ONCE_WEK080101_HPP

View File

@@ -0,0 +1,176 @@
#ifndef BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
#define BOOST_THREAD_CONDITION_VARIABLE_PTHREAD_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 Anthony Williams
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
#include "thread_data.hpp"
#include "condition_variable_fwd.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
inline void condition_variable::wait(unique_lock<mutex>& m)
{
detail::interruption_checker check_for_interruption(&cond);
BOOST_VERIFY(!pthread_cond_wait(&cond,m.mutex()->native_handle()));
}
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
{
detail::interruption_checker check_for_interruption(&cond);
struct timespec const timeout=detail::get_timespec(wait_until);
int const cond_res=pthread_cond_timedwait(&cond,m.mutex()->native_handle(),&timeout);
if(cond_res==ETIMEDOUT)
{
return false;
}
BOOST_ASSERT(!cond_res);
return true;
}
inline void condition_variable::notify_one()
{
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
inline void condition_variable::notify_all()
{
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
}
class condition_variable_any
{
pthread_mutex_t internal_mutex;
pthread_cond_t cond;
condition_variable_any(condition_variable&);
condition_variable_any& operator=(condition_variable&);
public:
condition_variable_any()
{
int const res=pthread_mutex_init(&internal_mutex,NULL);
if(res)
{
throw thread_resource_error();
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
throw thread_resource_error();
}
}
~condition_variable_any()
{
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
template<typename lock_type>
void wait(lock_type& m)
{
int res=0;
{
detail::interruption_checker check_for_interruption(&cond);
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
m.unlock();
res=pthread_cond_wait(&cond,&internal_mutex);
}
m.lock();
}
if(res)
{
throw condition_error();
}
}
template<typename lock_type,typename predicate_type>
void wait(lock_type& m,predicate_type pred)
{
while(!pred()) wait(m);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
{
struct timespec const timeout=detail::get_timespec(wait_until);
int res=0;
{
detail::interruption_checker check_for_interruption(&cond);
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
m.unlock();
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
}
m.lock();
}
if(res==ETIMEDOUT)
{
return false;
}
if(res)
{
throw condition_error();
}
return true;
}
template<typename lock_type>
bool timed_wait(lock_type& m,xtime const& wait_until)
{
return timed_wait(m,system_time(wait_until));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return timed_wait(m,get_system_time()+wait_duration);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!timed_wait(m, wait_until))
return pred();
}
return true;
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
void notify_one()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
void notify_all()
{
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,97 @@
#ifndef BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
#define BOOST_THREAD_PTHREAD_CONDITION_VARIABLE_FWD_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 Anthony Williams
#include <boost/assert.hpp>
#include <pthread.h>
#include <boost/thread/mutex.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class condition_variable
{
private:
pthread_cond_t cond;
condition_variable(condition_variable&);
condition_variable& operator=(condition_variable&);
public:
condition_variable()
{
int const res=pthread_cond_init(&cond,NULL);
if(res)
{
throw thread_resource_error();
}
}
~condition_variable()
{
BOOST_VERIFY(!pthread_cond_destroy(&cond));
}
void wait(unique_lock<mutex>& m);
template<typename predicate_type>
void wait(unique_lock<mutex>& m,predicate_type pred)
{
while(!pred()) wait(m);
}
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until);
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until)
{
return timed_wait(m,system_time(wait_until));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return timed_wait(m,get_system_time()+wait_duration);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!timed_wait(m, wait_until))
return pred();
}
return true;
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,xtime const& wait_until,predicate_type pred)
{
return timed_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return timed_wait(m,get_system_time()+wait_duration,pred);
}
typedef pthread_cond_t* native_handle_type;
native_handle_type native_handle()
{
return &cond;
}
void notify_one();
void notify_all();
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,210 @@
#ifndef BOOST_THREAD_PTHREAD_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_MUTEX_HPP
// (C) Copyright 2007-8 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 <pthread.h>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/assert.hpp>
#include <errno.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
#ifdef _POSIX_TIMEOUTS
#if _POSIX_TIMEOUTS >= 0
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class mutex:
boost::noncopyable
{
private:
pthread_mutex_t m;
public:
mutex()
{
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
throw thread_resource_error();
}
}
~mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
}
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
typedef unique_lock<mutex> scoped_lock;
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
};
typedef mutex try_mutex;
class timed_mutex:
boost::noncopyable
{
private:
pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
pthread_cond_t cond;
bool is_locked;
#endif
public:
timed_mutex()
{
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
throw thread_resource_error();
}
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
throw thread_resource_error();
}
is_locked=false;
#endif
}
~timed_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
bool timed_lock(boost::xtime const & absolute_time)
{
return timed_lock(system_time(absolute_time));
}
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
bool timed_lock(system_time const & abs_time)
{
struct timespec const timeout=detail::get_timespec(abs_time);
int const res=pthread_mutex_timedlock(&m,&timeout);
BOOST_ASSERT(!res || res==ETIMEDOUT);
return !res;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
#else
void lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
}
is_locked=true;
}
void unlock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
is_locked=false;
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked)
{
return false;
}
is_locked=true;
return true;
}
bool timed_lock(system_time const & abs_time)
{
struct timespec const timeout=detail::get_timespec(abs_time);
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
while(is_locked)
{
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
if(cond_res==ETIMEDOUT)
{
return false;
}
BOOST_ASSERT(!cond_res);
}
is_locked=true;
return true;
}
#endif
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,90 @@
#ifndef BOOST_THREAD_PTHREAD_ONCE_HPP
#define BOOST_THREAD_PTHREAD_ONCE_HPP
// once.hpp
//
// (C) Copyright 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <pthread.h>
#include <boost/assert.hpp>
#include "pthread_mutex_scoped_lock.hpp"
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
#include <boost/cstdint.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
struct once_flag
{
boost::uintmax_t epoch;
};
namespace detail
{
BOOST_THREAD_DECL boost::uintmax_t& get_once_per_thread_epoch();
BOOST_THREAD_DECL extern boost::uintmax_t once_global_epoch;
BOOST_THREAD_DECL extern pthread_mutex_t once_epoch_mutex;
BOOST_THREAD_DECL extern pthread_cond_t once_epoch_cv;
}
#define BOOST_ONCE_INITIAL_FLAG_VALUE 0
#define BOOST_ONCE_INIT {BOOST_ONCE_INITIAL_FLAG_VALUE}
// Based on Mike Burrows fast_pthread_once algorithm as described in
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2444.html
template<typename Function>
void call_once(once_flag& flag,Function f)
{
static boost::uintmax_t const uninitialized_flag=BOOST_ONCE_INITIAL_FLAG_VALUE;
static boost::uintmax_t const being_initialized=uninitialized_flag+1;
boost::uintmax_t const epoch=flag.epoch;
boost::uintmax_t& this_thread_epoch=detail::get_once_per_thread_epoch();
if(epoch<this_thread_epoch)
{
pthread::pthread_mutex_scoped_lock lk(&detail::once_epoch_mutex);
while(flag.epoch<=being_initialized)
{
if(flag.epoch==uninitialized_flag)
{
flag.epoch=being_initialized;
try
{
pthread::pthread_mutex_scoped_unlock relocker(&detail::once_epoch_mutex);
f();
}
catch(...)
{
flag.epoch=uninitialized_flag;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
throw;
}
flag.epoch=--detail::once_global_epoch;
BOOST_VERIFY(!pthread_cond_broadcast(&detail::once_epoch_cv));
}
else
{
while(flag.epoch==being_initialized)
{
BOOST_VERIFY(!pthread_cond_wait(&detail::once_epoch_cv,&detail::once_epoch_mutex));
}
}
}
this_thread_epoch=detail::once_global_epoch;
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,54 @@
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
// (C) Copyright 2007-8 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 <pthread.h>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace pthread
{
class pthread_mutex_scoped_lock
{
pthread_mutex_t* m;
public:
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
m(m_)
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
~pthread_mutex_scoped_lock()
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
};
class pthread_mutex_scoped_unlock
{
pthread_mutex_t* m;
public:
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
m(m_)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
~pthread_mutex_scoped_unlock()
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
};
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,266 @@
#ifndef BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_RECURSIVE_MUTEX_HPP
// (C) Copyright 2007-8 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 <pthread.h>
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/assert.hpp>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <boost/date_time/posix_time/conversion.hpp>
#include <errno.h>
#include "timespec.hpp"
#include "pthread_mutex_scoped_lock.hpp"
#ifdef _POSIX_TIMEOUTS
#if _POSIX_TIMEOUTS >= 0
#define BOOST_PTHREAD_HAS_TIMEDLOCK
#endif
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class recursive_mutex:
boost::noncopyable
{
private:
pthread_mutex_t m;
public:
recursive_mutex()
{
pthread_mutexattr_t attr;
int const init_attr_res=pthread_mutexattr_init(&attr);
if(init_attr_res)
{
throw thread_resource_error();
}
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
if(set_attr_res)
{
throw thread_resource_error();
}
int const res=pthread_mutex_init(&m,&attr);
if(res)
{
throw thread_resource_error();
}
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
}
~recursive_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
}
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
typedef unique_lock<recursive_mutex> scoped_lock;
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
};
typedef recursive_mutex recursive_try_mutex;
class recursive_timed_mutex:
boost::noncopyable
{
private:
pthread_mutex_t m;
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
pthread_cond_t cond;
bool is_locked;
pthread_t owner;
unsigned count;
#endif
public:
recursive_timed_mutex()
{
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
pthread_mutexattr_t attr;
int const init_attr_res=pthread_mutexattr_init(&attr);
if(init_attr_res)
{
throw thread_resource_error();
}
int const set_attr_res=pthread_mutexattr_settype(&attr,PTHREAD_MUTEX_RECURSIVE);
if(set_attr_res)
{
throw thread_resource_error();
}
int const res=pthread_mutex_init(&m,&attr);
if(res)
{
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
throw thread_resource_error();
}
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
#else
int const res=pthread_mutex_init(&m,NULL);
if(res)
{
throw thread_resource_error();
}
int const res2=pthread_cond_init(&cond,NULL);
if(res2)
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
throw thread_resource_error();
}
is_locked=false;
count=0;
#endif
}
~recursive_timed_mutex()
{
BOOST_VERIFY(!pthread_mutex_destroy(&m));
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
BOOST_VERIFY(!pthread_cond_destroy(&cond));
#endif
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
#ifdef BOOST_PTHREAD_HAS_TIMEDLOCK
void lock()
{
BOOST_VERIFY(!pthread_mutex_lock(&m));
}
void unlock()
{
BOOST_VERIFY(!pthread_mutex_unlock(&m));
}
bool try_lock()
{
int const res=pthread_mutex_trylock(&m);
BOOST_ASSERT(!res || res==EBUSY);
return !res;
}
bool timed_lock(system_time const & abs_time)
{
struct timespec const timeout=detail::get_timespec(abs_time);
int const res=pthread_mutex_timedlock(&m,&timeout);
BOOST_ASSERT(!res || res==ETIMEDOUT);
return !res;
}
typedef pthread_mutex_t* native_handle_type;
native_handle_type native_handle()
{
return &m;
}
#else
void lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && pthread_equal(owner,pthread_self()))
{
++count;
return;
}
while(is_locked)
{
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
}
is_locked=true;
++count;
owner=pthread_self();
}
void unlock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(!--count)
{
is_locked=false;
}
BOOST_VERIFY(!pthread_cond_signal(&cond));
}
bool try_lock()
{
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && !pthread_equal(owner,pthread_self()))
{
return false;
}
is_locked=true;
++count;
owner=pthread_self();
return true;
}
bool timed_lock(system_time const & abs_time)
{
struct timespec const timeout=detail::get_timespec(abs_time);
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
if(is_locked && pthread_equal(owner,pthread_self()))
{
++count;
return true;
}
while(is_locked)
{
int const cond_res=pthread_cond_timedwait(&cond,&m,&timeout);
if(cond_res==ETIMEDOUT)
{
return false;
}
BOOST_ASSERT(!cond_res);
}
is_locked=true;
++count;
owner=pthread_self();
return true;
}
#endif
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,303 @@
#ifndef BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_PTHREAD_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 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/thread.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex
{
private:
struct state_data
{
unsigned shared_count;
bool exclusive;
bool upgrade;
bool exclusive_waiting_blocked;
};
state_data state;
boost::mutex state_change;
boost::condition_variable shared_cond;
boost::condition_variable exclusive_cond;
boost::condition_variable upgrade_cond;
void release_waiters()
{
exclusive_cond.notify_one();
shared_cond.notify_all();
}
public:
shared_mutex()
{
state_data state_={0,0,0,0};
state=state_;
}
~shared_mutex()
{
}
void lock_shared()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked)
{
shared_cond.wait(lk);
}
++state.shared_count;
}
bool try_lock_shared()
{
boost::mutex::scoped_lock lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked)
{
return false;
}
else
{
++state.shared_count;
return true;
}
}
bool timed_lock_shared(system_time const& timeout)
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked)
{
if(!shared_cond.timed_wait(lk,timeout))
{
return false;
}
}
++state.shared_count;
return true;
}
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
return timed_lock_shared(get_system_time()+relative_time);
}
void unlock_shared()
{
boost::mutex::scoped_lock lk(state_change);
bool const last_reader=!--state.shared_count;
if(last_reader)
{
if(state.upgrade)
{
state.upgrade=false;
state.exclusive=true;
upgrade_cond.notify_one();
}
else
{
state.exclusive_waiting_blocked=false;
}
release_waiters();
}
}
void lock()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
exclusive_cond.wait(lk);
}
state.exclusive=true;
}
bool timed_lock(system_time const& timeout)
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=true;
if(!exclusive_cond.timed_wait(lk,timeout))
{
if(state.shared_count || state.exclusive)
{
state.exclusive_waiting_blocked=false;
exclusive_cond.notify_one();
return false;
}
break;
}
}
state.exclusive=true;
return true;
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
bool try_lock()
{
boost::mutex::scoped_lock lk(state_change);
if(state.shared_count || state.exclusive)
{
return false;
}
else
{
state.exclusive=true;
return true;
}
}
void unlock()
{
boost::mutex::scoped_lock lk(state_change);
state.exclusive=false;
state.exclusive_waiting_blocked=false;
release_waiters();
}
void lock_upgrade()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
shared_cond.wait(lk);
}
++state.shared_count;
state.upgrade=true;
}
bool timed_lock_upgrade(system_time const& timeout)
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
while(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
if(!shared_cond.timed_wait(lk,timeout))
{
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
break;
}
}
++state.shared_count;
state.upgrade=true;
return true;
}
template<typename TimeDuration>
bool timed_lock_upgrade(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
bool try_lock_upgrade()
{
boost::mutex::scoped_lock lk(state_change);
if(state.exclusive || state.exclusive_waiting_blocked || state.upgrade)
{
return false;
}
else
{
++state.shared_count;
state.upgrade=true;
return true;
}
}
void unlock_upgrade()
{
boost::mutex::scoped_lock lk(state_change);
state.upgrade=false;
bool const last_reader=!--state.shared_count;
if(last_reader)
{
state.exclusive_waiting_blocked=false;
release_waiters();
}
}
void unlock_upgrade_and_lock()
{
boost::this_thread::disable_interruption do_not_disturb;
boost::mutex::scoped_lock lk(state_change);
--state.shared_count;
while(state.shared_count)
{
upgrade_cond.wait(lk);
}
state.upgrade=false;
state.exclusive=true;
}
void unlock_and_lock_upgrade()
{
boost::mutex::scoped_lock lk(state_change);
state.exclusive=false;
state.upgrade=true;
++state.shared_count;
state.exclusive_waiting_blocked=false;
release_waiters();
}
void unlock_and_lock_shared()
{
boost::mutex::scoped_lock lk(state_change);
state.exclusive=false;
++state.shared_count;
state.exclusive_waiting_blocked=false;
release_waiters();
}
void unlock_upgrade_and_lock_shared()
{
boost::mutex::scoped_lock lk(state_change);
state.upgrade=false;
state.exclusive_waiting_blocked=false;
release_waiters();
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,118 @@
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/optional.hpp>
#include <pthread.h>
#include "condition_variable_fwd.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class thread;
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base;
typedef boost::shared_ptr<thread_data_base> thread_data_ptr;
struct BOOST_THREAD_DECL thread_data_base:
enable_shared_from_this<thread_data_base>
{
thread_data_ptr self;
pthread_t thread_handle;
boost::mutex data_mutex;
boost::condition_variable done_condition;
boost::mutex sleep_mutex;
boost::condition_variable sleep_condition;
bool done;
bool join_started;
bool joined;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interrupt_enabled;
bool interrupt_requested;
pthread_cond_t* current_cond;
thread_data_base():
done(false),join_started(false),joined(false),
thread_exit_callbacks(0),tss_data(0),
interrupt_enabled(true),
interrupt_requested(false),
current_cond(0)
{}
virtual ~thread_data_base();
typedef pthread_t native_handle_type;
virtual void run()=0;
};
BOOST_THREAD_DECL thread_data_base* get_current_thread_data();
class interruption_checker
{
thread_data_base* const thread_info;
void check_for_interruption()
{
if(thread_info->interrupt_requested)
{
thread_info->interrupt_requested=false;
throw thread_interrupted();
}
}
void operator=(interruption_checker&);
public:
explicit interruption_checker(pthread_cond_t* cond):
thread_info(detail::get_current_thread_data())
{
if(thread_info && thread_info->interrupt_enabled)
{
lock_guard<mutex> guard(thread_info->data_mutex);
check_for_interruption();
thread_info->current_cond=cond;
}
}
~interruption_checker()
{
if(thread_info && thread_info->interrupt_enabled)
{
lock_guard<mutex> guard(thread_info->data_mutex);
thread_info->current_cond=NULL;
check_for_interruption();
}
}
};
}
namespace this_thread
{
void BOOST_THREAD_DECL yield();
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
{
this_thread::sleep(get_system_time()+rel_time);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,242 @@
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2008 Anthony Williams
#ifndef THREAD_HEAP_ALLOC_PTHREAD_HPP
#define THREAD_HEAP_ALLOC_PTHREAD_HPP
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
template<typename T>
inline T* heap_new()
{
return new T();
}
#ifdef BOOST_HAS_RVALUE_REFS
template<typename T,typename A1>
inline T* heap_new(A1&& a1)
{
return new T(static_cast<A1&&>(a1));
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1&& a1,A2&& a2)
{
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
{
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3));
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
{
return new T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
}
#else
template<typename T,typename A1>
inline T* heap_new_impl(A1 a1)
{
return new T(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new_impl(A1 a1,A2 a2)
{
return new T(a1,a2);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
{
return new T(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
{
return new T(a1,a2,a3,a4);
}
template<typename T,typename A1>
inline T* heap_new(A1 const& a1)
{
return heap_new_impl<T,A1 const&>(a1);
}
template<typename T,typename A1>
inline T* heap_new(A1& a1)
{
return heap_new_impl<T,A1&>(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2 const& a2)
{
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2 const& a2)
{
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2& a2)
{
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2& a2)
{
return heap_new_impl<T,A1&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
#endif
template<typename T>
inline void heap_delete(T* data)
{
delete data;
}
template<typename T>
struct do_heap_delete
{
void operator()(T* data) const
{
detail::heap_delete(data);
}
};
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,36 @@
#ifndef BOOST_THREAD_PTHREAD_TIMESPEC_HPP
#define BOOST_THREAD_PTHREAD_TIMESPEC_HPP
// (C) Copyright 2007-8 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/thread_time.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <pthread.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
inline struct timespec get_timespec(boost::system_time const& abs_time)
{
struct timespec timeout={0,0};
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
timeout.tv_sec=time_since_epoch.total_seconds();
timeout.tv_nsec=(long)(time_since_epoch.fractional_seconds()*(1000000000l/time_since_epoch.ticks_per_second()));
return timeout;
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,184 +1,21 @@
// Copyright (C) 2001-2003
// William E. Kempf
#ifndef BOOST_THREAD_RECURSIVE_MUTEX_HPP
#define BOOST_THREAD_RECURSIVE_MUTEX_HPP
// recursive_mutex.hpp
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 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)
#ifndef BOOST_RECURSIVE_MUTEX_WEK070601_HPP
#define BOOST_RECURSIVE_MUTEX_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/thread/detail/lock.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#include <boost/thread/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/recursive_mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/recursive_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#if defined(BOOST_HAS_MPTASKS)
# include "scoped_critical_region.hpp"
#endif
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:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
unsigned m_count;
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
# endif
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
class BOOST_THREAD_DECL recursive_try_mutex
: private noncopyable
{
public:
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:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
bool do_trylock();
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
bool m_critical_section;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
unsigned m_count;
# if !defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE)
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
# endif
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
class BOOST_THREAD_DECL recursive_timed_mutex
: private noncopyable
{
public:
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:
#if (defined(BOOST_HAS_WINTHREADS) || defined(BOOST_HAS_MPTASKS))
typedef std::size_t cv_state;
#elif defined(BOOST_HAS_PTHREADS)
struct cv_state
{
long count;
pthread_mutex_t* pmutex;
};
#endif
void do_lock();
bool do_trylock();
bool do_timedlock(const xtime& xt);
void do_unlock();
void do_lock(cv_state& state);
void do_unlock(cv_state& state);
#if defined(BOOST_HAS_WINTHREADS)
void* m_mutex;
unsigned long m_count;
#elif defined(BOOST_HAS_PTHREADS)
pthread_mutex_t m_mutex;
pthread_cond_t m_unlocked;
pthread_t m_thread_id;
bool m_valid_id;
unsigned m_count;
#elif defined(BOOST_HAS_MPTASKS)
threads::mac::detail::scoped_critical_region m_mutex;
threads::mac::detail::scoped_critical_region m_mutex_mutex;
std::size_t m_count;
#endif
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif // BOOST_RECURSIVE_MUTEX_WEK070601_HPP
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 1 Jun 01 WEKEMPF Modified to use xtime for time outs. Factored out
// to three classes, mutex, try_mutex and timed_mutex.
// 11 Jun 01 WEKEMPF Modified to use PTHREAD_MUTEX_RECURSIVE if available.
// 3 Jan 03 WEKEMPF Modified for DLL implementation.

View File

@@ -0,0 +1,21 @@
#ifndef BOOST_THREAD_SHARED_MUTEX_HPP
#define BOOST_THREAD_SHARED_MUTEX_HPP
// shared_mutex.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/detail/platform.hpp>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/shared_mutex.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/shared_mutex.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
#endif

View File

@@ -1,89 +1,25 @@
// Copyright (C) 2001-2003
// William E. Kempf
#ifndef BOOST_THREAD_THREAD_HPP
#define BOOST_THREAD_THREAD_HPP
// thread.hpp
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 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)
#ifndef BOOST_THREAD_WEK070601_HPP
#define BOOST_THREAD_WEK070601_HPP
#include <boost/thread/detail/platform.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/mutex.hpp>
#include <list>
#include <memory>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
# include <boost/thread/condition.hpp>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#if defined(BOOST_THREAD_PLATFORM_WIN32)
#include <boost/thread/win32/thread_data.hpp>
#elif defined(BOOST_THREAD_PLATFORM_PTHREAD)
#include <boost/thread/pthread/thread_data.hpp>
#else
#error "Boost threads unavailable on this platform"
#endif
namespace boost {
#include <boost/thread/detail/thread.hpp>
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:
#if defined(BOOST_HAS_WINTHREADS)
void* m_thread;
unsigned int m_id;
#elif defined(BOOST_HAS_PTHREADS)
private:
pthread_t m_thread;
#elif defined(BOOST_HAS_MPTASKS)
MPQueueID m_pJoinQueueID;
MPTaskID m_pTaskID;
#endif
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
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.
// 1 Jun 01 WEKEMPF Added boost::thread initial implementation.
// 3 Jul 01 WEKEMPF Redesigned boost::thread to be noncopyable.
#endif // BOOST_THREAD_WEK070601_HPP

View File

@@ -0,0 +1,50 @@
#ifndef BOOST_THREAD_TIME_HPP
#define BOOST_THREAD_TIME_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/date_time/microsec_time_clock.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
typedef boost::posix_time::ptime system_time;
inline system_time get_system_time()
{
return boost::date_time::microsec_clock<system_time>::universal_time();
}
namespace detail
{
inline system_time get_system_time_sentinel()
{
return system_time(boost::posix_time::pos_infin);
}
inline unsigned long get_milliseconds_until(system_time const& target_time)
{
if(target_time.is_pos_infinity())
{
return ~(unsigned long)0;
}
system_time const now=get_system_time();
if(target_time<=now)
{
return 0;
}
return static_cast<unsigned long>((target_time-now).total_milliseconds()+1);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,128 +1,111 @@
// 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)
#ifndef BOOST_TSS_WEK070601_HPP
#define BOOST_TSS_WEK070601_HPP
#include <boost/thread/detail/config.hpp>
#include <boost/utility.hpp>
#include <boost/function.hpp>
#include <boost/thread/exceptions.hpp>
#if defined(BOOST_HAS_PTHREADS)
# include <pthread.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#endif
namespace boost {
// 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();
}
}
~tss();
void* get() const;
void set(void* value);
void cleanup(void* p);
private:
unsigned int m_slot; //This is a "pseudo-slot", not a native slot
void init(boost::function1<void, void*>* pcleanup);
};
#if defined(BOOST_HAS_MPTASKS)
void thread_cleanup();
#endif
template <typename T>
struct tss_adapter
{
template <typename F>
tss_adapter(const F& cleanup) : m_cleanup(cleanup) { }
void operator()(void* p) { m_cleanup(static_cast<T*>(p)); }
boost::function1<void, T*> m_cleanup;
};
} // namespace detail
template <typename T>
class thread_specific_ptr : private noncopyable
{
public:
thread_specific_ptr()
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(
&thread_specific_ptr<T>::cleanup)))
{
}
thread_specific_ptr(void (*clean)(T*))
: m_tss(new boost::function1<void, void*>(
boost::detail::tss_adapter<T>(clean)))
{
}
~thread_specific_ptr() { reset(); }
T* get() const { return static_cast<T*>(m_tss.get()); }
T* operator->() const { return get(); }
T& operator*() const { return *get(); }
T* release() { T* temp = get(); if (temp) m_tss.set(0); return temp; }
void reset(T* p=0)
{
T* cur = get();
if (cur == p) return;
m_tss.set(p);
if (cur) m_tss.cleanup(cur);
}
private:
static void cleanup(T* p) { delete p; }
detail::tss m_tss;
};
#ifdef BOOST_MSVC
# pragma warning(pop)
#endif
} // namespace boost
#endif //BOOST_TSS_WEK070601_HPP
// Change Log:
// 6 Jun 01
// WEKEMPF Initial version.
// 30 May 02 WEKEMPF
// Added interface to set specific cleanup handlers.
// Removed TLS slot limits from most implementations.
// 22 Mar 04 GlassfordM for WEKEMPF
// Fixed: thread_specific_ptr::reset() doesn't check error returned
// by tss::set(); tss::set() now throws if it fails.
// Fixed: calling thread_specific_ptr::reset() or
// thread_specific_ptr::release() causes double-delete: once on
// reset()/release() and once on ~thread_specific_ptr().
#ifndef BOOST_THREAD_TSS_HPP
#define BOOST_THREAD_TSS_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/thread/detail/thread_heap_alloc.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
struct tss_cleanup_function
{
virtual ~tss_cleanup_function()
{}
virtual void operator()(void* data)=0;
};
BOOST_THREAD_DECL void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing);
BOOST_THREAD_DECL void* get_tss_data(void const* key);
}
template <typename T>
class thread_specific_ptr
{
private:
thread_specific_ptr(thread_specific_ptr&);
thread_specific_ptr& operator=(thread_specific_ptr&);
struct delete_data:
detail::tss_cleanup_function
{
void operator()(void* data)
{
delete static_cast<T*>(data);
}
};
struct run_custom_cleanup_function:
detail::tss_cleanup_function
{
void (*cleanup_function)(T*);
explicit run_custom_cleanup_function(void (*cleanup_function_)(T*)):
cleanup_function(cleanup_function_)
{}
void operator()(void* data)
{
cleanup_function(static_cast<T*>(data));
}
};
boost::shared_ptr<detail::tss_cleanup_function> cleanup;
public:
thread_specific_ptr():
cleanup(detail::heap_new<delete_data>(),detail::do_heap_delete<delete_data>())
{}
explicit thread_specific_ptr(void (*func_)(T*))
{
if(func_)
{
cleanup.reset(detail::heap_new<run_custom_cleanup_function>(func_),detail::do_heap_delete<run_custom_cleanup_function>());
}
}
~thread_specific_ptr()
{
reset();
}
T* get() const
{
return static_cast<T*>(detail::get_tss_data(this));
}
T* operator->() const
{
return get();
}
T& operator*() const
{
return *get();
}
T* release()
{
T* const temp=get();
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
return temp;
}
void reset(T* new_value=0)
{
T* const current_value=get();
if(current_value!=new_value)
{
detail::set_tss_data(this,cleanup,new_value,true);
}
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,120 @@
#ifndef BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
#define BOOST_BASIC_RECURSIVE_MUTEX_WIN32_HPP
// basic_recursive_mutex.hpp
//
// (C) Copyright 2006-8 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 "thread_primitives.hpp"
#include "basic_timed_mutex.hpp"
#include <boost/config/abi_prefix.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::system_time const& target)
{
long const current_thread_id=win32::GetCurrentThreadId();
return try_recursive_lock(current_thread_id) || try_timed_lock(current_thread_id,target);
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
}
void unlock()
{
if(!--recursion_count)
{
BOOST_INTERLOCKED_EXCHANGE(&locking_thread_id,0);
mutex.unlock();
}
}
private:
bool try_recursive_lock(long current_thread_id)
{
if(::boost::detail::interlocked_read_acquire(&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::system_time 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}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,178 @@
#ifndef BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
#define BOOST_BASIC_TIMED_MUTEX_WIN32_HPP
// basic_timed_mutex_win32.hpp
//
// (C) Copyright 2006-8 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 "thread_primitives.hpp"
#include "interlocked_read.hpp"
#include <boost/thread/thread_time.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/detail/interlocked.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
struct basic_timed_mutex
{
BOOST_STATIC_CONSTANT(unsigned char,lock_flag_bit=31);
BOOST_STATIC_CONSTANT(unsigned char,event_set_flag_bit=30);
BOOST_STATIC_CONSTANT(long,lock_flag_value=1<<lock_flag_bit);
BOOST_STATIC_CONSTANT(long,event_set_flag_value=1<<event_set_flag_bit);
long active_count;
void* event;
void initialize()
{
active_count=0;
event=0;
}
void destroy()
{
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4312)
#endif
void* const old_event=BOOST_INTERLOCKED_EXCHANGE_POINTER(&event,0);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
if(old_event)
{
win32::CloseHandle(old_event);
}
}
bool try_lock()
{
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
}
void lock()
{
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
}
bool timed_lock(::boost::system_time const& wait_until)
{
if(!win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit))
{
return true;
}
long old_count=active_count;
for(;;)
{
long const new_count=(old_count&lock_flag_value)?(old_count+1):(old_count|lock_flag_value);
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
break;
}
old_count=current;
}
if(old_count&lock_flag_value)
{
bool lock_acquired=false;
void* const sem=get_event();
do
{
if(win32::WaitForSingleObject(sem,::boost::detail::get_milliseconds_until(wait_until))!=0)
{
BOOST_INTERLOCKED_DECREMENT(&active_count);
return false;
}
old_count&=~lock_flag_value;
old_count|=event_set_flag_value;
for(;;)
{
long const new_count=((old_count&lock_flag_value)?old_count:((old_count-1)|lock_flag_value))&~event_set_flag_value;
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(&active_count,new_count,old_count);
if(current==old_count)
{
break;
}
old_count=current;
}
lock_acquired=!(old_count&lock_flag_value);
}
while(!lock_acquired);
}
return true;
}
template<typename Duration>
bool timed_lock(Duration const& timeout)
{
return timed_lock(get_system_time()+timeout);
}
bool timed_lock(boost::xtime const& timeout)
{
return timed_lock(system_time(timeout));
}
void unlock()
{
long const offset=lock_flag_value;
long const old_count=BOOST_INTERLOCKED_EXCHANGE_ADD(&active_count,lock_flag_value);
if(!(old_count&event_set_flag_value) && (old_count>offset))
{
if(!win32::interlocked_bit_test_and_set(&active_count,event_set_flag_bit))
{
win32::SetEvent(get_event());
}
}
}
private:
void* get_event()
{
void* current_event=::boost::detail::interlocked_read_acquire(&event);
if(!current_event)
{
void* const new_event=win32::create_anonymous_event(win32::auto_reset_event,win32::event_initially_reset);
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4311)
#pragma warning(disable:4312)
#endif
void* const old_event=BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(&event,new_event,0);
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
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}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,418 @@
#ifndef BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
#define BOOST_THREAD_CONDITION_VARIABLE_WIN32_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007-8 Anthony Williams
#include <boost/thread/mutex.hpp>
#include "thread_primitives.hpp"
#include <limits.h>
#include <boost/assert.hpp>
#include <algorithm>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include "interlocked_read.hpp"
#include <boost/thread/xtime.hpp>
#include <vector>
#include <boost/intrusive_ptr.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
class basic_cv_list_entry;
void intrusive_ptr_add_ref(basic_cv_list_entry * p);
void intrusive_ptr_release(basic_cv_list_entry * p);
class basic_cv_list_entry
{
private:
detail::win32::handle_manager semaphore;
detail::win32::handle_manager wake_sem;
long waiters;
bool notified;
long references;
basic_cv_list_entry(basic_cv_list_entry&);
void operator=(basic_cv_list_entry&);
public:
explicit basic_cv_list_entry(detail::win32::handle_manager const& wake_sem_):
semaphore(detail::win32::create_anonymous_semaphore(0,LONG_MAX)),
wake_sem(wake_sem_.duplicate()),
waiters(1),notified(false),references(0)
{}
static bool no_waiters(boost::intrusive_ptr<basic_cv_list_entry> const& entry)
{
return !detail::interlocked_read_acquire(&entry->waiters);
}
void add_waiter()
{
BOOST_INTERLOCKED_INCREMENT(&waiters);
}
void remove_waiter()
{
BOOST_INTERLOCKED_DECREMENT(&waiters);
}
void release(unsigned count_to_release)
{
notified=true;
detail::win32::ReleaseSemaphore(semaphore,count_to_release,0);
}
void release_waiters()
{
release(detail::interlocked_read_acquire(&waiters));
}
bool is_notified() const
{
return notified;
}
bool wait(timeout wait_until)
{
return this_thread::interruptible_wait(semaphore,wait_until);
}
bool woken()
{
unsigned long const woken_result=detail::win32::WaitForSingleObject(wake_sem,0);
BOOST_ASSERT((woken_result==detail::win32::timeout) || (woken_result==0));
return woken_result==0;
}
friend void intrusive_ptr_add_ref(basic_cv_list_entry * p);
friend void intrusive_ptr_release(basic_cv_list_entry * p);
};
inline void intrusive_ptr_add_ref(basic_cv_list_entry * p)
{
BOOST_INTERLOCKED_INCREMENT(&p->references);
}
inline void intrusive_ptr_release(basic_cv_list_entry * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
{
delete p;
}
}
class basic_condition_variable
{
boost::mutex internal_mutex;
long total_count;
unsigned active_generation_count;
typedef basic_cv_list_entry list_entry;
typedef boost::intrusive_ptr<list_entry> entry_ptr;
typedef std::vector<entry_ptr> generation_list;
generation_list generations;
detail::win32::handle_manager wake_sem;
void wake_waiters(long count_to_wake)
{
detail::interlocked_write_release(&total_count,total_count-count_to_wake);
detail::win32::ReleaseSemaphore(wake_sem,count_to_wake,0);
}
template<typename lock_type>
struct relocker
{
lock_type& lock;
bool unlocked;
relocker(lock_type& lock_):
lock(lock_),unlocked(false)
{}
void unlock()
{
lock.unlock();
unlocked=true;
}
~relocker()
{
if(unlocked)
{
lock.lock();
}
}
private:
relocker(relocker&);
void operator=(relocker&);
};
entry_ptr get_wait_entry()
{
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
BOOST_ASSERT(wake_sem);
}
detail::interlocked_write_release(&total_count,total_count+1);
if(generations.empty() || generations.back()->is_notified())
{
entry_ptr new_entry(new list_entry(wake_sem));
generations.push_back(new_entry);
return new_entry;
}
else
{
generations.back()->add_waiter();
return generations.back();
}
}
struct entry_manager
{
entry_ptr const entry;
entry_manager(entry_ptr const& entry_):
entry(entry_)
{}
~entry_manager()
{
entry->remove_waiter();
}
list_entry* operator->()
{
return entry.get();
}
private:
void operator=(entry_manager&);
entry_manager(entry_manager&);
};
protected:
template<typename lock_type>
bool do_wait(lock_type& lock,timeout wait_until)
{
relocker<lock_type> locker(lock);
entry_manager entry(get_wait_entry());
locker.unlock();
bool woken=false;
while(!woken)
{
if(!entry->wait(wait_until))
{
return false;
}
woken=entry->woken();
}
return woken;
}
template<typename lock_type,typename predicate_type>
bool do_wait(lock_type& m,timeout const& wait_until,predicate_type pred)
{
while (!pred())
{
if(!do_wait(m, wait_until))
return pred();
}
return true;
}
basic_condition_variable(const basic_condition_variable& other);
basic_condition_variable& operator=(const basic_condition_variable& other);
public:
basic_condition_variable():
total_count(0),active_generation_count(0),wake_sem(0)
{}
~basic_condition_variable()
{}
void notify_one()
{
if(detail::interlocked_read_acquire(&total_count))
{
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
if(!total_count)
{
return;
}
wake_waiters(1);
for(generation_list::iterator it=generations.begin(),
end=generations.end();
it!=end;++it)
{
(*it)->release(1);
}
generations.erase(std::remove_if(generations.begin(),generations.end(),&basic_cv_list_entry::no_waiters),generations.end());
}
}
void notify_all()
{
if(detail::interlocked_read_acquire(&total_count))
{
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
if(!total_count)
{
return;
}
wake_waiters(total_count);
for(generation_list::iterator it=generations.begin(),
end=generations.end();
it!=end;++it)
{
(*it)->release_waiters();
}
generations.clear();
wake_sem=detail::win32::handle(0);
}
}
};
}
class condition_variable:
private detail::basic_condition_variable
{
private:
condition_variable(condition_variable&);
void operator=(condition_variable&);
public:
condition_variable()
{}
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
void wait(unique_lock<mutex>& m)
{
do_wait(m,detail::timeout::sentinel());
}
template<typename predicate_type>
void wait(unique_lock<mutex>& m,predicate_type pred)
{
while(!pred()) wait(m);
}
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
{
return do_wait(m,wait_until);
}
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename duration_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until,predicate_type pred)
{
return do_wait(m,wait_until,pred);
}
template<typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename duration_type,typename predicate_type>
bool timed_wait(unique_lock<mutex>& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};
class condition_variable_any:
private detail::basic_condition_variable
{
private:
condition_variable_any(condition_variable_any&);
void operator=(condition_variable_any&);
public:
condition_variable_any()
{}
using detail::basic_condition_variable::notify_one;
using detail::basic_condition_variable::notify_all;
template<typename lock_type>
void wait(lock_type& m)
{
do_wait(m,detail::timeout::sentinel());
}
template<typename lock_type,typename predicate_type>
void wait(lock_type& m,predicate_type pred)
{
while(!pred()) wait(m);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
{
return do_wait(m,wait_until);
}
template<typename lock_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until)
{
return do_wait(m,system_time(wait_until));
}
template<typename lock_type,typename duration_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration)
{
return do_wait(m,wait_duration.total_milliseconds());
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::system_time const& wait_until,predicate_type pred)
{
return do_wait(m,wait_until,pred);
}
template<typename lock_type,typename predicate_type>
bool timed_wait(lock_type& m,boost::xtime const& wait_until,predicate_type pred)
{
return do_wait(m,system_time(wait_until),pred);
}
template<typename lock_type,typename duration_type,typename predicate_type>
bool timed_wait(lock_type& m,duration_type const& wait_duration,predicate_type pred)
{
return do_wait(m,wait_duration.total_milliseconds(),pred);
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,80 @@
#ifndef BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
#define BOOST_THREAD_DETAIL_INTERLOCKED_READ_WIN32_HPP
// interlocked_read_win32.hpp
//
// (C) Copyright 2005-8 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/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
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;
}
inline void interlocked_write_release(long volatile* x,long value)
{
_ReadWriteBarrier();
*x=value;
}
inline void interlocked_write_release(void* volatile* x,void* value)
{
_ReadWriteBarrier();
*x=value;
}
}
}
#else
namespace boost
{
namespace detail
{
inline long interlocked_read_acquire(long volatile* x)
{
return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
}
inline void* interlocked_read_acquire(void* volatile* x)
{
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
}
inline void interlocked_write_release(long volatile* x,long value)
{
BOOST_INTERLOCKED_EXCHANGE(x,value);
}
inline void interlocked_write_release(void* volatile* x,void* value)
{
BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
}
}
}
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,65 @@
#ifndef BOOST_THREAD_WIN32_MUTEX_HPP
#define BOOST_THREAD_WIN32_MUTEX_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 "basic_timed_mutex.hpp"
#include <boost/utility.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
typedef ::boost::detail::basic_timed_mutex underlying_mutex;
}
class mutex:
boost::noncopyable,
public ::boost::detail::underlying_mutex
{
public:
mutex()
{
initialize();
}
~mutex()
{
destroy();
}
typedef unique_lock<mutex> scoped_lock;
typedef detail::try_lock_wrapper<mutex> scoped_try_lock;
};
typedef mutex try_mutex;
class timed_mutex:
boost::noncopyable,
public ::boost::detail::basic_timed_mutex
{
public:
timed_mutex()
{
initialize();
}
~timed_mutex()
{
destroy();
}
typedef unique_lock<timed_mutex> scoped_timed_lock;
typedef detail::try_lock_wrapper<timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,136 @@
#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>
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std
{
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_)
{
BOOST_VERIFY(!win32::WaitForSingleObject(mutex_handle,win32::infinite));
}
~win32_mutex_scoped_lock()
{
BOOST_VERIFY(win32::ReleaseMutex(mutex_handle)!=0);
}
private:
void operator=(win32_mutex_scoped_lock&);
};
#ifdef BOOST_NO_ANSI_APIS
template <class I>
void int_to_string(I p, wchar_t* buf)
{
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
{
*buf = L'A' + static_cast<wchar_t>((p >> (i*4)) & 0x0f);
}
*buf = 0;
}
#else
template <class I>
void int_to_string(I p, char* buf)
{
for(unsigned i=0; i < sizeof(I)*2; ++i,++buf)
{
*buf = 'A' + static_cast<char>((p >> (i*4)) & 0x0f);
}
*buf = 0;
}
#endif
// 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(void* flag_address)
{
#ifdef BOOST_NO_ANSI_APIS
typedef wchar_t char_type;
static const char_type fixed_mutex_name[]=L"{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
#else
typedef char char_type;
static const char_type fixed_mutex_name[]="{C15730E2-145C-4c5e-B005-3BC753F42475}-once-flag";
#endif
unsigned const once_mutex_name_fixed_buffer_size=sizeof(fixed_mutex_name)/sizeof(char_type);
unsigned const once_mutex_name_fixed_length=once_mutex_name_fixed_buffer_size-1;
unsigned const once_mutex_name_length=once_mutex_name_fixed_buffer_size+sizeof(void*)*2+sizeof(unsigned long)*2;
char_type mutex_name[once_mutex_name_length];
std::memcpy(mutex_name,fixed_mutex_name,sizeof(fixed_mutex_name));
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);
#ifdef BOOST_NO_ANSI_APIS
return win32::CreateMutexW(0, 0, mutex_name);
#else
return win32::CreateMutexA(0, 0, mutex_name);
#endif
}
}
template<typename Function>
void call_once(once_flag& flag,Function f)
{
// Try for a quick win: if the procedure 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)
{
void* const mutex_handle(::boost::detail::create_once_mutex(&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);
}
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,64 @@
#ifndef BOOST_RECURSIVE_MUTEX_WIN32_HPP
#define BOOST_RECURSIVE_MUTEX_WIN32_HPP
// recursive_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/utility.hpp>
#include "basic_recursive_mutex.hpp"
#include <boost/thread/exceptions.hpp>
#include <boost/thread/locks.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class recursive_mutex:
boost::noncopyable,
public ::boost::detail::basic_recursive_mutex
{
public:
recursive_mutex()
{
::boost::detail::basic_recursive_mutex::initialize();
}
~recursive_mutex()
{
::boost::detail::basic_recursive_mutex::destroy();
}
typedef unique_lock<recursive_mutex> scoped_lock;
typedef detail::try_lock_wrapper<recursive_mutex> scoped_try_lock;
};
typedef recursive_mutex recursive_try_mutex;
class recursive_timed_mutex:
boost::noncopyable,
public ::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();
}
typedef unique_lock<recursive_timed_mutex> scoped_timed_lock;
typedef detail::try_lock_wrapper<recursive_timed_mutex> scoped_try_lock;
typedef scoped_timed_lock scoped_lock;
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,566 @@
#ifndef BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
#define BOOST_THREAD_WIN32_SHARED_MUTEX_HPP
// (C) Copyright 2006-8 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/static_assert.hpp>
#include <limits.h>
#include <boost/utility.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost
{
class shared_mutex:
private boost::noncopyable
{
private:
struct state_data
{
unsigned shared_count:11,
shared_waiting:11,
exclusive:1,
upgrade:1,
exclusive_waiting:7,
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;
detail::win32::handle semaphores[2];
detail::win32::handle &unlock_sem;
detail::win32::handle &exclusive_sem;
detail::win32::handle upgrade_sem;
void release_waiters(state_data old_state)
{
if(old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(exclusive_sem,1,0)!=0);
}
if(old_state.shared_waiting || old_state.exclusive_waiting)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(unlock_sem,old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
}
}
public:
shared_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);
upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
state_data state_={0};
state=state_;
}
~shared_mutex()
{
detail::win32::CloseHandle(upgrade_sem);
detail::win32::CloseHandle(unlock_sem);
detail::win32::CloseHandle(exclusive_sem);
}
bool try_lock_shared()
{
state_data old_state=state;
for(;;)
{
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;
}
return !(old_state.exclusive| old_state.exclusive_waiting_blocked);
}
void lock_shared()
{
BOOST_VERIFY(timed_lock_shared(::boost::detail::get_system_time_sentinel()));
}
template<typename TimeDuration>
bool timed_lock_shared(TimeDuration const & relative_time)
{
return timed_lock_shared(get_system_time()+relative_time);
}
bool timed_lock_shared(boost::system_time const& wait_until)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
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;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
unsigned long const res=detail::win32::WaitForSingleObject(unlock_sem,::boost::detail::get_milliseconds_until(wait_until));
if(res==detail::win32::timeout)
{
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked)
{
if(new_state.shared_waiting)
{
--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;
}
if(!(old_state.exclusive| old_state.exclusive_waiting_blocked))
{
return true;
}
return false;
}
BOOST_ASSERT(res==0);
}
}
void unlock_shared()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
if(new_state.upgrade)
{
new_state.upgrade=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.upgrade)
{
BOOST_VERIFY(detail::win32::ReleaseSemaphore(upgrade_sem,1,0)!=0);
}
else
{
release_waiters(old_state);
}
}
break;
}
old_state=current_state;
}
}
void lock()
{
BOOST_VERIFY(timed_lock(::boost::detail::get_system_time_sentinel()));
}
template<typename TimeDuration>
bool timed_lock(TimeDuration const & relative_time)
{
return timed_lock(get_system_time()+relative_time);
}
bool try_lock()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
return false;
}
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;
}
return true;
}
bool timed_lock(boost::system_time const& wait_until)
{
for(;;)
{
state_data old_state=state;
for(;;)
{
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;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
if(wait_res==detail::win32::timeout)
{
for(;;)
{
state_data new_state=old_state;
if(new_state.shared_count || new_state.exclusive)
{
if(new_state.exclusive_waiting)
{
if(!--new_state.exclusive_waiting)
{
new_state.exclusive_waiting_blocked=false;
}
}
}
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;
}
if(!old_state.shared_count && !old_state.exclusive)
{
return true;
}
return false;
}
BOOST_ASSERT(wait_res<2);
}
}
void unlock()
{
state_data old_state=state;
for(;;)
{
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;
}
release_waiters(old_state);
}
void lock_upgrade()
{
for(;;)
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
{
++new_state.shared_waiting;
}
else
{
++new_state.shared_count;
new_state.upgrade=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
if(!(old_state.exclusive|| old_state.exclusive_waiting_blocked|| old_state.upgrade))
{
return;
}
BOOST_VERIFY(!detail::win32::WaitForSingleObject(unlock_sem,detail::win32::infinite));
}
}
bool try_lock_upgrade()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
if(new_state.exclusive || new_state.exclusive_waiting_blocked || new_state.upgrade)
{
return false;
}
else
{
++new_state.shared_count;
new_state.upgrade=true;
}
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
if(current_state==old_state)
{
break;
}
old_state=current_state;
}
return true;
}
void unlock_upgrade()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
new_state.upgrade=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;
}
}
void unlock_upgrade_and_lock()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
bool const last_reader=!--new_state.shared_count;
if(last_reader)
{
new_state.upgrade=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)
{
BOOST_VERIFY(!detail::win32::WaitForSingleObject(upgrade_sem,detail::win32::infinite));
}
break;
}
old_state=current_state;
}
}
void unlock_and_lock_upgrade()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
new_state.exclusive=false;
new_state.upgrade=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;
}
release_waiters(old_state);
}
void unlock_and_lock_shared()
{
state_data old_state=state;
for(;;)
{
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;
}
release_waiters(old_state);
}
void unlock_upgrade_and_lock_shared()
{
state_data old_state=state;
for(;;)
{
state_data new_state=old_state;
new_state.upgrade=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;
}
release_waiters(old_state);
}
};
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,178 @@
#ifndef BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
#define BOOST_THREAD_PTHREAD_THREAD_DATA_HPP
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2008 Anthony Williams
#include <boost/thread/detail/config.hpp>
#include <boost/intrusive_ptr.hpp>
#include <boost/thread/thread_time.hpp>
#include "thread_primitives.hpp"
#include "thread_heap_alloc.hpp"
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
struct thread_exit_callback_node;
struct tss_data_node;
struct thread_data_base;
void intrusive_ptr_add_ref(thread_data_base * p);
void intrusive_ptr_release(thread_data_base * p);
struct thread_data_base
{
long count;
detail::win32::handle_manager thread_handle;
detail::win32::handle_manager interruption_handle;
boost::detail::thread_exit_callback_node* thread_exit_callbacks;
boost::detail::tss_data_node* tss_data;
bool interruption_enabled;
unsigned id;
thread_data_base():
count(0),thread_handle(detail::win32::invalid_handle_value),
interruption_handle(create_anonymous_event(detail::win32::manual_reset_event,detail::win32::event_initially_reset)),
thread_exit_callbacks(0),tss_data(0),
interruption_enabled(true),
id(0)
{}
virtual ~thread_data_base()
{}
friend void intrusive_ptr_add_ref(thread_data_base * p)
{
BOOST_INTERLOCKED_INCREMENT(&p->count);
}
friend void intrusive_ptr_release(thread_data_base * p)
{
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
{
detail::heap_delete(p);
}
}
void interrupt()
{
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
}
typedef detail::win32::handle native_handle_type;
virtual void run()=0;
};
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
struct timeout
{
unsigned long start;
uintmax_t milliseconds;
bool relative;
boost::system_time abs_time;
static unsigned long const max_non_infinite_wait=0xfffffffe;
timeout(uintmax_t milliseconds_):
start(win32::GetTickCount()),
milliseconds(milliseconds_),
relative(true),
abs_time(boost::get_system_time())
{}
timeout(boost::system_time const& abs_time_):
start(win32::GetTickCount()),
milliseconds(0),
relative(false),
abs_time(abs_time_)
{}
struct remaining_time
{
bool more;
unsigned long milliseconds;
remaining_time(uintmax_t remaining):
more(remaining>max_non_infinite_wait),
milliseconds(more?max_non_infinite_wait:(unsigned long)remaining)
{}
};
remaining_time remaining_milliseconds() const
{
if(is_sentinel())
{
return remaining_time(win32::infinite);
}
else if(relative)
{
unsigned long const now=win32::GetTickCount();
unsigned long const elapsed=now-start;
return remaining_time((elapsed<milliseconds)?(milliseconds-elapsed):0);
}
else
{
system_time const now=get_system_time();
if(abs_time<=now)
{
return remaining_time(0);
}
return remaining_time((abs_time-now).total_milliseconds()+1);
}
}
bool is_sentinel() const
{
return milliseconds==~uintmax_t(0);
}
static timeout sentinel()
{
return timeout(sentinel_type());
}
private:
struct sentinel_type
{};
explicit timeout(sentinel_type):
start(0),milliseconds(~uintmax_t(0)),relative(true)
{}
};
}
namespace this_thread
{
void BOOST_THREAD_DECL yield();
bool BOOST_THREAD_DECL interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time);
inline void interruptible_wait(unsigned long milliseconds)
{
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
}
inline void interruptible_wait(system_time const& abs_time)
{
interruptible_wait(detail::win32::invalid_handle_value,abs_time);
}
template<typename TimeDuration>
inline void sleep(TimeDuration const& rel_time)
{
interruptible_wait(static_cast<unsigned long>(rel_time.total_milliseconds()));
}
inline void sleep(system_time const& abs_time)
{
interruptible_wait(abs_time);
}
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,397 @@
// Distributed under the 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 THREAD_HEAP_ALLOC_HPP
#define THREAD_HEAP_ALLOC_HPP
#include <new>
#include "thread_primitives.hpp"
#include <stdexcept>
#include <boost/assert.hpp>
#if defined( BOOST_USE_WINDOWS_H )
# include <windows.h>
namespace boost
{
namespace detail
{
namespace win32
{
using ::GetProcessHeap;
using ::HeapAlloc;
using ::HeapFree;
}
}
}
#else
# ifdef HeapAlloc
# undef HeapAlloc
# endif
namespace boost
{
namespace detail
{
namespace win32
{
extern "C"
{
__declspec(dllimport) handle __stdcall GetProcessHeap();
__declspec(dllimport) void* __stdcall HeapAlloc(handle,unsigned long,ulong_ptr);
__declspec(dllimport) int __stdcall HeapFree(handle,unsigned long,void*);
}
}
}
}
#endif
#include <boost/config/abi_prefix.hpp>
namespace boost
{
namespace detail
{
inline BOOST_THREAD_DECL void* allocate_raw_heap_memory(unsigned size)
{
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
if(!heap_memory)
{
throw std::bad_alloc();
}
return heap_memory;
}
inline BOOST_THREAD_DECL void free_raw_heap_memory(void* heap_memory)
{
BOOST_VERIFY(detail::win32::HeapFree(detail::win32::GetProcessHeap(),0,heap_memory)!=0);
}
template<typename T>
inline T* heap_new()
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T();
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
#ifdef BOOST_HAS_RVALUE_REFS
template<typename T,typename A1>
inline T* heap_new(A1&& a1)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1&& a1,A2&& a2)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1&& a1,A2&& a2,A3&& a3,A4&& a4)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(static_cast<A1&&>(a1),static_cast<A2&&>(a2),
static_cast<A3&&>(a3),static_cast<A4&&>(a4));
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
#else
template<typename T,typename A1>
inline T* heap_new_impl(A1 a1)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2>
inline T* heap_new_impl(A1 a1,A2 a2)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2,a3);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new_impl(A1 a1,A2 a2,A3 a3,A4 a4)
{
void* const heap_memory=allocate_raw_heap_memory(sizeof(T));
try
{
T* const data=new (heap_memory) T(a1,a2,a3,a4);
return data;
}
catch(...)
{
free_raw_heap_memory(heap_memory);
throw;
}
}
template<typename T,typename A1>
inline T* heap_new(A1 const& a1)
{
return heap_new_impl<T,A1 const&>(a1);
}
template<typename T,typename A1>
inline T* heap_new(A1& a1)
{
return heap_new_impl<T,A1&>(a1);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2 const& a2)
{
return heap_new_impl<T,A1 const&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2 const& a2)
{
return heap_new_impl<T,A1&,A2 const&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1 const& a1,A2& a2)
{
return heap_new_impl<T,A1 const&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2>
inline T* heap_new(A1& a1,A2& a2)
{
return heap_new_impl<T,A1&,A2&>(a1,a2);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3)
{
return heap_new_impl<T,A1&,A2&,A3 const&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2 const&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1 const&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3>
inline T* heap_new(A1& a1,A2& a2,A3& a3)
{
return heap_new_impl<T,A1&,A2&,A3&>(a1,a2,a3);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4 const& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4 const&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3 const& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3 const&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2 const& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2 const&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1 const& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1 const&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
template<typename T,typename A1,typename A2,typename A3,typename A4>
inline T* heap_new(A1& a1,A2& a2,A3& a3,A4& a4)
{
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
}
#endif
template<typename T>
inline void heap_delete(T* data)
{
data->~T();
free_raw_heap_memory(data);
}
template<typename T>
struct do_heap_delete
{
void operator()(T* data) const
{
detail::heap_delete(data);
}
};
}
}
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -0,0 +1,398 @@
#ifndef BOOST_WIN32_THREAD_PRIMITIVES_HPP
#define BOOST_WIN32_THREAD_PRIMITIVES_HPP
// win32_thread_primitives.hpp
//
// (C) Copyright 2005-7 Anthony Williams
// (C) Copyright 2007 David Deakins
//
// Distributed under the 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>
#include <boost/detail/interlocked.hpp>
#include <algorithm>
#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;
handle const invalid_handle_value=INVALID_HANDLE_VALUE;
# ifdef BOOST_NO_ANSI_APIS
using ::CreateMutexW;
using ::CreateEventW;
using ::CreateSemaphoreW;
# else
using ::CreateMutexA;
using ::CreateEventA;
using ::CreateSemaphoreA;
# endif
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 ::Sleep;
using ::QueueUserAPC;
using ::GetTickCount;
}
}
}
#elif defined( WIN32 ) || defined( _WIN32 ) || defined( __WIN32__ )
# ifdef UNDER_CE
# ifndef WINAPI
# ifndef _WIN32_WCE_EMULATION
# define WINAPI __cdecl // Note this doesn't match the desktop definition
# else
# define WINAPI __stdcall
# endif
# endif
# ifdef __cplusplus
extern "C" {
# endif
typedef int BOOL;
typedef unsigned long DWORD;
typedef void* HANDLE;
# include <kfuncs.h>
# ifdef __cplusplus
}
# endif
# endif
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;
handle const invalid_handle_value=(handle)(-1);
extern "C"
{
struct _SECURITY_ATTRIBUTES;
# ifdef BOOST_NO_ANSI_APIS
__declspec(dllimport) void* __stdcall CreateMutexW(_SECURITY_ATTRIBUTES*,int,wchar_t const*);
__declspec(dllimport) void* __stdcall CreateSemaphoreW(_SECURITY_ATTRIBUTES*,long,long,wchar_t const*);
__declspec(dllimport) void* __stdcall CreateEventW(_SECURITY_ATTRIBUTES*,int,int,wchar_t const*);
# else
__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*);
# endif
__declspec(dllimport) int __stdcall CloseHandle(void*);
__declspec(dllimport) int __stdcall ReleaseMutex(void*);
__declspec(dllimport) unsigned long __stdcall WaitForSingleObject(void*,unsigned long);
__declspec(dllimport) unsigned long __stdcall WaitForMultipleObjects(unsigned long nCount,void* const * lpHandles,int bWaitAll,unsigned long dwMilliseconds);
__declspec(dllimport) int __stdcall ReleaseSemaphore(void*,long,long*);
__declspec(dllimport) int __stdcall DuplicateHandle(void*,void*,void*,void**,unsigned long,int,unsigned long);
__declspec(dllimport) unsigned long __stdcall SleepEx(unsigned long,int);
__declspec(dllimport) void __stdcall Sleep(unsigned long);
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) unsigned long __stdcall GetTickCount();
# ifndef UNDER_CE
__declspec(dllimport) unsigned long __stdcall GetCurrentProcessId();
__declspec(dllimport) unsigned long __stdcall GetCurrentThreadId();
__declspec(dllimport) void* __stdcall GetCurrentThread();
__declspec(dllimport) void* __stdcall GetCurrentProcess();
__declspec(dllimport) int __stdcall SetEvent(void*);
__declspec(dllimport) int __stdcall ResetEvent(void*);
# else
using ::GetCurrentProcessId;
using ::GetCurrentThreadId;
using ::GetCurrentThread;
using ::GetCurrentProcess;
using ::SetEvent;
using ::ResetEvent;
# endif
}
}
}
}
#else
# error "Win32 functions not available"
#endif
#include <boost/config/abi_prefix.hpp>
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)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=win32::CreateEventA(0,type,state,0);
#else
handle const res=win32::CreateEventW(0,type,state,0);
#endif
if(!res)
{
throw thread_resource_error();
}
return res;
}
inline handle create_anonymous_semaphore(long initial_count,long max_count)
{
#if !defined(BOOST_NO_ANSI_APIS)
handle const res=CreateSemaphoreA(0,initial_count,max_count,0);
#else
handle const res=CreateSemaphoreW(0,initial_count,max_count,0);
#endif
if(!res)
{
throw thread_resource_error();
}
return res;
}
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;
if(!success)
{
throw thread_resource_error();
}
return new_handle;
}
inline void release_semaphore(handle semaphore,long count)
{
BOOST_VERIFY(ReleaseSemaphore(semaphore,count,0)!=0);
}
class handle_manager
{
private:
handle handle_to_manage;
handle_manager(handle_manager&);
handle_manager& operator=(handle_manager&);
void cleanup()
{
if(handle_to_manage && handle_to_manage!=invalid_handle_value)
{
BOOST_VERIFY(CloseHandle(handle_to_manage));
}
}
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;
return *this;
}
operator handle() const
{
return handle_to_manage;
}
handle duplicate() const
{
return duplicate_handle(handle_to_manage);
}
void swap(handle_manager& other)
{
std::swap(handle_to_manage,other.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();
}
};
}
}
}
#if defined(BOOST_MSVC) && (_MSC_VER>=1400) && !defined(UNDER_CE)
namespace boost
{
namespace detail
{
namespace win32
{
#if _MSC_VER==1400
extern "C" unsigned char _interlockedbittestandset(long *a,long b);
extern "C" unsigned char _interlockedbittestandreset(long *a,long b);
#else
extern "C" unsigned char _interlockedbittestandset(volatile long *a,long b);
extern "C" unsigned char _interlockedbittestandreset(volatile long *a,long b);
#endif
#pragma intrinsic(_interlockedbittestandset)
#pragma intrinsic(_interlockedbittestandreset)
inline bool interlocked_bit_test_and_set(long* x,long bit)
{
return _interlockedbittestandset(x,bit)!=0;
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
{
return _interlockedbittestandreset(x,bit)!=0;
}
}
}
}
#define BOOST_THREAD_BTS_DEFINED
#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86)
namespace boost
{
namespace detail
{
namespace win32
{
inline bool interlocked_bit_test_and_set(long* x,long bit)
{
__asm {
mov eax,bit;
mov edx,x;
lock bts [edx],eax;
setc al;
};
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
{
__asm {
mov eax,bit;
mov edx,x;
lock btr [edx],eax;
setc al;
};
}
}
}
}
#define BOOST_THREAD_BTS_DEFINED
#endif
#ifndef BOOST_THREAD_BTS_DEFINED
namespace boost
{
namespace detail
{
namespace win32
{
inline bool interlocked_bit_test_and_set(long* x,long bit)
{
long const value=1<<bit;
long old=*x;
do
{
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old|value,old);
if(current==old)
{
break;
}
old=current;
}
while(true);
return (old&value)!=0;
}
inline bool interlocked_bit_test_and_reset(long* x,long bit)
{
long const value=1<<bit;
long old=*x;
do
{
long const current=BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,old&~value,old);
if(current==old)
{
break;
}
old=current;
}
while(true);
return (old&value)!=0;
}
}
}
}
#endif
#include <boost/config/abi_suffix.hpp>
#endif

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007-8 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)
@@ -10,6 +11,10 @@
#include <boost/thread/detail/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <boost/config/abi_prefix.hpp>
namespace boost {
@@ -37,9 +42,40 @@ struct xtime
xtime_sec_t sec;
xtime_nsec_t nsec;
operator system_time() const
{
return boost::posix_time::from_time_t(0)+
boost::posix_time::seconds(static_cast<long>(sec))+
#ifdef BOOST_DATE_TIME_HAS_NANOSECONDS
boost::posix_time::nanoseconds(nsec);
#else
boost::posix_time::microseconds((nsec+500)/1000);
#endif
}
};
int BOOST_THREAD_DECL xtime_get(struct xtime* xtp, int clock_type);
inline xtime get_xtime(boost::system_time const& abs_time)
{
xtime res;
boost::posix_time::time_duration const time_since_epoch=abs_time-boost::posix_time::from_time_t(0);
res.sec=static_cast<xtime::xtime_sec_t>(time_since_epoch.total_seconds());
res.nsec=static_cast<xtime::xtime_nsec_t>(time_since_epoch.fractional_seconds()*(1000000000/time_since_epoch.ticks_per_second()));
return res;
}
inline int xtime_get(struct xtime* xtp, int clock_type)
{
if (clock_type == TIME_UTC)
{
*xtp=get_xtime(get_system_time());
return clock_type;
}
return 0;
}
inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
{
@@ -51,4 +87,6 @@ inline int xtime_cmp(const xtime& xt1, const xtime& xt2)
} // namespace boost
#include <boost/config/abi_suffix.hpp>
#endif //BOOST_XTIME_WEK070601_HPP

View File

@@ -1,6 +1,6 @@
<!-- Copyright (c) 2002-2003 William E. Kempf.
Subject to the Boost Software License, Version 1.0.
(See accompanying file LICENSE-1.0 or http://www.boost.org/LICENSE-1.0)
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
-->
<html>

View File

@@ -342,6 +342,9 @@ condition_impl::condition_impl()
res = pthread_cond_init(&m_condition, 0);
if (res != 0)
throw thread_resource_error();
res = pthread_mutex_init(&m_mutex, 0);
if (res != 0)
throw thread_resource_error();
}
condition_impl::~condition_impl()
@@ -349,20 +352,30 @@ condition_impl::~condition_impl()
int res = 0;
res = pthread_cond_destroy(&m_condition);
assert(res == 0);
res = pthread_mutex_destroy(&m_mutex);
assert(res == 0);
}
void condition_impl::notify_one()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
res = pthread_cond_signal(&m_condition);
assert(res == 0);
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
void condition_impl::notify_all()
{
int res = 0;
res = pthread_mutex_lock(&m_mutex);
assert(res == 0);
res = pthread_cond_broadcast(&m_condition);
assert(res == 0);
res = pthread_mutex_unlock(&m_mutex);
assert(res == 0);
}
void condition_impl::do_wait(pthread_mutex_t* pmutex)

View File

@@ -1,561 +0,0 @@
// 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/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/exceptions.hpp>
#include <boost/limits.hpp>
#include <string>
#include <stdexcept>
#include <cassert>
#include "timeconv.inl"
#if defined(BOOST_HAS_WINTHREADS)
# include <new>
# include <boost/thread/once.hpp>
# include <windows.h>
# include <time.h>
# include "mutex.inl"
#elif defined(BOOST_HAS_PTHREADS)
# include <errno.h>
#elif defined(BOOST_HAS_MPTASKS)
# include <MacErrors.h>
# include "mac/init.hpp"
# include "mac/safe.hpp"
#endif
namespace boost {
#if defined(BOOST_HAS_WINTHREADS)
mutex::mutex()
: m_mutex(0)
, m_critical_section(false)
{
m_critical_section = true;
if (m_critical_section)
m_mutex = new_critical_section();
else
m_mutex = new_mutex(0);
}
mutex::~mutex()
{
if (m_critical_section)
delete_critical_section(m_mutex);
else
delete_mutex(m_mutex);
}
void mutex::do_lock()
{
if (m_critical_section)
wait_critical_section_infinite(m_mutex);
else
wait_mutex(m_mutex, INFINITE);
}
void mutex::do_unlock()
{
if (m_critical_section)
release_critical_section(m_mutex);
else
release_mutex(m_mutex);
}
void mutex::do_lock(cv_state&)
{
do_lock();
}
void mutex::do_unlock(cv_state&)
{
do_unlock();
}
try_mutex::try_mutex()
: m_mutex(0)
, m_critical_section(false)
{
m_critical_section = has_TryEnterCriticalSection();
if (m_critical_section)
m_mutex = new_critical_section();
else
m_mutex = new_mutex(0);
}
try_mutex::~try_mutex()
{
if (m_critical_section)
delete_critical_section(m_mutex);
else
delete_mutex(m_mutex);
}
void try_mutex::do_lock()
{
if (m_critical_section)
wait_critical_section_infinite(m_mutex);
else
wait_mutex(m_mutex, INFINITE);
}
bool try_mutex::do_trylock()
{
if (m_critical_section)
return wait_critical_section_try(m_mutex);
else
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
}
void try_mutex::do_unlock()
{
if (m_critical_section)
release_critical_section(m_mutex);
else
release_mutex(m_mutex);
}
void try_mutex::do_lock(cv_state&)
{
do_lock();
}
void try_mutex::do_unlock(cv_state&)
{
do_unlock();
}
timed_mutex::timed_mutex()
: m_mutex(0)
{
m_mutex = new_mutex(0);
}
timed_mutex::~timed_mutex()
{
delete_mutex(m_mutex);
}
void timed_mutex::do_lock()
{
wait_mutex(m_mutex, INFINITE);
}
bool timed_mutex::do_trylock()
{
return wait_mutex(m_mutex, 0) == WAIT_OBJECT_0;
}
bool timed_mutex::do_timedlock(const xtime& xt)
{
for (;;)
{
int milliseconds;
to_duration(xt, milliseconds);
int res = wait_mutex(m_mutex, milliseconds);
if (res == WAIT_TIMEOUT)
{
boost::xtime cur;
boost::xtime_get(&cur, boost::TIME_UTC);
if (boost::xtime_cmp(xt, cur) > 0)
continue;
}
return res == WAIT_OBJECT_0;
}
}
void timed_mutex::do_unlock()
{
release_mutex(m_mutex);
}
void timed_mutex::do_lock(cv_state&)
{
do_lock();
}
void timed_mutex::do_unlock(cv_state&)
{
do_unlock();
}
#elif defined(BOOST_HAS_PTHREADS)
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);
timespec ts;
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;
}
#elif defined(BOOST_HAS_MPTASKS)
using threads::mac::detail::safe_enter_critical_region;
mutex::mutex()
{
}
mutex::~mutex()
{
}
void mutex::do_lock()
{
OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
}
void mutex::do_unlock()
{
OSStatus lStatus = noErr;
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
}
void mutex::do_lock(cv_state& /*state*/)
{
do_lock();
}
void mutex::do_unlock(cv_state& /*state*/)
{
do_unlock();
}
try_mutex::try_mutex()
{
}
try_mutex::~try_mutex()
{
}
void try_mutex::do_lock()
{
OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
}
bool try_mutex::do_trylock()
{
OSStatus lStatus = noErr;
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
return lStatus == noErr;
}
void try_mutex::do_unlock()
{
OSStatus lStatus = noErr;
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
}
void try_mutex::do_lock(cv_state& /*state*/)
{
do_lock();
}
void try_mutex::do_unlock(cv_state& /*state*/)
{
do_unlock();
}
timed_mutex::timed_mutex()
{
}
timed_mutex::~timed_mutex()
{
}
void timed_mutex::do_lock()
{
OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, kDurationForever,
m_mutex_mutex);
assert(lStatus == noErr);
}
bool timed_mutex::do_trylock()
{
OSStatus lStatus = noErr;
lStatus = MPEnterCriticalRegion(m_mutex, kDurationImmediate);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
return(lStatus == noErr);
}
bool timed_mutex::do_timedlock(const xtime& xt)
{
int microseconds;
to_microduration(xt, microseconds);
Duration lDuration = kDurationMicrosecond * microseconds;
OSStatus lStatus = noErr;
lStatus = safe_enter_critical_region(m_mutex, lDuration, m_mutex_mutex);
assert(lStatus == noErr || lStatus == kMPTimeoutErr);
return(lStatus == noErr);
}
void timed_mutex::do_unlock()
{
OSStatus lStatus = noErr;
lStatus = MPExitCriticalRegion(m_mutex);
assert(lStatus == noErr);
}
void timed_mutex::do_lock(cv_state& /*state*/)
{
do_lock();
}
void timed_mutex::do_unlock(cv_state& /*state*/)
{
do_unlock();
}
#endif
} // namespace boost
// Change Log:
// 8 Feb 01 WEKEMPF Initial version.

View File

@@ -1,120 +0,0 @@
// 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)
// boostinspect:nounnamed
namespace {
#if defined(BOOST_HAS_WINTHREADS)
//:PREVENT THIS FROM BEING DUPLICATED
typedef BOOL (WINAPI* TryEnterCriticalSection_type)(LPCRITICAL_SECTION lpCriticalSection);
TryEnterCriticalSection_type g_TryEnterCriticalSection = 0;
boost::once_flag once_init_TryEnterCriticalSection = BOOST_ONCE_INIT;
void init_TryEnterCriticalSection()
{
//TryEnterCriticalSection is only available on WinNT 4.0 or later;
//it is not available on Win9x.
OSVERSIONINFO version_info = {sizeof(OSVERSIONINFO)};
::GetVersionEx(&version_info);
if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT &&
version_info.dwMajorVersion >= 4)
{
if (HMODULE kernel_module = GetModuleHandle(TEXT("KERNEL32.DLL")))
g_TryEnterCriticalSection = reinterpret_cast<TryEnterCriticalSection_type>(GetProcAddress(kernel_module, TEXT("TryEnterCriticalSection")));
}
}
inline bool has_TryEnterCriticalSection()
{
boost::call_once(init_TryEnterCriticalSection, once_init_TryEnterCriticalSection);
return g_TryEnterCriticalSection != 0;
}
inline HANDLE mutex_cast(void* p)
{
return reinterpret_cast<HANDLE>(p);
}
inline LPCRITICAL_SECTION critical_section_cast(void* p)
{
return reinterpret_cast<LPCRITICAL_SECTION>(p);
}
inline void* new_critical_section()
{
try
{
LPCRITICAL_SECTION critical_section = new CRITICAL_SECTION;
if (critical_section == 0) throw boost::thread_resource_error();
InitializeCriticalSection(critical_section);
return critical_section;
}
catch(...)
{
throw boost::thread_resource_error();
}
}
inline void* new_mutex(const char* name)
{
#if defined(BOOST_NO_ANSI_APIS)
USES_CONVERSION;
HANDLE mutex = CreateMutexW(0, 0, A2CW(name));
#else
HANDLE mutex = CreateMutexA(0, 0, name);
#endif
if (mutex == 0 || mutex == INVALID_HANDLE_VALUE) //:xxx (check for both values?)
throw boost::thread_resource_error();
return reinterpret_cast<void*>(mutex);
}
inline void delete_critical_section(void* mutex)
{
DeleteCriticalSection(critical_section_cast(mutex));
delete critical_section_cast(mutex);
}
inline void delete_mutex(void* mutex)
{
int res = 0;
res = CloseHandle(mutex_cast(mutex));
assert(res);
}
inline void wait_critical_section_infinite(void* mutex)
{
EnterCriticalSection(critical_section_cast(mutex)); //:xxx Can throw an exception under low memory conditions
}
inline bool wait_critical_section_try(void* mutex)
{
BOOL res = g_TryEnterCriticalSection(critical_section_cast(mutex));
return res != 0;
}
inline int wait_mutex(void* mutex, int time)
{
unsigned int res = 0;
res = WaitForSingleObject(mutex_cast(mutex), time);
//:xxx assert(res != WAIT_FAILED && res != WAIT_ABANDONED);
return res;
}
inline void release_critical_section(void* mutex)
{
LeaveCriticalSection(critical_section_cast(mutex));
}
inline void release_mutex(void* mutex)
{
BOOL res = FALSE;
res = ReleaseMutex(mutex_cast(mutex));
assert(res);
}
#endif
}

View File

@@ -1,213 +0,0 @@
// 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/detail/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/thread/once.hpp>
#include <cstdio>
#include <cassert>
#if defined(BOOST_HAS_WINTHREADS)
# if BOOST_WORKAROUND(__BORLANDC__,<= 0x551)
using std::size_t;
# endif
# include <windows.h>
# if defined(BOOST_NO_STRINGSTREAM)
# include <strstream>
class unfreezer
{
public:
unfreezer(std::ostrstream& s) : m_stream(s) {}
~unfreezer() { m_stream.freeze(false); }
private:
std::ostrstream& m_stream;
};
# else
# include <sstream>
# endif
#elif defined(BOOST_HAS_MPTASKS)
# include <Multiprocessing.h>
#endif
#ifdef BOOST_NO_STDC_NAMESPACE
namespace std { using ::sprintf; }
#endif
#if defined(BOOST_HAS_PTHREADS)
namespace {
pthread_key_t key;
pthread_once_t once = PTHREAD_ONCE_INIT;
typedef void (*once_callback)();
}
extern "C" {
static void key_init()
{
pthread_key_create(&key, 0);
}
static void do_once()
{
once_callback* cb = reinterpret_cast<once_callback*>(
pthread_getspecific(key));
(**cb)();
}
}
#elif defined(BOOST_HAS_MPTASKS)
namespace {
void *remote_call_proxy(void *pData)
{
std::pair<void (*)(), boost::once_flag *> &rData(
*reinterpret_cast<std::pair<void (*)(), boost::once_flag *> *>(pData));
if(*rData.second == false)
{
rData.first();
*rData.second = true;
}
return(NULL);
}
}
#elif defined(BOOST_HAS_WINTHREADS)
namespace {
// The signature for InterlockedCompareExchange has changed with the
// addition of Win64 support. I can't determine any (consistent and
// portable) way of using conditional compilation to detect this, so
// we use these type wrappers. Unfortunately, the various vendors
// use different calling conventions and other signature anamolies,
// and thus have unique types as well. This is known to work on VC6,
// VC7, Borland 5.5.2 and gcc 3.2. Are there other signatures for
// other platforms?
inline LONG ice_wrapper(LONG (__stdcall *ice)(LONG*, LONG, LONG),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (*ice)(const_cast<LONG*>(dest), exch, cmp);
}
inline LONG ice_wrapper(LONG (__stdcall *ice)(volatile LONG*, LONG, LONG),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (*ice)(dest, exch, cmp);
}
inline LONG ice_wrapper(LPVOID (__stdcall *ice)(LPVOID*, LPVOID, LPVOID),
volatile LONG* dest, LONG exch, LONG cmp)
{
return (LONG)(*ice)((LPVOID*)dest, (LPVOID)exch, (LPVOID)cmp);
}
// The friendly form of InterlockedCompareExchange that defers
// according to the above function type wrappers.
inline LONG compare_exchange(volatile LPLONG dest, LONG exch, LONG cmp)
{
#ifdef _WIN64
// Original patch from Anthony Williams.
// I (Roland Schwarz) am trying this for RC_1_34_0, since x64 regressions are
// currently not run on x64 platforms for HEAD
return InterlockedCompareExchange(dest, exch,cmp);
#else
return ice_wrapper(&InterlockedCompareExchange, dest, exch, cmp);
#endif
}
}
#endif
namespace boost {
void call_once(void (*func)(), once_flag& flag)
{
#if defined(BOOST_HAS_WINTHREADS)
if (compare_exchange(&flag, 1, 1) == 0)
{
#if defined(BOOST_NO_STRINGSTREAM)
std::ostrstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
<< std::hex
<< GetCurrentProcessId()
<< &flag
<< std::ends;
unfreezer unfreeze(strm);
# if defined (BOOST_NO_ANSI_APIS)
USES_CONVERSION;
HANDLE mutex = CreateMutexW(NULL, FALSE, A2CW(strm.str()));
# else
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str());
# endif
#else
# if defined (BOOST_NO_ANSI_APIS)
std::wostringstream strm;
strm << L"2AC1A572DB6944B0A65C38C4140AF2F4"
<< std::hex
<< GetCurrentProcessId()
<< &flag;
HANDLE mutex = CreateMutexW(NULL, FALSE, strm.str().c_str());
# else
std::ostringstream strm;
strm << "2AC1A572DB6944B0A65C38C4140AF2F4"
<< std::hex
<< GetCurrentProcessId()
<< &flag;
HANDLE mutex = CreateMutexA(NULL, FALSE, strm.str().c_str());
# endif
#endif
assert(mutex != NULL);
int res = 0;
res = WaitForSingleObject(mutex, INFINITE);
assert(res == WAIT_OBJECT_0);
if (compare_exchange(&flag, 1, 1) == 0)
{
try
{
func();
}
catch (...)
{
res = ReleaseMutex(mutex);
assert(res);
res = CloseHandle(mutex);
assert(res);
throw;
}
InterlockedExchange(&flag, 1);
}
res = ReleaseMutex(mutex);
assert(res);
res = CloseHandle(mutex);
assert(res);
}
#elif defined(BOOST_HAS_PTHREADS)
pthread_once(&once, &key_init);
pthread_setspecific(key, &func);
pthread_once(&flag, do_once);
#elif defined(BOOST_HAS_MPTASKS)
if(flag == false)
{
// all we do here is make a remote call to blue, as blue is not
// reentrant.
std::pair<void (*)(), once_flag *> sData(func, &flag);
MPRemoteCall(remote_call_proxy, &sData, kMPOwningProcessRemoteContext);
assert(flag == true);
}
#endif
}
}
// Change Log:
// 1 Aug 01 WEKEMPF Initial version.

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

@@ -0,0 +1,124 @@
// 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/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <cstring>
#include <string>
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;
}
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

51
src/pthread/once.cpp Normal file
View File

@@ -0,0 +1,51 @@
// Copyright (C) 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)
#define __STDC_CONSTANT_MACROS
#include <boost/thread/once.hpp>
#include <boost/assert.hpp>
#include <pthread.h>
#include <stdlib.h>
namespace boost
{
namespace detail
{
BOOST_THREAD_DECL boost::uintmax_t once_global_epoch=UINTMAX_C(~0);
BOOST_THREAD_DECL pthread_mutex_t once_epoch_mutex=PTHREAD_MUTEX_INITIALIZER;
BOOST_THREAD_DECL pthread_cond_t once_epoch_cv = PTHREAD_COND_INITIALIZER;
namespace
{
pthread_key_t epoch_tss_key;
pthread_once_t epoch_tss_key_flag=PTHREAD_ONCE_INIT;
extern "C" void delete_epoch_tss_data(void* data)
{
free(data);
}
extern "C" void create_epoch_tss_key()
{
BOOST_VERIFY(!pthread_key_create(&epoch_tss_key,delete_epoch_tss_data));
}
}
boost::uintmax_t& get_once_per_thread_epoch()
{
BOOST_VERIFY(!pthread_once(&epoch_tss_key_flag,create_epoch_tss_key));
void* data=pthread_getspecific(epoch_tss_key);
if(!data)
{
data=malloc(sizeof(boost::uintmax_t));
BOOST_VERIFY(!pthread_setspecific(epoch_tss_key,data));
*static_cast<boost::uintmax_t*>(data)=UINTMAX_C(~0);
}
return *static_cast<boost::uintmax_t*>(data);
}
}
}

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

@@ -0,0 +1,676 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#ifdef __linux__
#include <sys/sysinfo.h>
#elif defined(__APPLE__) || defined(__FreeBSD__)
#include <sys/types.h>
#include <sys/sysctl.h>
#elif defined BOOST_HAS_UNISTD_H
#include <unistd.h>
#endif
#include "timeconv.inl"
namespace boost
{
namespace detail
{
thread_data_base::~thread_data_base()
{}
struct thread_exit_callback_node
{
boost::detail::thread_exit_function_base* func;
thread_exit_callback_node* next;
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
thread_exit_callback_node* next_):
func(func_),next(next_)
{}
};
struct tss_data_node
{
void const* key;
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
tss_data_node* next_):
key(key_),func(func_),value(value_),next(next_)
{}
};
namespace
{
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
pthread_key_t current_thread_tls_key;
extern "C"
{
void tls_destructor(void* data)
{
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
if(thread_info)
{
while(thread_info->tss_data || thread_info->thread_exit_callbacks)
{
while(thread_info->thread_exit_callbacks)
{
detail::thread_exit_callback_node* const current_node=thread_info->thread_exit_callbacks;
thread_info->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
(*current_node->func)();
delete current_node->func;
}
delete current_node;
}
while(thread_info->tss_data)
{
detail::tss_data_node* const current_node=thread_info->tss_data;
thread_info->tss_data=current_node->next;
if(current_node->func)
{
(*current_node->func)(current_node->value);
}
delete current_node;
}
}
thread_info->self.reset();
}
}
}
void create_current_thread_tls_key()
{
BOOST_VERIFY(!pthread_key_create(&current_thread_tls_key,&tls_destructor));
}
}
boost::detail::thread_data_base* get_current_thread_data()
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
return (boost::detail::thread_data_base*)pthread_getspecific(current_thread_tls_key);
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
}
}
namespace
{
extern "C"
{
void* thread_proxy(void* param)
{
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(param)->self;
thread_info->self.reset();
detail::set_current_thread_data(thread_info.get());
try
{
thread_info->run();
}
catch(thread_interrupted const&)
{
}
catch(...)
{
std::terminate();
}
detail::tls_destructor(thread_info.get());
detail::set_current_thread_data(0);
boost::lock_guard<boost::mutex> lock(thread_info->data_mutex);
thread_info->done=true;
thread_info->done_condition.notify_all();
return 0;
}
}
struct externally_launched_thread:
detail::thread_data_base
{
externally_launched_thread()
{
interrupt_enabled=false;
}
void run()
{}
private:
externally_launched_thread(externally_launched_thread&);
void operator=(externally_launched_thread&);
};
detail::thread_data_base* make_external_thread_data()
{
detail::thread_data_base* const me(new externally_launched_thread());
me->self.reset(me);
set_current_thread_data(me);
return me;
}
detail::thread_data_base* get_or_make_current_thread_data()
{
detail::thread_data_base* current_thread_data(detail::get_current_thread_data());
if(!current_thread_data)
{
current_thread_data=make_external_thread_data();
}
return current_thread_data;
}
}
thread::thread()
{}
void thread::start_thread()
{
thread_info->self=thread_info;
int const res = pthread_create(&thread_info->thread_handle, 0, &thread_proxy, thread_info.get());
if (res != 0)
{
thread_info->self.reset();
throw thread_resource_error();
}
}
thread::~thread()
{
detach();
}
detail::thread_data_ptr thread::get_thread_info() const
{
lock_guard<mutex> l(thread_info_mutex);
return thread_info;
}
void thread::join()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
bool do_join=false;
{
unique_lock<mutex> lock(local_thread_info->data_mutex);
while(!local_thread_info->done)
{
local_thread_info->done_condition.wait(lock);
}
do_join=!local_thread_info->join_started;
if(do_join)
{
local_thread_info->join_started=true;
}
else
{
while(!local_thread_info->joined)
{
local_thread_info->done_condition.wait(lock);
}
}
}
if(do_join)
{
void* result=0;
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
lock_guard<mutex> lock(local_thread_info->data_mutex);
local_thread_info->joined=true;
local_thread_info->done_condition.notify_all();
}
lock_guard<mutex> l1(thread_info_mutex);
if(thread_info==local_thread_info)
{
thread_info.reset();
}
}
}
bool thread::timed_join(system_time const& wait_until)
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
bool do_join=false;
{
unique_lock<mutex> lock(local_thread_info->data_mutex);
while(!local_thread_info->done)
{
if(!local_thread_info->done_condition.timed_wait(lock,wait_until))
{
return false;
}
}
do_join=!local_thread_info->join_started;
if(do_join)
{
local_thread_info->join_started=true;
}
else
{
while(!local_thread_info->joined)
{
local_thread_info->done_condition.wait(lock);
}
}
}
if(do_join)
{
void* result=0;
BOOST_VERIFY(!pthread_join(local_thread_info->thread_handle,&result));
lock_guard<mutex> lock(local_thread_info->data_mutex);
local_thread_info->joined=true;
local_thread_info->done_condition.notify_all();
}
lock_guard<mutex> l1(thread_info_mutex);
if(thread_info==local_thread_info)
{
thread_info.reset();
}
}
return true;
}
bool thread::joinable() const
{
return get_thread_info();
}
void thread::detach()
{
detail::thread_data_ptr local_thread_info;
{
lock_guard<mutex> l1(thread_info_mutex);
thread_info.swap(local_thread_info);
}
if(local_thread_info)
{
lock_guard<mutex> lock(local_thread_info->data_mutex);
if(!local_thread_info->join_started)
{
BOOST_VERIFY(!pthread_detach(local_thread_info->thread_handle));
local_thread_info->join_started=true;
local_thread_info->joined=true;
}
}
}
namespace this_thread
{
void sleep(const system_time& st)
{
detail::thread_data_base* const thread_info=detail::get_current_thread_data();
if(thread_info)
{
unique_lock<mutex> lk(thread_info->sleep_mutex);
while(thread_info->sleep_condition.timed_wait(lk,st));
}
else
{
xtime const xt=get_xtime(st);
for (int foo=0; foo < 5; ++foo)
{
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
timespec ts;
to_timespec_duration(xt, ts);
BOOST_VERIFY(!pthread_delay_np(&ts));
# elif defined(BOOST_HAS_NANOSLEEP)
timespec ts;
to_timespec_duration(xt, ts);
// 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 yield()
{
# if defined(BOOST_HAS_SCHED_YIELD)
BOOST_VERIFY(!sched_yield());
# elif defined(BOOST_HAS_PTHREAD_YIELD)
BOOST_VERIFY(!pthread_yield());
# else
xtime xt;
xtime_get(&xt, TIME_UTC);
sleep(xt);
# endif
}
}
unsigned thread::hardware_concurrency()
{
#if defined(PTW32_VERSION) || defined(__hpux)
return pthread_num_processors_np();
#elif defined(__linux__)
return get_nprocs();
#elif defined(__APPLE__) || defined(__FreeBSD__)
int count;
size_t size=sizeof(count);
return sysctlbyname("hw.ncpu",&count,&size,NULL,0)?0:count;
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
int const count=sysconf(_SC_NPROCESSORS_ONLN);
return (count>0)?count:0;
#else
return 0;
#endif
}
thread::id thread::get_id() const
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
return id(local_thread_info);
}
else
{
return id();
}
}
void thread::interrupt()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
local_thread_info->interrupt_requested=true;
if(local_thread_info->current_cond)
{
BOOST_VERIFY(!pthread_cond_broadcast(local_thread_info->current_cond));
}
}
}
bool thread::interruption_requested() const
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
return local_thread_info->interrupt_requested;
}
else
{
return false;
}
}
thread::native_handle_type thread::native_handle()
{
detail::thread_data_ptr const local_thread_info=get_thread_info();
if(local_thread_info)
{
lock_guard<mutex> lk(local_thread_info->data_mutex);
return local_thread_info->thread_handle;
}
else
{
return pthread_t();
}
}
namespace this_thread
{
thread::id get_id()
{
boost::detail::thread_data_base* const thread_info=get_or_make_current_thread_data();
return thread::id(thread_info?thread_info->shared_from_this():detail::thread_data_ptr());
}
void interruption_point()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
if(thread_info && thread_info->interrupt_enabled)
{
lock_guard<mutex> lg(thread_info->data_mutex);
if(thread_info->interrupt_requested)
{
thread_info->interrupt_requested=false;
throw thread_interrupted();
}
}
}
bool interruption_enabled()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
return thread_info && thread_info->interrupt_enabled;
}
bool interruption_requested()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
if(!thread_info)
{
return false;
}
else
{
lock_guard<mutex> lg(thread_info->data_mutex);
return thread_info->interrupt_requested;
}
}
disable_interruption::disable_interruption():
interruption_was_enabled(interruption_enabled())
{
if(interruption_was_enabled)
{
detail::get_current_thread_data()->interrupt_enabled=false;
}
}
disable_interruption::~disable_interruption()
{
if(detail::get_current_thread_data())
{
detail::get_current_thread_data()->interrupt_enabled=interruption_was_enabled;
}
}
restore_interruption::restore_interruption(disable_interruption& d)
{
if(d.interruption_was_enabled)
{
detail::get_current_thread_data()->interrupt_enabled=true;
}
}
restore_interruption::~restore_interruption()
{
if(detail::get_current_thread_data())
{
detail::get_current_thread_data()->interrupt_enabled=false;
}
}
}
namespace detail
{
void add_thread_exit_function(thread_exit_function_base* func)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
new thread_exit_callback_node(func,current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
tss_data_node* find_tss_data(void const* key)
{
detail::thread_data_base* const current_thread_data(get_current_thread_data());
if(current_thread_data)
{
detail::tss_data_node* current_node=current_thread_data->tss_data;
while(current_node)
{
if(current_node->key==key)
{
return current_node;
}
current_node=current_node->next;
}
}
return NULL;
}
void* get_tss_data(void const* key)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
return current_node->value;
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func)
{
(*current_node->func)(current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=new tss_data_node(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
}
}
// 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);
// BOOST_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);
// BOOST_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();
// }
// }
// void thread_group::interrupt_all()
// {
// boost::lock_guard<mutex> guard(m_mutex);
// for(std::list<thread*>::iterator it=m_threads.begin(),end=m_threads.end();
// it!=end;
// ++it)
// {
// (*it)->interrupt();
// }
// }
// size_t thread_group::size() const
// {
// return m_threads.size();
// }
}

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

@@ -0,0 +1,130 @@
// 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)
// boostinspect:nounnamed
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(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_cmp(xt, cur) <= 0)
microseconds = 0;
else
{
if (cur.nsec > xt.nsec)
{
xt.nsec += NANOSECONDS_PER_SECOND;
--xt.sec;
}
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.

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 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)
@@ -9,6 +10,7 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/locks.hpp>
#include <cassert>
#if defined(BOOST_HAS_WINTHREADS)
@@ -100,22 +102,13 @@ extern "C" {
static OSStatus thread_proxy(void* param)
#endif
{
//try
//{
thread_param* p = static_cast<thread_param*>(param);
boost::function0<void> threadfunc = p->m_threadfunc;
p->started();
threadfunc();
thread_param* p = static_cast<thread_param*>(param);
boost::function0<void> threadfunc = p->m_threadfunc;
p->started();
threadfunc();
#if defined(BOOST_HAS_WINTHREADS)
on_thread_exit();
on_thread_exit();
#endif
//}
//catch (...)
//{
#if defined(BOOST_HAS_WINTHREADS)
// on_thread_exit();
#endif
//}
#if defined(BOOST_HAS_MPTASKS)
::boost::detail::thread_cleanup();
#endif
@@ -363,7 +356,7 @@ void thread_group::join_all()
}
}
int thread_group::size()
int thread_group::size() const
{
return m_threads.size();
}

View File

@@ -31,7 +31,7 @@ boost::once_flag tss_data_once = BOOST_ONCE_INIT;
boost::mutex* tss_data_mutex = 0;
tss_data_cleanup_handlers_type* tss_data_cleanup_handlers = 0;
#if defined(BOOST_HAS_WINTHREADS)
DWORD tss_data_native_key;
DWORD tss_data_native_key=TLS_OUT_OF_INDEXES;
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_t tss_data_native_key;
#elif defined(BOOST_HAS_MPTASKS)
@@ -60,6 +60,7 @@ void tss_data_dec_use(boost::mutex::scoped_lock& lk)
tss_data_mutex = 0;
#if defined(BOOST_HAS_WINTHREADS)
TlsFree(tss_data_native_key);
tss_data_native_key=TLS_OUT_OF_INDEXES;
#elif defined(BOOST_HAS_PTHREADS)
pthread_key_delete(tss_data_native_key);
#elif defined(BOOST_HAS_MPTASKS)
@@ -78,6 +79,9 @@ extern "C" void cleanup_slots(void* p)
(*(*tss_data_cleanup_handlers)[i])((*slots)[i]);
(*slots)[i] = 0;
}
#if defined(BOOST_HAS_WINTHREADS)
TlsSetValue(tss_data_native_key,0);
#endif
tss_data_dec_use(lock);
delete slots;
}
@@ -97,7 +101,7 @@ void init_tss_data()
//Allocate tls slot
tss_data_native_key = TlsAlloc();
if (tss_data_native_key == 0xFFFFFFFF)
if (tss_data_native_key == TLS_OUT_OF_INDEXES)
return;
#elif defined(BOOST_HAS_PTHREADS)
int res = pthread_key_create(&tss_data_native_key, &cleanup_slots);
@@ -178,7 +182,7 @@ namespace boost {
namespace detail {
void tss::init(boost::function1<void, void*>* pcleanup)
{
boost::call_once(&init_tss_data, tss_data_once);
boost::call_once(tss_data_once, &init_tss_data);
if (tss_data_cleanup_handlers == 0)
throw thread_resource_error();
boost::mutex::scoped_lock lock(*tss_data_mutex);

View File

@@ -74,7 +74,7 @@
thread_exit_handler exit_handler
)
{
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
//boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
@@ -141,7 +141,7 @@
extern "C" BOOST_THREAD_DECL void on_process_enter(void)
{
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
@@ -150,7 +150,7 @@
extern "C" BOOST_THREAD_DECL void on_process_exit(void)
{
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);
@@ -173,7 +173,7 @@
extern "C" BOOST_THREAD_DECL void on_thread_exit(void)
{
boost::call_once(init_threadmon_mutex, once_init_threadmon_mutex);
boost::call_once(once_init_threadmon_mutex, init_threadmon_mutex);
// boost::mutex::scoped_lock lock(*threadmon_mutex);
CScopedCSLock lock(&threadmon_mutex);

View File

@@ -1,11 +1,12 @@
// (C) Copyright Michael Glassford 2004.
// (C) Copyright 2007 Anthony Williams
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST)) && !defined(_MSC_VER)
#if defined(BOOST_HAS_WINTHREADS) && (defined(BOOST_THREAD_BUILD_LIB) || defined(BOOST_THREAD_TEST) || defined(UNDER_CE)) && (!defined(_MSC_VER) || defined(UNDER_CE))
/*
This file is a "null" implementation of tss cleanup; it's

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

@@ -0,0 +1,124 @@
// 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/detail/config.hpp>
#include <boost/thread/exceptions.hpp>
#include <cstring>
#include <string>
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;
}
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

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

@@ -0,0 +1,595 @@
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
#define _WIN32_WINNT 0x400
#define WINVER 0x400
#include <boost/thread/thread.hpp>
#include <algorithm>
#include <windows.h>
#ifndef UNDER_CE
#include <process.h>
#endif
#include <stdio.h>
#include <boost/thread/once.hpp>
#include <boost/thread/tss.hpp>
#include <boost/assert.hpp>
#include <boost/thread/detail/tss_hooks.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
namespace boost
{
namespace
{
boost::once_flag current_thread_tls_init_flag=BOOST_ONCE_INIT;
DWORD current_thread_tls_key=0;
void create_current_thread_tls_key()
{
tss_cleanup_implemented(); // if anyone uses TSS, we need the cleanup linked in
current_thread_tls_key=TlsAlloc();
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
}
void cleanup_tls_key()
{
if(current_thread_tls_key)
{
TlsFree(current_thread_tls_key);
current_thread_tls_key=0;
}
}
detail::thread_data_base* get_current_thread_data()
{
if(!current_thread_tls_key)
{
return 0;
}
return (detail::thread_data_base*)TlsGetValue(current_thread_tls_key);
}
void set_current_thread_data(detail::thread_data_base* new_data)
{
boost::call_once(current_thread_tls_init_flag,create_current_thread_tls_key);
BOOST_VERIFY(TlsSetValue(current_thread_tls_key,new_data));
}
#ifdef 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;
}
typedef void* uintptr_t;
inline uintptr_t const _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<uintptr_t const>(hthread);
}
#endif
}
namespace detail
{
struct thread_exit_callback_node
{
boost::detail::thread_exit_function_base* func;
thread_exit_callback_node* next;
thread_exit_callback_node(boost::detail::thread_exit_function_base* func_,
thread_exit_callback_node* next_):
func(func_),next(next_)
{}
};
struct tss_data_node
{
void const* key;
boost::shared_ptr<boost::detail::tss_cleanup_function> func;
void* value;
tss_data_node* next;
tss_data_node(void const* key_,boost::shared_ptr<boost::detail::tss_cleanup_function> func_,void* value_,
tss_data_node* next_):
key(key_),func(func_),value(value_),next(next_)
{}
};
}
namespace
{
void run_thread_exit_callbacks()
{
detail::thread_data_ptr current_thread_data(get_current_thread_data(),false);
if(current_thread_data)
{
while(current_thread_data->tss_data || current_thread_data->thread_exit_callbacks)
{
while(current_thread_data->thread_exit_callbacks)
{
detail::thread_exit_callback_node* const current_node=current_thread_data->thread_exit_callbacks;
current_thread_data->thread_exit_callbacks=current_node->next;
if(current_node->func)
{
(*current_node->func)();
boost::detail::heap_delete(current_node->func);
}
boost::detail::heap_delete(current_node);
}
while(current_thread_data->tss_data)
{
detail::tss_data_node* const current_node=current_thread_data->tss_data;
current_thread_data->tss_data=current_node->next;
if(current_node->func)
{
(*current_node->func)(current_node->value);
}
boost::detail::heap_delete(current_node);
}
}
set_current_thread_data(0);
}
}
unsigned __stdcall thread_start_function(void* param)
{
detail::thread_data_base* const thread_info(reinterpret_cast<detail::thread_data_base*>(param));
set_current_thread_data(thread_info);
try
{
thread_info->run();
}
catch(thread_interrupted const&)
{
}
catch(...)
{
std::terminate();
}
run_thread_exit_callbacks();
return 0;
}
}
thread::thread()
{}
void thread::start_thread()
{
uintptr_t const new_thread=_beginthreadex(0,0,&thread_start_function,thread_info.get(),CREATE_SUSPENDED,&thread_info->id);
if(!new_thread)
{
throw thread_resource_error();
}
intrusive_ptr_add_ref(thread_info.get());
thread_info->thread_handle=(detail::win32::handle)(new_thread);
ResumeThread(thread_info->thread_handle);
}
thread::thread(detail::thread_data_ptr data):
thread_info(data)
{}
namespace
{
struct externally_launched_thread:
detail::thread_data_base
{
externally_launched_thread()
{
++count;
interruption_enabled=false;
}
void run()
{}
private:
externally_launched_thread(externally_launched_thread&);
void operator=(externally_launched_thread&);
};
void make_external_thread_data()
{
externally_launched_thread* me=detail::heap_new<externally_launched_thread>();
set_current_thread_data(me);
}
detail::thread_data_base* get_or_make_current_thread_data()
{
detail::thread_data_base* current_thread_data(get_current_thread_data());
if(!current_thread_data)
{
make_external_thread_data();
current_thread_data=get_current_thread_data();
}
return current_thread_data;
}
}
thread::~thread()
{
detach();
}
thread::id thread::get_id() const
{
return thread::id(get_thread_info());
}
bool thread::joinable() const
{
return get_thread_info();
}
void thread::join()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
this_thread::interruptible_wait(local_thread_info->thread_handle,detail::timeout::sentinel());
release_handle();
}
}
bool thread::timed_join(boost::system_time const& wait_until)
{
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
if(!this_thread::interruptible_wait(local_thread_info->thread_handle,get_milliseconds_until(wait_until)))
{
return false;
}
release_handle();
}
return true;
}
void thread::detach()
{
release_handle();
}
void thread::release_handle()
{
lock_guard<mutex> l1(thread_info_mutex);
thread_info=0;
}
void thread::interrupt()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
if(local_thread_info)
{
local_thread_info->interrupt();
}
}
bool thread::interruption_requested() const
{
detail::thread_data_ptr local_thread_info=get_thread_info();
return local_thread_info.get() && (detail::win32::WaitForSingleObject(local_thread_info->interruption_handle,0)==0);
}
unsigned thread::hardware_concurrency()
{
SYSTEM_INFO info={0};
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}
thread::native_handle_type thread::native_handle()
{
detail::thread_data_ptr local_thread_info=get_thread_info();
return local_thread_info?(detail::win32::handle)local_thread_info->thread_handle:detail::win32::invalid_handle_value;
}
detail::thread_data_ptr thread::get_thread_info() const
{
boost::mutex::scoped_lock l(thread_info_mutex);
return thread_info;
}
namespace this_thread
{
namespace
{
LARGE_INTEGER get_due_time(detail::timeout const& target_time)
{
LARGE_INTEGER due_time={0};
if(target_time.relative)
{
unsigned long const elapsed_milliseconds=GetTickCount()-target_time.start;
LONGLONG const remaining_milliseconds=(target_time.milliseconds-elapsed_milliseconds);
LONGLONG const hundred_nanoseconds_in_one_millisecond=10000;
if(remaining_milliseconds>0)
{
due_time.QuadPart=-(remaining_milliseconds*hundred_nanoseconds_in_one_millisecond);
}
}
else
{
SYSTEMTIME target_system_time={0};
target_system_time.wYear=target_time.abs_time.date().year();
target_system_time.wMonth=target_time.abs_time.date().month();
target_system_time.wDay=target_time.abs_time.date().day();
target_system_time.wHour=(WORD)target_time.abs_time.time_of_day().hours();
target_system_time.wMinute=(WORD)target_time.abs_time.time_of_day().minutes();
target_system_time.wSecond=(WORD)target_time.abs_time.time_of_day().seconds();
if(!SystemTimeToFileTime(&target_system_time,((FILETIME*)&due_time)))
{
due_time.QuadPart=0;
}
else
{
long const hundred_nanoseconds_in_one_second=10000000;
due_time.QuadPart+=target_time.abs_time.time_of_day().fractional_seconds()*(hundred_nanoseconds_in_one_second/target_time.abs_time.time_of_day().ticks_per_second());
}
}
return due_time;
}
}
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
{
detail::win32::handle handles[3]={0};
unsigned handle_count=0;
unsigned wait_handle_index=~0U;
unsigned interruption_index=~0U;
unsigned timeout_index=~0U;
if(handle_to_wait_for!=detail::win32::invalid_handle_value)
{
wait_handle_index=handle_count;
handles[handle_count++]=handle_to_wait_for;
}
if(get_current_thread_data() && get_current_thread_data()->interruption_enabled)
{
interruption_index=handle_count;
handles[handle_count++]=get_current_thread_data()->interruption_handle;
}
detail::win32::handle_manager timer_handle;
#ifndef UNDER_CE
unsigned const min_timer_wait_period=20;
if(!target_time.is_sentinel())
{
detail::timeout::remaining_time const time_left=target_time.remaining_milliseconds();
if(time_left.milliseconds > min_timer_wait_period)
{
// for a long-enough timeout, use a waitable timer (which tracks clock changes)
timer_handle=CreateWaitableTimer(NULL,false,NULL);
if(timer_handle!=0)
{
LARGE_INTEGER due_time=get_due_time(target_time);
bool const set_time_succeeded=SetWaitableTimer(timer_handle,&due_time,0,0,0,false)!=0;
if(set_time_succeeded)
{
timeout_index=handle_count;
handles[handle_count++]=timer_handle;
}
}
}
else if(!target_time.relative)
{
// convert short absolute-time timeouts into relative ones, so we don't race against clock changes
target_time=detail::timeout(time_left.milliseconds);
}
}
#endif
bool const using_timer=timeout_index!=~0u;
detail::timeout::remaining_time time_left(0);
do
{
if(!using_timer)
{
time_left=target_time.remaining_milliseconds();
}
if(handle_count)
{
unsigned long const notified_index=detail::win32::WaitForMultipleObjects(handle_count,handles,false,using_timer?INFINITE:time_left.milliseconds);
if(notified_index<handle_count)
{
if(notified_index==wait_handle_index)
{
return true;
}
else if(notified_index==interruption_index)
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
else if(notified_index==timeout_index)
{
return false;
}
}
}
else
{
detail::win32::Sleep(time_left.milliseconds);
}
if(target_time.relative)
{
target_time.milliseconds-=detail::timeout::max_non_infinite_wait;
}
}
while(time_left.more);
return false;
}
thread::id get_id()
{
return thread::id(get_or_make_current_thread_data());
}
void interruption_point()
{
if(interruption_enabled() && interruption_requested())
{
detail::win32::ResetEvent(get_current_thread_data()->interruption_handle);
throw thread_interrupted();
}
}
bool interruption_enabled()
{
return get_current_thread_data() && get_current_thread_data()->interruption_enabled;
}
bool interruption_requested()
{
return get_current_thread_data() && (detail::win32::WaitForSingleObject(get_current_thread_data()->interruption_handle,0)==0);
}
void yield()
{
detail::win32::Sleep(0);
}
disable_interruption::disable_interruption():
interruption_was_enabled(interruption_enabled())
{
if(interruption_was_enabled)
{
get_current_thread_data()->interruption_enabled=false;
}
}
disable_interruption::~disable_interruption()
{
if(get_current_thread_data())
{
get_current_thread_data()->interruption_enabled=interruption_was_enabled;
}
}
restore_interruption::restore_interruption(disable_interruption& d)
{
if(d.interruption_was_enabled)
{
get_current_thread_data()->interruption_enabled=true;
}
}
restore_interruption::~restore_interruption()
{
if(get_current_thread_data())
{
get_current_thread_data()->interruption_enabled=false;
}
}
}
namespace detail
{
void add_thread_exit_function(thread_exit_function_base* func)
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
thread_exit_callback_node* const new_node=
heap_new<thread_exit_callback_node>(func,
current_thread_data->thread_exit_callbacks);
current_thread_data->thread_exit_callbacks=new_node;
}
tss_data_node* find_tss_data(void const* key)
{
detail::thread_data_base* const current_thread_data(get_current_thread_data());
if(current_thread_data)
{
detail::tss_data_node* current_node=current_thread_data->tss_data;
while(current_node)
{
if(current_node->key==key)
{
return current_node;
}
current_node=current_node->next;
}
}
return NULL;
}
void* get_tss_data(void const* key)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
return current_node->value;
}
return NULL;
}
void set_tss_data(void const* key,boost::shared_ptr<tss_cleanup_function> func,void* tss_data,bool cleanup_existing)
{
if(tss_data_node* const current_node=find_tss_data(key))
{
if(cleanup_existing && current_node->func.get())
{
(*current_node->func)(current_node->value);
}
current_node->func=func;
current_node->value=tss_data;
}
else
{
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
tss_data_node* const new_node=heap_new<tss_data_node>(key,func,tss_data,current_thread_data->tss_data);
current_thread_data->tss_data=new_node;
}
}
}
}
extern "C" BOOST_THREAD_DECL void on_process_enter()
{}
extern "C" BOOST_THREAD_DECL void on_thread_enter()
{}
extern "C" BOOST_THREAD_DECL void on_process_exit()
{
boost::cleanup_tls_key();
}
extern "C" BOOST_THREAD_DECL void on_thread_exit()
{
boost::run_thread_exit_callbacks();
}

130
src/win32/timeconv.inl Normal file
View File

@@ -0,0 +1,130 @@
// 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)
// boostinspect:nounnamed
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(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_cmp(xt, cur) <= 0)
microseconds = 0;
else
{
if (cur.nsec > xt.nsec)
{
xt.nsec += NANOSECONDS_PER_SECOND;
--xt.sec;
}
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.

72
src/win32/tss_dll.cpp Normal file
View File

@@ -0,0 +1,72 @@
// (C) Copyright Michael Glassford 2004.
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)
#include <boost/thread/detail/tss_hooks.hpp>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#if defined(__BORLANDC__)
extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
#elif defined(_WIN32_WCE)
extern "C" BOOL WINAPI DllMain(HANDLE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
#else
extern "C" BOOL WINAPI DllMain(HINSTANCE /*hInstance*/, DWORD dwReason, LPVOID /*lpReserved*/)
#endif
{
switch(dwReason)
{
case DLL_PROCESS_ATTACH:
{
on_process_enter();
on_thread_enter();
break;
}
case DLL_THREAD_ATTACH:
{
on_thread_enter();
break;
}
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
case DLL_PROCESS_DETACH:
{
on_thread_exit();
on_process_exit();
break;
}
}
return TRUE;
}
extern "C" void tss_cleanup_implemented(void)
{
/*
This function's sole purpose is to cause a link error in cases where
automatic tss cleanup is not implemented by Boost.Threads as a
reminder that user code is responsible for calling the necessary
functions at the appropriate times (and for implementing an a
tss_cleanup_implemented() function to eliminate the linker's
missing symbol error).
If Boost.Threads later implements automatic tss cleanup in cases
where it currently doesn't (which is the plan), the duplicate
symbol error will warn the user that their custom solution is no
longer needed and can be removed.
*/
}
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_DLL)

287
src/win32/tss_pe.cpp Normal file
View File

@@ -0,0 +1,287 @@
// $Id$
// (C) Copyright Aaron W. LaFramboise, Roland Schwarz, Michael Glassford 2004.
// (C) Copyright 2007 Roland Schwarz
// (C) Copyright 2007 Anthony Williams
// (C) Copyright 2007 David Deakins
// Use, modification and distribution are subject to the
// Boost Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if defined(__MINGW32__) && !defined(_WIN64)
#include <boost/thread/detail/tss_hooks.hpp>
#include <windows.h>
#include <cstdlib>
extern "C" void tss_cleanup_implemented(void) {}
namespace {
void NTAPI on_tls_callback(void* h, DWORD dwReason, PVOID pv)
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
{
on_thread_exit();
break;
}
}
}
void on_after_ctors(void)
{
on_process_enter();
}
void on_before_dtors(void)
{
on_thread_exit();
}
void on_after_dtors(void)
{
on_process_exit();
}
}
extern "C" {
void (* after_ctors )(void) __attribute__((section(".ctors"))) = on_after_ctors;
void (* before_dtors)(void) __attribute__((section(".dtors"))) = on_before_dtors;
void (* after_dtors )(void) __attribute__((section(".dtors.zzz"))) = on_after_dtors;
ULONG __tls_index__ = 0;
char __tls_end__ __attribute__((section(".tls$zzz"))) = 0;
char __tls_start__ __attribute__((section(".tls"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_start__ __attribute__ ((section(".CRT$XLA"))) = 0;
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
PIMAGE_TLS_CALLBACK __crt_xl_end__ __attribute__ ((section(".CRT$XLZ"))) = 0;
}
extern "C" const IMAGE_TLS_DIRECTORY32 _tls_used __attribute__ ((section(".rdata$T"))) =
{
(DWORD) &__tls_start__,
(DWORD) &__tls_end__,
(DWORD) &__tls_index__,
(DWORD) (&__crt_xl_start__+1),
(DWORD) 0,
(DWORD) 0
};
#elif defined(_MSC_VER) && !defined(UNDER_CE)
#include <boost/thread/detail/tss_hooks.hpp>
#include <stdlib.h>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
//Definitions required by implementation
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
typedef void (__cdecl *_PVFV)(void);
#define INIRETSUCCESS
#define PVAPI void
#else
typedef int (__cdecl *_PVFV)(void);
#define INIRETSUCCESS 0
#define PVAPI int
#endif
typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);
//Symbols for connection to the runtime environment
extern "C"
{
extern DWORD _tls_used; //the tls directory (located in .rdata segment)
extern _TLSCB __xl_a[], __xl_z[]; //tls initializers */
}
namespace
{
//Forward declarations
static PVAPI on_tls_prepare(void);
static PVAPI on_process_init(void);
static PVAPI on_process_term(void);
static void NTAPI on_tls_callback(HINSTANCE, DWORD, PVOID);
//The .CRT$Xxx information is taken from Codeguru:
//http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
#if (_MSC_VER >= 1400)
#pragma section(".CRT$XIU",long,read)
#pragma section(".CRT$XCU",long,read)
#pragma section(".CRT$XTU",long,read)
#pragma section(".CRT$XLC",long,read)
__declspec(allocate(".CRT$XLC")) _TLSCB __xl_ca=on_tls_callback;
__declspec(allocate(".CRT$XIU"))_PVFV p_tls_prepare = on_tls_prepare;
__declspec(allocate(".CRT$XCU"))_PVFV p_process_init = on_process_init;
__declspec(allocate(".CRT$XTU"))_PVFV p_process_term = on_process_term;
#else
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(push, old_seg)
#endif
//Callback to run tls glue code first.
//I don't think it is necessary to run it
//at .CRT$XIB level, since we are only
//interested in thread detachement. But
//this could be changed easily if required.
#pragma data_seg(".CRT$XIU")
static _PVFV p_tls_prepare = on_tls_prepare;
#pragma data_seg()
//Callback after all global ctors.
#pragma data_seg(".CRT$XCU")
static _PVFV p_process_init = on_process_init;
#pragma data_seg()
//Callback for tls notifications.
#pragma data_seg(".CRT$XLB")
_TLSCB p_thread_callback = on_tls_callback;
#pragma data_seg()
//Callback for termination.
#pragma data_seg(".CRT$XTU")
static _PVFV p_process_term = on_process_term;
#pragma data_seg()
#if (_MSC_VER >= 1300) // 1300 == VC++ 7.0
# pragma data_seg(pop, old_seg)
#endif
#endif
#ifdef BOOST_MSVC
#pragma warning(push)
#pragma warning(disable:4189)
#endif
PVAPI on_tls_prepare(void)
{
//The following line has an important side effect:
//if the TLS directory is not already there, it will
//be created by the linker. In other words, it forces a tls
//directory to be generated by the linker even when static tls
//(i.e. __declspec(thread)) is not used.
//The volatile should prevent the optimizer
//from removing the reference.
DWORD volatile dw = _tls_used;
#if (_MSC_VER < 1300) // 1300 == VC++ 7.0
_TLSCB* pfbegin = __xl_a;
_TLSCB* pfend = __xl_z;
_TLSCB* pfdst = pfbegin;
//pfdst = (_TLSCB*)_tls_used.AddressOfCallBacks;
//The following loop will merge the address pointers
//into a contiguous area, since the tlssup code seems
//to require this (at least on MSVC 6)
while (pfbegin < pfend)
{
if (*pfbegin != 0)
{
*pfdst = *pfbegin;
++pfdst;
}
++pfbegin;
}
*pfdst = 0;
#endif
return INIRETSUCCESS;
}
#ifdef BOOST_MSVC
#pragma warning(pop)
#endif
PVAPI on_process_init(void)
{
//Schedule on_thread_exit() to be called for the main
//thread before destructors of global objects have been
//called.
//It will not be run when 'quick' exiting the
//library; however, this is the standard behaviour
//for destructors of global objects, so that
//shouldn't be a problem.
atexit(on_thread_exit);
//Call Boost process entry callback here
on_process_enter();
return INIRETSUCCESS;
}
PVAPI on_process_term(void)
{
on_process_exit();
return INIRETSUCCESS;
}
void NTAPI on_tls_callback(HINSTANCE /*h*/, DWORD dwReason, PVOID /*pv*/)
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
on_thread_exit();
break;
}
}
BOOL WINAPI dll_callback(HANDLE, DWORD dwReason, LPVOID)
{
switch (dwReason)
{
case DLL_THREAD_DETACH:
on_thread_exit();
break;
case DLL_PROCESS_DETACH:
on_process_exit();
break;
}
return true;
}
} //namespace
extern "C"
{
extern BOOL (WINAPI * const _pRawDllMain)(HANDLE, DWORD, LPVOID)=&dll_callback;
}
extern "C" void tss_cleanup_implemented(void)
{
/*
This function's sole purpose is to cause a link error in cases where
automatic tss cleanup is not implemented by Boost.Threads as a
reminder that user code is responsible for calling the necessary
functions at the appropriate times (and for implementing an a
tss_cleanup_implemented() function to eliminate the linker's
missing symbol error).
If Boost.Threads later implements automatic tss cleanup in cases
where it currently doesn't (which is the plan), the duplicate
symbol error will warn the user that their custom solution is no
longer needed and can be removed.
*/
}
#endif //defined(_MSC_VER) && !defined(UNDER_CE)
#endif //defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)

View File

@@ -1,4 +1,5 @@
# (C) Copyright William E. Kempf 2001.
# (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)
#
@@ -21,25 +22,40 @@ project
: requirements <library>/boost/test//boost_unit_test_framework/<link>static
<threading>multi
;
rule thread-run ( sources )
{
return
[ run $(sources) ../build//boost_thread ]
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
: : : : $(sources[1]:B)_lib ]
;
[ run $(sources) ../build//boost_thread ]
[ run $(sources) ../src/tss_null.cpp ../build//boost_thread/<link>static
: : : : $(sources[1]:B)_lib ]
;
}
{
test-suite "threads"
: [ thread-run test_thread.cpp ]
[ thread-run test_thread_id.cpp ]
[ thread-run test_hardware_concurrency.cpp ]
[ thread-run test_thread_move.cpp ]
[ thread-run test_thread_launching.cpp ]
[ thread-run test_thread_mf.cpp ]
[ thread-run test_move_function.cpp ]
[ thread-run test_mutex.cpp ]
[ thread-run test_condition_notify_one.cpp ]
[ thread-run test_condition_timed_wait_times_out.cpp ]
[ thread-run test_condition_notify_all.cpp ]
[ thread-run test_condition.cpp ]
[ thread-run test_tss.cpp ]
[ thread-run test_once.cpp ]
[ thread-run test_xtime.cpp ]
[ thread-run test_barrier.cpp ]
# [ thread-run test_read_write_mutex.cpp ]
[ thread-run test_barrier.cpp ]
[ thread-run test_shared_mutex.cpp ]
[ thread-run test_shared_mutex_part_2.cpp ]
[ thread-run test_shared_mutex_timed_locks.cpp ]
[ thread-run test_lock_concept.cpp ]
[ thread-run test_generic_locks.cpp ]
[ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
[ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
;
}

View File

@@ -0,0 +1,97 @@
#ifndef CONDITION_TEST_COMMON_HPP
#define CONDITION_TEST_COMMON_HPP
// Copyright (C) 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/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread_time.hpp>
unsigned const timeout_seconds=5;
struct wait_for_flag
{
boost::mutex mutex;
boost::condition_variable cond_var;
bool flag;
unsigned woken;
wait_for_flag():
flag(false),woken(0)
{}
struct check_flag
{
bool const& flag;
check_flag(bool const& flag_):
flag(flag_)
{}
bool operator()() const
{
return flag;
}
private:
void operator=(check_flag&);
};
void wait_without_predicate()
{
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
cond_var.wait(lock);
}
++woken;
}
void wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
cond_var.wait(lock,check_flag(flag));
if(flag)
{
++woken;
}
}
void timed_wait_without_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
while(!flag)
{
if(!cond_var.timed_wait(lock,timeout))
{
return;
}
}
++woken;
}
void timed_wait_with_predicate()
{
boost::system_time const timeout=boost::get_system_time()+boost::posix_time::seconds(timeout_seconds);
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,timeout,check_flag(flag)) && flag)
{
++woken;
}
}
void relative_timed_wait_with_predicate()
{
boost::mutex::scoped_lock lock(mutex);
if(cond_var.timed_wait(lock,boost::posix_time::seconds(timeout_seconds),check_flag(flag)) && flag)
{
++woken;
}
}
};
#endif

View File

@@ -0,0 +1,15 @@
// Copyright (C) 2008 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/thread.hpp>
void do_nothing()
{}
void test()
{
boost::thread t1(do_nothing);
boost::thread t2;
t2=t1;
}

View File

@@ -0,0 +1,14 @@
// Copyright (C) 2008 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/thread.hpp>
void do_nothing()
{}
void test()
{
boost::thread t1(do_nothing);
boost::thread t2(t1);
}

View File

@@ -0,0 +1,132 @@
#ifndef SHARED_MUTEX_LOCKING_THREAD_HPP
#define SHARED_MUTEX_LOCKING_THREAD_HPP
// (C) Copyright 2008 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/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/shared_mutex.hpp>
template<typename lock_type>
class locking_thread
{
boost::shared_mutex& rw_mutex;
unsigned& unblocked_count;
boost::condition_variable& unblocked_condition;
unsigned& simultaneous_running_count;
unsigned& max_simultaneous_running;
boost::mutex& unblocked_count_mutex;
boost::mutex& finish_mutex;
public:
locking_thread(boost::shared_mutex& rw_mutex_,
unsigned& unblocked_count_,
boost::mutex& unblocked_count_mutex_,
boost::condition_variable& unblocked_condition_,
boost::mutex& finish_mutex_,
unsigned& simultaneous_running_count_,
unsigned& max_simultaneous_running_):
rw_mutex(rw_mutex_),
unblocked_count(unblocked_count_),
unblocked_condition(unblocked_condition_),
simultaneous_running_count(simultaneous_running_count_),
max_simultaneous_running(max_simultaneous_running_),
unblocked_count_mutex(unblocked_count_mutex_),
finish_mutex(finish_mutex_)
{}
void operator()()
{
// acquire lock
lock_type lock(rw_mutex);
// increment count to show we're unblocked
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
++unblocked_count;
unblocked_condition.notify_one();
++simultaneous_running_count;
if(simultaneous_running_count>max_simultaneous_running)
{
max_simultaneous_running=simultaneous_running_count;
}
}
// wait to finish
boost::mutex::scoped_lock finish_lock(finish_mutex);
{
boost::mutex::scoped_lock ublock(unblocked_count_mutex);
--simultaneous_running_count;
}
}
private:
void operator=(locking_thread&);
};
class simple_writing_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
void operator=(simple_writing_thread&);
public:
simple_writing_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::unique_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
class simple_reading_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
void operator=(simple_reading_thread&);
public:
simple_reading_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::shared_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
#endif

View File

@@ -10,6 +10,7 @@
#include <boost/thread/barrier.hpp>
#include <boost/test/unit_test.hpp>
#include <vector>
namespace {
@@ -38,12 +39,20 @@ void test_barrier()
boost::thread_group g;
global_parameter = 0;
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
BOOST_CHECK(global_parameter == 5);
try
{
for (int i = 0; i < N_THREADS; ++i)
g.create_thread(&barrier_thread);
g.join_all();
}
catch(...)
{
g.interrupt_all();
g.join_all();
throw;
}
BOOST_CHECK_EQUAL(global_parameter,5);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 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)
@@ -19,7 +20,7 @@ struct condition_test_data
condition_test_data() : notified(0), awoken(0) { }
boost::mutex mutex;
boost::condition condition;
boost::condition_variable condition;
int notified;
int awoken;
};
@@ -42,6 +43,9 @@ struct cond_predicate
int& _var;
int _val;
private:
void operator=(cond_predicate&);
};
void condition_test_waits(condition_test_data* data)
@@ -82,56 +86,15 @@ void condition_test_waits(condition_test_data* data)
BOOST_CHECK_EQUAL(data->notified, 4);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_notify_one()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_one();
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 1);
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one, 2, execution_monitor::use_mutex);
}
void do_test_condition_notify_all()
{
const int NUMTHREADS = 5;
boost::thread_group threads;
condition_test_data data;
for (int i = 0; i < NUMTHREADS; ++i)
threads.create_thread(bind(&condition_test_thread, &data));
{
boost::mutex::scoped_lock lock(data.mutex);
BOOST_CHECK(lock ? true : false);
data.notified++;
data.condition.notify_all();
}
threads.join_all();
BOOST_CHECK_EQUAL(data.awoken, NUMTHREADS);
}
void test_condition_notify_all()
{
// We should have already tested notify_one here, so
// a timed test with the default execution_monitor::use_condition
// should be OK, and gives the fastest performance
timed_test(&do_test_condition_notify_all, 3);
// Test predicate timed_wait with relative timeout
cond_predicate pred_rel(data->notified, 5);
BOOST_CHECK(data->condition.timed_wait(lock, boost::posix_time::seconds(10), pred_rel));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(pred_rel());
BOOST_CHECK_EQUAL(data->notified, 5);
data->awoken++;
data->condition.notify_one();
}
void do_test_condition_waits()
@@ -175,10 +138,19 @@ void do_test_condition_waits()
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 4);
boost::thread::sleep(delay(1));
data.notified++;
data.condition.notify_one();
while (data.awoken != 5)
data.condition.wait(lock);
BOOST_CHECK(lock ? true : false);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
thread.join();
BOOST_CHECK_EQUAL(data.awoken, 4);
BOOST_CHECK_EQUAL(data.awoken, 5);
}
void test_condition_waits()
@@ -189,14 +161,30 @@ void test_condition_waits()
timed_test(&do_test_condition_waits, 12);
}
void do_test_condition_wait_is_a_interruption_point()
{
condition_test_data data;
boost::thread thread(bind(&condition_test_thread, &data));
thread.interrupt();
thread.join();
BOOST_CHECK_EQUAL(data.awoken,0);
}
void test_condition_wait_is_a_interruption_point()
{
timed_test(&do_test_condition_wait_is_a_interruption_point, 1);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
test->add(BOOST_TEST_CASE(&test_condition_waits));
test->add(BOOST_TEST_CASE(&test_condition_wait_is_a_interruption_point));
return test;
}

View File

@@ -0,0 +1,222 @@
// Copyright (C) 2007 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
unsigned const number_of_test_threads=5;
void do_test_condition_notify_all_wakes_from_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
void do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread_group group;
try
{
for(unsigned i=0;i<number_of_test_threads;++i)
{
group.create_thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
}
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_all();
}
group.join_all();
BOOST_CHECK_EQUAL(data.woken,number_of_test_threads);
}
catch(...)
{
group.join_all();
throw;
}
}
namespace
{
boost::mutex multiple_wake_mutex;
boost::condition_variable multiple_wake_cond;
unsigned multiple_wake_count=0;
void wait_for_condvar_and_increase_count()
{
boost::mutex::scoped_lock lk(multiple_wake_mutex);
multiple_wake_cond.wait(lk);
++multiple_wake_count;
}
}
void do_test_notify_all_following_notify_one_wakes_all_threads()
{
boost::thread thread1(wait_for_condvar_and_increase_count);
boost::thread thread2(wait_for_condvar_and_increase_count);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
multiple_wake_cond.notify_one();
boost::thread thread3(wait_for_condvar_and_increase_count);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
multiple_wake_cond.notify_one();
multiple_wake_cond.notify_all();
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
{
boost::mutex::scoped_lock lk(multiple_wake_mutex);
BOOST_CHECK(multiple_wake_count==3);
}
thread1.join();
thread2.join();
thread3.join();
}
void test_condition_notify_all()
{
timed_test(&do_test_condition_notify_all_wakes_from_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_timed_wait_with_predicate, timeout_seconds);
timed_test(&do_test_condition_notify_all_wakes_from_relative_timed_wait_with_predicate, timeout_seconds);
timed_test(&do_test_notify_all_following_notify_one_wakes_all_threads, timeout_seconds);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
return test;
}

View File

@@ -0,0 +1,155 @@
// Copyright (C) 2007 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <libs/thread/test/util.inl>
#include "condition_test_common.hpp"
void do_test_condition_notify_one_wakes_from_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_without_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
void do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate()
{
wait_for_flag data;
boost::thread thread(bind(&wait_for_flag::relative_timed_wait_with_predicate, data));
{
boost::mutex::scoped_lock lock(data.mutex);
data.flag=true;
data.cond_var.notify_one();
}
thread.join();
BOOST_CHECK(data.woken);
}
namespace
{
boost::mutex multiple_wake_mutex;
boost::condition_variable multiple_wake_cond;
unsigned multiple_wake_count=0;
void wait_for_condvar_and_increase_count()
{
boost::mutex::scoped_lock lk(multiple_wake_mutex);
multiple_wake_cond.wait(lk);
++multiple_wake_count;
}
}
void do_test_multiple_notify_one_calls_wakes_multiple_threads()
{
boost::thread thread1(wait_for_condvar_and_increase_count);
boost::thread thread2(wait_for_condvar_and_increase_count);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
multiple_wake_cond.notify_one();
boost::thread thread3(wait_for_condvar_and_increase_count);
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
multiple_wake_cond.notify_one();
multiple_wake_cond.notify_one();
boost::this_thread::sleep(boost::posix_time::milliseconds(200));
{
boost::mutex::scoped_lock lk(multiple_wake_mutex);
BOOST_CHECK(multiple_wake_count==3);
}
thread1.join();
thread2.join();
thread3.join();
}
void test_condition_notify_one()
{
timed_test(&do_test_condition_notify_one_wakes_from_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_condition_notify_one_wakes_from_relative_timed_wait_with_predicate, timeout_seconds, execution_monitor::use_mutex);
timed_test(&do_test_multiple_notify_one_calls_wakes_multiple_threads, timeout_seconds, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
return test;
}

View File

@@ -0,0 +1,173 @@
// Copyright (C) 2007-8 Anthony Williams
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/thread/detail/config.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread/thread.hpp>
#include <boost/test/unit_test.hpp>
#include "util.inl"
bool fake_predicate()
{
return false;
}
unsigned const timeout_seconds=2;
unsigned const timeout_grace=1;
boost::posix_time::milliseconds const timeout_resolution(100);
void do_test_timed_wait_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
while(cond.timed_wait(lock,timeout));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_relative_timed_wait_with_predicate_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
bool const res=cond.timed_wait(lock,delay,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_timed_wait_relative_times_out()
{
boost::condition_variable cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
while(cond.timed_wait(lock,delay));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_timed_wait_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
while(cond.timed_wait(lock,timeout));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_timed_wait_with_predicate_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+delay;
bool const res=cond.timed_wait(lock,timeout,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_relative_timed_wait_with_predicate_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
bool const res=cond.timed_wait(lock,delay,fake_predicate);
boost::system_time const end=boost::get_system_time();
BOOST_CHECK(!res);
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void do_test_cv_any_timed_wait_relative_times_out()
{
boost::condition_variable_any cond;
boost::mutex m;
boost::posix_time::seconds const delay(timeout_seconds);
boost::mutex::scoped_lock lock(m);
boost::system_time const start=boost::get_system_time();
while(cond.timed_wait(lock,delay));
boost::system_time const end=boost::get_system_time();
BOOST_CHECK((delay-timeout_resolution)<=(end-start));
}
void test_timed_wait_times_out()
{
timed_test(&do_test_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_timed_wait_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_relative_timed_wait_with_predicate_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
timed_test(&do_test_cv_any_timed_wait_relative_times_out, timeout_seconds+timeout_grace, execution_monitor::use_mutex);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
return test;
}

523
test/test_generic_locks.cpp Normal file
View File

@@ -0,0 +1,523 @@
// (C) Copyright 2008 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/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/locks.hpp>
#include <boost/thread/condition_variable.hpp>
void test_lock_two_uncontended()
{
boost::mutex m1,m2;
boost::mutex::scoped_lock l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
boost::lock(l1,l2);
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
}
struct wait_data
{
boost::mutex m;
bool flag;
boost::condition_variable cond;
wait_data():
flag(false)
{}
void wait()
{
boost::mutex::scoped_lock l(m);
while(!flag)
{
cond.wait(l);
}
}
template<typename Duration>
bool timed_wait(Duration d)
{
boost::system_time const target=boost::get_system_time()+d;
boost::mutex::scoped_lock l(m);
while(!flag)
{
if(!cond.timed_wait(l,target))
{
return flag;
}
}
return true;
}
void signal()
{
boost::mutex::scoped_lock l(m);
flag=true;
cond.notify_all();
}
};
void lock_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,wait_data* locked,wait_data* quit)
{
boost::lock_guard<boost::mutex> l1(*m1);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l2(*m2);
locked->signal();
quit->wait();
}
void lock_pair(boost::mutex* m1,boost::mutex* m2)
{
boost::lock(*m1,*m2);
boost::mutex::scoped_lock l1(*m1,boost::adopt_lock),
l2(*m2,boost::adopt_lock);
}
void test_lock_two_other_thread_locks_in_order()
{
boost::mutex m1,m2;
wait_data locked;
wait_data release;
boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_pair,&m1,&m2);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
t.join();
}
void test_lock_two_other_thread_locks_in_opposite_order()
{
boost::mutex m1,m2;
wait_data locked;
wait_data release;
boost::thread t(lock_mutexes_slowly,&m1,&m2,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_pair,&m2,&m1);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(1)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(1)));
t.join();
}
void test_lock_five_uncontended()
{
boost::mutex m1,m2,m3,m4,m5;
boost::mutex::scoped_lock l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock),
l3(m3,boost::defer_lock),
l4(m4,boost::defer_lock),
l5(m5,boost::defer_lock);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
BOOST_CHECK(!l4.owns_lock());
BOOST_CHECK(!l5.owns_lock());
boost::lock(l1,l2,l3,l4,l5);
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
BOOST_CHECK(l4.owns_lock());
BOOST_CHECK(l5.owns_lock());
}
void lock_five_mutexes_slowly(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5,
wait_data* locked,wait_data* quit)
{
boost::lock_guard<boost::mutex> l1(*m1);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l2(*m2);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l3(*m3);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l4(*m4);
boost::this_thread::sleep(boost::posix_time::milliseconds(500));
boost::lock_guard<boost::mutex> l5(*m5);
locked->signal();
quit->wait();
}
void lock_five(boost::mutex* m1,boost::mutex* m2,boost::mutex* m3,boost::mutex* m4,boost::mutex* m5)
{
boost::lock(*m1,*m2,*m3,*m4,*m5);
m1->unlock();
m2->unlock();
m3->unlock();
m4->unlock();
m5->unlock();
}
void test_lock_five_other_thread_locks_in_order()
{
boost::mutex m1,m2,m3,m4,m5;
wait_data locked;
wait_data release;
boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_five,&m1,&m2,&m3,&m4,&m5);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
t.join();
}
void test_lock_five_other_thread_locks_in_different_order()
{
boost::mutex m1,m2,m3,m4,m5;
wait_data locked;
wait_data release;
boost::thread t(lock_five_mutexes_slowly,&m1,&m2,&m3,&m4,&m5,&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_five,&m5,&m1,&m4,&m2,&m3);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
t.join();
}
void lock_n(boost::mutex* mutexes,unsigned count)
{
boost::lock(mutexes,mutexes+count);
for(unsigned i=0;i<count;++i)
{
mutexes[i].unlock();
}
}
void test_lock_ten_other_thread_locks_in_different_order()
{
unsigned const num_mutexes=10;
boost::mutex mutexes[num_mutexes];
wait_data locked;
wait_data release;
boost::thread t(lock_five_mutexes_slowly,&mutexes[6],&mutexes[3],&mutexes[8],&mutexes[0],&mutexes[2],&locked,&release);
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
boost::thread t2(lock_n,mutexes,num_mutexes);
BOOST_CHECK(locked.timed_wait(boost::posix_time::seconds(3)));
release.signal();
BOOST_CHECK(t2.timed_join(boost::posix_time::seconds(3)));
t.join();
}
struct dummy_mutex
{
bool is_locked;
dummy_mutex():
is_locked(false)
{}
void lock()
{
is_locked=true;
}
bool try_lock()
{
if(is_locked)
{
return false;
}
is_locked=true;
return true;
}
void unlock()
{
is_locked=false;
}
};
namespace boost
{
template<>
struct is_mutex_type<dummy_mutex>
{
BOOST_STATIC_CONSTANT(bool, value = true);
};
}
void test_lock_five_in_range()
{
unsigned const num_mutexes=5;
dummy_mutex mutexes[num_mutexes];
boost::lock(mutexes,mutexes+num_mutexes);
for(unsigned i=0;i<num_mutexes;++i)
{
BOOST_CHECK(mutexes[i].is_locked);
}
}
void test_lock_ten_in_range()
{
unsigned const num_mutexes=10;
dummy_mutex mutexes[num_mutexes];
boost::lock(mutexes,mutexes+num_mutexes);
for(unsigned i=0;i<num_mutexes;++i)
{
BOOST_CHECK(mutexes[i].is_locked);
}
}
void test_try_lock_two_uncontended()
{
dummy_mutex m1,m2;
int const res=boost::try_lock(m1,m2);
BOOST_CHECK(res==-1);
BOOST_CHECK(m1.is_locked);
BOOST_CHECK(m2.is_locked);
}
void test_try_lock_two_first_locked()
{
dummy_mutex m1,m2;
m1.lock();
boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock);
int const res=boost::try_lock(l1,l2);
BOOST_CHECK(res==0);
BOOST_CHECK(m1.is_locked);
BOOST_CHECK(!m2.is_locked);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
}
void test_try_lock_two_second_locked()
{
dummy_mutex m1,m2;
m2.lock();
boost::unique_lock<dummy_mutex> l1(m1,boost::defer_lock),
l2(m2,boost::defer_lock);
int const res=boost::try_lock(l1,l2);
BOOST_CHECK(res==1);
BOOST_CHECK(!m1.is_locked);
BOOST_CHECK(m2.is_locked);
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
}
void test_try_lock_three()
{
int const num_mutexes=3;
for(int i=-1;i<num_mutexes;++i)
{
dummy_mutex mutexes[num_mutexes];
if(i>=0)
{
mutexes[i].lock();
}
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
l2(mutexes[1],boost::defer_lock),
l3(mutexes[2],boost::defer_lock);
int const res=boost::try_lock(l1,l2,l3);
BOOST_CHECK(res==i);
for(int j=0;j<num_mutexes;++j)
{
if((i==j) || (i==-1))
{
BOOST_CHECK(mutexes[j].is_locked);
}
else
{
BOOST_CHECK(!mutexes[j].is_locked);
}
}
if(i==-1)
{
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
}
else
{
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
}
}
}
void test_try_lock_four()
{
int const num_mutexes=4;
for(int i=-1;i<num_mutexes;++i)
{
dummy_mutex mutexes[num_mutexes];
if(i>=0)
{
mutexes[i].lock();
}
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
l2(mutexes[1],boost::defer_lock),
l3(mutexes[2],boost::defer_lock),
l4(mutexes[3],boost::defer_lock);
int const res=boost::try_lock(l1,l2,l3,l4);
BOOST_CHECK(res==i);
for(int j=0;j<num_mutexes;++j)
{
if((i==j) || (i==-1))
{
BOOST_CHECK(mutexes[j].is_locked);
}
else
{
BOOST_CHECK(!mutexes[j].is_locked);
}
}
if(i==-1)
{
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
BOOST_CHECK(l4.owns_lock());
}
else
{
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
BOOST_CHECK(!l4.owns_lock());
}
}
}
void test_try_lock_five()
{
int const num_mutexes=5;
for(int i=-1;i<num_mutexes;++i)
{
dummy_mutex mutexes[num_mutexes];
if(i>=0)
{
mutexes[i].lock();
}
boost::unique_lock<dummy_mutex> l1(mutexes[0],boost::defer_lock),
l2(mutexes[1],boost::defer_lock),
l3(mutexes[2],boost::defer_lock),
l4(mutexes[3],boost::defer_lock),
l5(mutexes[4],boost::defer_lock);
int const res=boost::try_lock(l1,l2,l3,l4,l5);
BOOST_CHECK(res==i);
for(int j=0;j<num_mutexes;++j)
{
if((i==j) || (i==-1))
{
BOOST_CHECK(mutexes[j].is_locked);
}
else
{
BOOST_CHECK(!mutexes[j].is_locked);
}
}
if(i==-1)
{
BOOST_CHECK(l1.owns_lock());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l3.owns_lock());
BOOST_CHECK(l4.owns_lock());
BOOST_CHECK(l5.owns_lock());
}
else
{
BOOST_CHECK(!l1.owns_lock());
BOOST_CHECK(!l2.owns_lock());
BOOST_CHECK(!l3.owns_lock());
BOOST_CHECK(!l4.owns_lock());
BOOST_CHECK(!l5.owns_lock());
}
}
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_order));
test->add(BOOST_TEST_CASE(&test_lock_two_other_thread_locks_in_opposite_order));
test->add(BOOST_TEST_CASE(&test_lock_five_uncontended));
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_order));
test->add(BOOST_TEST_CASE(&test_lock_five_other_thread_locks_in_different_order));
test->add(BOOST_TEST_CASE(&test_lock_five_in_range));
test->add(BOOST_TEST_CASE(&test_lock_ten_in_range));
test->add(BOOST_TEST_CASE(&test_lock_ten_other_thread_locks_in_different_order));
test->add(BOOST_TEST_CASE(&test_try_lock_two_uncontended));
test->add(BOOST_TEST_CASE(&test_try_lock_two_first_locked));
test->add(BOOST_TEST_CASE(&test_try_lock_two_second_locked));
test->add(BOOST_TEST_CASE(&test_try_lock_three));
test->add(BOOST_TEST_CASE(&test_try_lock_four));
test->add(BOOST_TEST_CASE(&test_try_lock_five));
return test;
}

View File

@@ -0,0 +1,21 @@
// Copyright (C) 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/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
void test_hardware_concurrency_is_non_zero()
{
BOOST_CHECK(boost::thread::hardware_concurrency()!=0);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
return test;
}

571
test/test_lock_concept.cpp Normal file
View File

@@ -0,0 +1,571 @@
// (C) Copyright 2006-8 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/test/unit_test.hpp>
#include <boost/test/test_case_template.hpp>
#include <boost/mpl/vector.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/shared_mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/condition_variable.hpp>
template<typename Mutex,typename Lock>
struct test_initially_locked
{
void operator()() const
{
Mutex m;
Lock lock(m);
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_initially_unlocked_if_other_thread_has_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_initially_unlocked_if_other_thread_has_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m);
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
bool is_done() const
{
return done;
}
void operator()()
{
Lock lock(m);
typedef test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock> this_type;
boost::thread t(&this_type::locking_thread,this);
try
{
{
boost::mutex::scoped_lock lk(done_mutex);
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
boost::bind(&this_type::is_done,this)));
BOOST_CHECK(!locked);
}
lock.unlock();
t.join();
}
catch(...)
{
lock.unlock();
t.join();
throw;
}
}
};
template<typename Mutex,typename Lock>
struct test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m,boost::try_to_lock);
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
bool is_done() const
{
return done;
}
void operator()()
{
boost::unique_lock<Mutex> lock(m);
typedef test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock> this_type;
boost::thread t(&this_type::locking_thread,this);
try
{
{
boost::mutex::scoped_lock lk(done_mutex);
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
boost::bind(&this_type::is_done,this)));
BOOST_CHECK(!locked);
}
lock.unlock();
t.join();
}
catch(...)
{
lock.unlock();
t.join();
throw;
}
}
};
template<typename Mutex,typename Lock>
struct test_initially_locked_if_other_thread_has_shared_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_initially_locked_if_other_thread_has_shared_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m);
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
bool is_done() const
{
return done;
}
void operator()()
{
boost::shared_lock<Mutex> lock(m);
typedef test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock> this_type;
boost::thread t(&this_type::locking_thread,this);
try
{
{
boost::mutex::scoped_lock lk(done_mutex);
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
boost::bind(&this_type::is_done,this)));
BOOST_CHECK(locked);
}
lock.unlock();
t.join();
}
catch(...)
{
lock.unlock();
t.join();
throw;
}
}
};
template<typename Mutex,typename Lock>
struct test_initially_unlocked_with_defer_lock_parameter
{
void operator()() const
{
Mutex m;
Lock lock(m,boost::defer_lock);
BOOST_CHECK(!lock);
BOOST_CHECK(!lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_initially_locked_with_adopt_lock_parameter
{
void operator()() const
{
Mutex m;
m.lock();
Lock lock(m,boost::adopt_lock);
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_unlocked_after_unlock_called
{
void operator()() const
{
Mutex m;
Lock lock(m);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK(!lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_locked_after_lock_called
{
void operator()() const
{
Mutex m;
Lock lock(m,boost::defer_lock);
lock.lock();
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_locked_after_try_lock_called
{
void operator()() const
{
Mutex m;
Lock lock(m,boost::defer_lock);
lock.try_lock();
BOOST_CHECK(lock);
BOOST_CHECK(lock.owns_lock());
}
};
template<typename Mutex,typename Lock>
struct test_unlocked_after_try_lock_if_other_thread_has_lock
{
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_unlocked_after_try_lock_if_other_thread_has_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m,boost::defer_lock);
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
bool is_done() const
{
return done;
}
void operator()()
{
Lock lock(m);
typedef test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock> this_type;
boost::thread t(&this_type::locking_thread,this);
try
{
{
boost::mutex::scoped_lock lk(done_mutex);
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
boost::bind(&this_type::is_done,this)));
BOOST_CHECK(!locked);
}
lock.unlock();
t.join();
}
catch(...)
{
lock.unlock();
t.join();
throw;
}
}
};
template<typename Mutex,typename Lock>
struct test_throws_if_lock_called_when_already_locked
{
void operator()() const
{
Mutex m;
Lock lock(m);
BOOST_CHECK_THROW( lock.lock(), boost::lock_error );
}
};
template<typename Mutex,typename Lock>
struct test_throws_if_try_lock_called_when_already_locked
{
void operator()() const
{
Mutex m;
Lock lock(m);
BOOST_CHECK_THROW( lock.try_lock(), boost::lock_error );
}
};
template<typename Mutex,typename Lock>
struct test_throws_if_unlock_called_when_already_unlocked
{
void operator()() const
{
Mutex m;
Lock lock(m);
lock.unlock();
BOOST_CHECK_THROW( lock.unlock(), boost::lock_error );
}
};
template<typename Lock>
struct test_default_constructed_has_no_mutex_and_unlocked
{
void operator()() const
{
Lock l;
BOOST_CHECK(!l.mutex());
BOOST_CHECK(!l.owns_lock());
};
};
template<typename Mutex,typename Lock>
struct test_locks_can_be_swapped
{
void operator()() const
{
Mutex m1;
Mutex m2;
Mutex m3;
Lock l1(m1);
Lock l2(m2);
BOOST_CHECK_EQUAL(l1.mutex(),&m1);
BOOST_CHECK_EQUAL(l2.mutex(),&m2);
l1.swap(l2);
BOOST_CHECK_EQUAL(l1.mutex(),&m2);
BOOST_CHECK_EQUAL(l2.mutex(),&m1);
swap(l1,l2);
BOOST_CHECK_EQUAL(l1.mutex(),&m1);
BOOST_CHECK_EQUAL(l2.mutex(),&m2);
l1.swap(Lock(m3));
BOOST_CHECK_EQUAL(l1.mutex(),&m3);
}
};
template<typename Mutex,typename Lock>
void test_lock_is_scoped_lock_concept_for_mutex()
{
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
test_unlocked_after_unlock_called<Mutex,Lock>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
test_locks_can_be_swapped<Mutex,Lock>()();
test_locked_after_try_lock_called<Mutex,Lock>()();
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_lock_concept,Mutex)
{
typedef typename Mutex::scoped_lock Lock;
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_unique_lock_is_scoped_lock,Mutex)
{
typedef boost::unique_lock<Mutex> Lock;
test_lock_is_scoped_lock_concept_for_mutex<Mutex,Lock>();
}
BOOST_TEST_CASE_TEMPLATE_FUNCTION(test_scoped_try_lock_concept,Mutex)
{
typedef typename Mutex::scoped_try_lock Lock;
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_if_other_thread_has_lock<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
test_unlocked_after_unlock_called<Mutex,Lock>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_locked_after_try_lock_called<Mutex,Lock>()();
test_unlocked_after_try_lock_if_other_thread_has_lock<Mutex,Lock>()();
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
test_locks_can_be_swapped<Mutex,Lock>()();
}
struct dummy_shared_mutex
{
bool locked;
bool shared_locked;
bool shared_unlocked;
bool shared_timed_locked_relative;
bool shared_timed_locked_absolute;
bool timed_locked_relative;
bool timed_locked_absolute;
dummy_shared_mutex():
locked(false),shared_locked(false),shared_unlocked(false),
shared_timed_locked_relative(false),
shared_timed_locked_absolute(false),
timed_locked_relative(false),
timed_locked_absolute(false)
{}
void lock()
{
locked=true;
}
void lock_shared()
{
shared_locked=true;
}
void unlock()
{}
void unlock_shared()
{
shared_unlocked=true;
}
bool timed_lock_shared(boost::system_time)
{
shared_timed_locked_absolute=true;
return false;
}
template<typename Duration>
bool timed_lock_shared(Duration)
{
shared_timed_locked_relative=true;
return false;
}
bool timed_lock(boost::system_time)
{
timed_locked_absolute=true;
return false;
}
template<typename Duration>
bool timed_lock(Duration)
{
timed_locked_relative=true;
return false;
}
};
void test_shared_lock()
{
typedef boost::shared_mutex Mutex;
typedef boost::shared_lock<Mutex> Lock;
test_default_constructed_has_no_mutex_and_unlocked<Lock>()();
test_initially_locked<Mutex,Lock>()();
test_initially_unlocked_with_try_lock_if_other_thread_has_unique_lock<Mutex,Lock>()();
test_initially_locked_if_other_thread_has_shared_lock<Mutex,Lock>()();
test_initially_unlocked_with_defer_lock_parameter<Mutex,Lock>()();
test_initially_locked_with_adopt_lock_parameter<Mutex,Lock>()();
test_unlocked_after_unlock_called<Mutex,Lock>()();
test_locked_after_lock_called<Mutex,Lock>()();
test_locked_after_try_lock_called<Mutex,Lock>()();
test_throws_if_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_try_lock_called_when_already_locked<Mutex,Lock>()();
test_throws_if_unlock_called_when_already_unlocked<Mutex,Lock>()();
test_locks_can_be_swapped<Mutex,Lock>()();
dummy_shared_mutex dummy;
boost::shared_lock<dummy_shared_mutex> lk(dummy);
BOOST_CHECK(dummy.shared_locked);
lk.unlock();
BOOST_CHECK(dummy.shared_unlocked);
lk.timed_lock(boost::posix_time::milliseconds(5));
BOOST_CHECK(dummy.shared_timed_locked_relative);
lk.timed_lock(boost::get_system_time());
BOOST_CHECK(dummy.shared_timed_locked_absolute);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_lock;
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_lock_concept,mutex_types_with_scoped_lock));
typedef boost::mpl::vector<boost::try_mutex,boost::timed_mutex,
boost::recursive_try_mutex,boost::recursive_timed_mutex> mutex_types_with_scoped_try_lock;
test->add(BOOST_TEST_CASE_TEMPLATE(test_scoped_try_lock_concept,mutex_types_with_scoped_try_lock));
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
boost::recursive_mutex,boost::recursive_try_mutex,boost::recursive_timed_mutex,boost::shared_mutex> all_mutex_types;
test->add(BOOST_TEST_CASE_TEMPLATE(test_unique_lock_is_scoped_lock,all_mutex_types));
test->add(BOOST_TEST_CASE(&test_shared_lock));
return test;
}

124
test/test_move_function.cpp Normal file
View File

@@ -0,0 +1,124 @@
// Copyright (C) 2007-8 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/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/shared_ptr.hpp>
void do_nothing()
{}
void test_thread_move_from_lvalue_on_construction()
{
boost::thread src(do_nothing);
boost::thread::id src_id=src.get_id();
boost::thread dest(boost::move(src));
boost::thread::id dest_id=dest.get_id();
BOOST_CHECK(src_id==dest_id);
BOOST_CHECK(src.get_id()==boost::thread::id());
dest.join();
}
void test_thread_move_from_lvalue_on_assignment()
{
boost::thread src(do_nothing);
boost::thread::id src_id=src.get_id();
boost::thread dest;
dest=boost::move(src);
boost::thread::id dest_id=dest.get_id();
BOOST_CHECK(src_id==dest_id);
BOOST_CHECK(src.get_id()==boost::thread::id());
dest.join();
}
boost::thread start_thread()
{
return boost::thread(do_nothing);
}
void test_thread_move_from_rvalue_on_construction()
{
boost::thread x(start_thread());
BOOST_CHECK(x.get_id()!=boost::thread::id());
x.join();
}
void test_thread_move_from_rvalue_using_explicit_move()
{
boost::thread x(boost::move(start_thread()));
BOOST_CHECK(x.get_id()!=boost::thread::id());
x.join();
}
void test_unique_lock_move_from_lvalue_on_construction()
{
boost::mutex m;
boost::unique_lock<boost::mutex> l(m);
BOOST_CHECK(l.owns_lock());
BOOST_CHECK(l.mutex()==&m);
boost::unique_lock<boost::mutex> l2(boost::move(l));
BOOST_CHECK(!l.owns_lock());
BOOST_CHECK(!l.mutex());
BOOST_CHECK(l2.owns_lock());
BOOST_CHECK(l2.mutex()==&m);
}
boost::unique_lock<boost::mutex> get_lock(boost::mutex& m)
{
return boost::unique_lock<boost::mutex>(m);
}
void test_unique_lock_move_from_rvalue_on_construction()
{
boost::mutex m;
boost::unique_lock<boost::mutex> l(get_lock(m));
BOOST_CHECK(l.owns_lock());
BOOST_CHECK(l.mutex()==&m);
}
namespace user_test_ns
{
template<typename T>
T move(T& t)
{
return t.move();
}
bool move_called=false;
struct nc:
public boost::shared_ptr<int>
{
nc move()
{
move_called=true;
return nc();
}
};
}
void test_move_for_user_defined_type_unaffected()
{
user_test_ns::nc src;
user_test_ns::nc dest=move(src);
BOOST_CHECK(user_test_ns::move_called);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_on_construction));
test->add(BOOST_TEST_CASE(test_thread_move_from_rvalue_using_explicit_move));
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_assignment));
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_lvalue_on_construction));
test->add(BOOST_TEST_CASE(test_unique_lock_move_from_rvalue_on_construction));
test->add(BOOST_TEST_CASE(test_move_for_user_defined_type_unaffected));
return test;
}

View File

@@ -7,8 +7,9 @@
#include <boost/thread/detail/config.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/thread/condition.hpp>
#include <boost/test/unit_test.hpp>
@@ -29,7 +30,7 @@ struct test_lock
// Test the lock's constructors.
{
lock_type lock(mutex, false);
lock_type lock(mutex, boost::defer_lock);
BOOST_CHECK(!lock);
}
lock_type lock(mutex);
@@ -69,10 +70,10 @@ struct test_trylock
BOOST_CHECK(lock ? true : false);
}
{
try_lock_type lock(mutex, false);
try_lock_type lock(mutex, boost::defer_lock);
BOOST_CHECK(!lock);
}
try_lock_type lock(mutex, true);
try_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
@@ -96,41 +97,131 @@ struct test_trylock
}
};
template<typename Mutex>
struct test_lock_times_out_if_other_thread_has_lock
{
typedef boost::unique_lock<Mutex> Lock;
Mutex m;
boost::mutex done_mutex;
bool done;
bool locked;
boost::condition_variable done_cond;
test_lock_times_out_if_other_thread_has_lock():
done(false),locked(false)
{}
void locking_thread()
{
Lock lock(m,boost::defer_lock);
lock.timed_lock(boost::posix_time::milliseconds(50));
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
void locking_thread_through_constructor()
{
Lock lock(m,boost::posix_time::milliseconds(50));
boost::lock_guard<boost::mutex> lk(done_mutex);
locked=lock.owns_lock();
done=true;
done_cond.notify_one();
}
bool is_done() const
{
return done;
}
typedef test_lock_times_out_if_other_thread_has_lock<Mutex> this_type;
void do_test(void (this_type::*test_func)())
{
Lock lock(m);
locked=false;
done=false;
boost::thread t(test_func,this);
try
{
{
boost::mutex::scoped_lock lk(done_mutex);
BOOST_CHECK(done_cond.timed_wait(lk,boost::posix_time::seconds(2),
boost::bind(&this_type::is_done,this)));
BOOST_CHECK(!locked);
}
lock.unlock();
t.join();
}
catch(...)
{
lock.unlock();
t.join();
throw;
}
}
void operator()()
{
do_test(&this_type::locking_thread);
do_test(&this_type::locking_thread_through_constructor);
}
};
template <typename M>
struct test_timedlock
{
typedef M mutex_type;
typedef typename M::scoped_timed_lock timed_lock_type;
static bool fake_predicate()
{
return false;
}
void operator()()
{
test_lock_times_out_if_other_thread_has_lock<mutex_type>()();
mutex_type mutex;
boost::condition condition;
// Test the lock's constructors.
{
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::system_time xt = boost::get_system_time()+boost::posix_time::milliseconds(100);
timed_lock_type lock(mutex, xt);
BOOST_CHECK(lock ? true : false);
}
{
timed_lock_type lock(mutex, false);
timed_lock_type lock(mutex, boost::defer_lock);
BOOST_CHECK(!lock);
}
timed_lock_type lock(mutex, true);
timed_lock_type lock(mutex);
BOOST_CHECK(lock ? true : false);
// Construct and initialize an xtime for a fast time out.
boost::xtime xt = delay(0, 100);
boost::system_time timeout = boost::get_system_time()+boost::posix_time::milliseconds(100);
// Test the lock and the mutex with condition variables.
// No one is going to notify this condition variable. We expect to
// time out.
BOOST_CHECK(!condition.timed_wait(lock, xt));
BOOST_CHECK(!condition.timed_wait(lock, timeout, fake_predicate));
BOOST_CHECK(lock ? true : false);
BOOST_CHECK(in_range(xt));
boost::system_time now=boost::get_system_time();
boost::posix_time::milliseconds const timeout_resolution(20);
BOOST_CHECK((timeout-timeout_resolution)<now);
// Test the lock, unlock and timedlock methods.
lock.unlock();
@@ -139,9 +230,20 @@ struct test_timedlock
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
xt = delay(0, 100);
BOOST_CHECK(lock.timed_lock(xt));
boost::system_time target = boost::get_system_time()+boost::posix_time::milliseconds(100);
BOOST_CHECK(lock.timed_lock(target));
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
BOOST_CHECK(mutex.timed_lock(boost::posix_time::milliseconds(100)));
mutex.unlock();
BOOST_CHECK(lock.timed_lock(boost::posix_time::milliseconds(100)));
BOOST_CHECK(lock ? true : false);
lock.unlock();
BOOST_CHECK(!lock);
}
};
@@ -159,6 +261,7 @@ struct test_recursive_lock
}
};
void do_test_mutex()
{
test_lock<boost::mutex>()();

View File

@@ -1,52 +1,191 @@
// 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/detail/config.hpp>
#include <boost/thread/once.hpp>
#include <boost/thread/thread.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/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <libs/thread/test/util.inl>
boost::once_flag flag=BOOST_ONCE_INIT;
int var_to_init=0;
boost::mutex m;
int once_value = 0;
boost::once_flag once = BOOST_ONCE_INIT;
void init_once_value()
void initialize_variable()
{
once_value++;
// ensure that if multiple threads get in here, they are serialized, so we can see the effect
boost::mutex::scoped_lock lock(m);
++var_to_init;
}
void test_once_thread()
void call_once_thread()
{
boost::call_once(init_once_value, once);
unsigned const loop_count=100;
int my_once_value=0;
for(unsigned i=0;i<loop_count;++i)
{
boost::call_once(flag, initialize_variable);
my_once_value=var_to_init;
if(my_once_value!=1)
{
break;
}
}
boost::mutex::scoped_lock lock(m);
BOOST_CHECK_EQUAL(my_once_value, 1);
}
void do_test_once()
void test_call_once()
{
const int NUMTHREADS=5;
boost::thread_group threads;
for (int i=0; i<NUMTHREADS; ++i)
threads.create_thread(&test_once_thread);
threads.join_all();
BOOST_CHECK_EQUAL(once_value, 1);
unsigned const num_threads=20;
boost::thread_group group;
try
{
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_thread);
}
group.join_all();
}
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
BOOST_CHECK_EQUAL(var_to_init,1);
}
void test_once()
int var_to_init_with_functor=0;
struct increment_value
{
timed_test(&do_test_once, 2);
int* value;
explicit increment_value(int* value_):
value(value_)
{}
void operator()() const
{
boost::mutex::scoped_lock lock(m);
++(*value);
}
};
void call_once_with_functor()
{
unsigned const loop_count=100;
int my_once_value=0;
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
for(unsigned i=0;i<loop_count;++i)
{
boost::call_once(functor_flag, increment_value(&var_to_init_with_functor));
my_once_value=var_to_init_with_functor;
if(my_once_value!=1)
{
break;
}
}
boost::mutex::scoped_lock lock(m);
BOOST_CHECK_EQUAL(my_once_value, 1);
}
void test_call_once_arbitrary_functor()
{
unsigned const num_threads=20;
boost::thread_group group;
try
{
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_functor);
}
group.join_all();
}
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
BOOST_CHECK_EQUAL(var_to_init_with_functor,1);
}
struct throw_before_third_pass
{
struct my_exception
{};
static unsigned pass_counter;
void operator()() const
{
boost::mutex::scoped_lock lock(m);
++pass_counter;
if(pass_counter<3)
{
throw my_exception();
}
}
};
unsigned throw_before_third_pass::pass_counter=0;
unsigned exception_counter=0;
void call_once_with_exception()
{
static boost::once_flag functor_flag=BOOST_ONCE_INIT;
try
{
boost::call_once(functor_flag, throw_before_third_pass());
}
catch(throw_before_third_pass::my_exception)
{
boost::mutex::scoped_lock lock(m);
++exception_counter;
}
}
void test_call_once_retried_on_exception()
{
unsigned const num_threads=20;
boost::thread_group group;
try
{
for(unsigned i=0;i<num_threads;++i)
{
group.create_thread(&call_once_with_exception);
}
group.join_all();
}
catch(...)
{
group.interrupt_all();
group.join_all();
throw;
}
BOOST_CHECK_EQUAL(throw_before_third_pass::pass_counter,3u);
BOOST_CHECK_EQUAL(exception_counter,2u);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: once test suite");
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
test->add(BOOST_TEST_CASE(test_once));
test->add(BOOST_TEST_CASE(test_call_once));
test->add(BOOST_TEST_CASE(test_call_once_arbitrary_functor));
test->add(BOOST_TEST_CASE(test_call_once_retried_on_exception));
return test;
}

285
test/test_shared_mutex.cpp Normal file
View File

@@ -0,0 +1,285 @@
// (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/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#include "shared_mutex_locking_thread.hpp"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
boost::mutex::scoped_lock lock(mutex_name); \
BOOST_CHECK_EQUAL(value,expected_value); \
}
void test_multiple_readers()
{
unsigned const number_of_threads=10;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
{
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<number_of_threads)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,number_of_threads);
}
void test_only_one_writer_permitted()
{
unsigned const number_of_threads=10;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
{
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(2));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
void test_reader_blocks_writer()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<1)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,2U);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
void test_unlocking_writer_unblocks_all_readers()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
boost::unique_lock<boost::shared_mutex> write_lock(rw_mutex);
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=10;
try
{
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,0U);
write_lock.unlock();
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count);
}
void test_unlocking_last_reader_only_unblocks_one_writer()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_readers=0;
unsigned max_simultaneous_readers=0;
unsigned simultaneous_running_writers=0;
unsigned max_simultaneous_writers=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_reading_mutex;
boost::mutex::scoped_lock finish_reading_lock(finish_reading_mutex);
boost::mutex finish_writing_mutex;
boost::mutex::scoped_lock finish_writing_lock(finish_writing_mutex);
unsigned const reader_count=10;
unsigned const writer_count=10;
try
{
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_reading_mutex,simultaneous_running_readers,max_simultaneous_readers));
}
boost::thread::sleep(delay(1));
for(unsigned i=0;i<writer_count;++i)
{
pool.create_thread(locking_thread<boost::unique_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_writing_mutex,simultaneous_running_writers,max_simultaneous_writers));
}
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<reader_count)
{
unblocked_condition.wait(lk);
}
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count);
finish_reading_lock.unlock();
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_writing_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+writer_count);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_readers,reader_count);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_writers,1u);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_multiple_readers));
test->add(BOOST_TEST_CASE(&test_only_one_writer_permitted));
test->add(BOOST_TEST_CASE(&test_reader_blocks_writer));
test->add(BOOST_TEST_CASE(&test_unlocking_writer_unblocks_all_readers));
test->add(BOOST_TEST_CASE(&test_unlocking_last_reader_only_unblocks_one_writer));
return test;
}

View File

@@ -0,0 +1,290 @@
// (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/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#include "shared_mutex_locking_thread.hpp"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
boost::mutex::scoped_lock lock(mutex_name); \
BOOST_CHECK_EQUAL(value,expected_value); \
}
class simple_upgrade_thread
{
boost::shared_mutex& rwm;
boost::mutex& finish_mutex;
boost::mutex& unblocked_mutex;
unsigned& unblocked_count;
void operator=(simple_upgrade_thread&);
public:
simple_upgrade_thread(boost::shared_mutex& rwm_,
boost::mutex& finish_mutex_,
boost::mutex& unblocked_mutex_,
unsigned& unblocked_count_):
rwm(rwm_),finish_mutex(finish_mutex_),
unblocked_mutex(unblocked_mutex_),unblocked_count(unblocked_count_)
{}
void operator()()
{
boost::upgrade_lock<boost::shared_mutex> lk(rwm);
{
boost::mutex::scoped_lock ulk(unblocked_mutex);
++unblocked_count;
}
boost::mutex::scoped_lock flk(finish_mutex);
}
};
void test_only_one_upgrade_lock_permitted()
{
unsigned const number_of_threads=10;
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
try
{
for(unsigned i=0;i<number_of_threads;++i)
{
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,1U);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,number_of_threads);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,1u);
}
void test_can_lock_upgrade_if_currently_locked_shared()
{
boost::thread_group pool;
boost::shared_mutex rw_mutex;
unsigned unblocked_count=0;
unsigned simultaneous_running_count=0;
unsigned max_simultaneous_running=0;
boost::mutex unblocked_count_mutex;
boost::condition_variable unblocked_condition;
boost::mutex finish_mutex;
boost::mutex::scoped_lock finish_lock(finish_mutex);
unsigned const reader_count=10;
try
{
for(unsigned i=0;i<reader_count;++i)
{
pool.create_thread(locking_thread<boost::shared_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
}
boost::thread::sleep(delay(1));
pool.create_thread(locking_thread<boost::upgrade_lock<boost::shared_mutex> >(rw_mutex,unblocked_count,unblocked_count_mutex,unblocked_condition,
finish_mutex,simultaneous_running_count,max_simultaneous_running));
{
boost::mutex::scoped_lock lk(unblocked_count_mutex);
while(unblocked_count<(reader_count+1))
{
unblocked_condition.wait(lk);
}
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
finish_lock.unlock();
pool.join_all();
}
catch(...)
{
pool.interrupt_all();
pool.join_all();
throw;
}
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,unblocked_count,reader_count+1);
CHECK_LOCKED_VALUE_EQUAL(unblocked_count_mutex,max_simultaneous_running,reader_count+1);
}
void test_if_other_thread_has_write_lock_try_lock_shared_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_if_other_thread_has_write_lock_try_lock_upgrade_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
finish_lock.unlock();
writer.join();
}
void test_if_no_thread_has_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
}
void test_if_no_thread_has_lock_try_lock_upgrade_returns_true()
{
boost::shared_mutex rw_mutex;
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
}
void test_if_other_thread_has_shared_lock_try_lock_shared_returns_true()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_shared();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_if_other_thread_has_shared_lock_try_lock_upgrade_returns_true()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
finish_lock.unlock();
writer.join();
}
void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_upgrade_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
bool const try_succeeded=rw_mutex.try_lock_upgrade();
BOOST_CHECK(!try_succeeded);
if(try_succeeded)
{
rw_mutex.unlock_upgrade();
}
finish_lock.unlock();
writer.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
test->add(BOOST_TEST_CASE(&test_can_lock_upgrade_if_currently_locked_shared));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_write_lock_try_lock_shared_returns_false));
test->add(BOOST_TEST_CASE(&test_if_no_thread_has_lock_try_lock_shared_returns_true));
test->add(BOOST_TEST_CASE(&test_if_other_thread_has_shared_lock_try_lock_shared_returns_true));
return test;
}

View File

@@ -0,0 +1,268 @@
// (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/test/unit_test.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include "util.inl"
#include "shared_mutex_locking_thread.hpp"
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \
boost::mutex::scoped_lock lock(mutex_name); \
BOOST_CHECK_EQUAL(value,expected_value); \
}
void test_timed_lock_shared_times_out_if_write_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
boost::posix_time::milliseconds const timeout_resolution(50);
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
boost::posix_time::milliseconds const wait_duration(500);
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
writer.join();
}
void test_timed_lock_shared_succeeds_if_no_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
boost::posix_time::milliseconds const timeout_resolution(50);
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK(boost::get_system_time()<timeout);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
boost::posix_time::milliseconds const wait_duration(500);
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
BOOST_CHECK(boost::get_system_time()<timeout2);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
}
void test_timed_lock_shared_succeeds_if_read_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
boost::posix_time::milliseconds const timeout_resolution(50);
bool timed_lock_succeeded=rw_mutex.timed_lock_shared(timeout);
BOOST_CHECK(boost::get_system_time()<timeout);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
boost::posix_time::milliseconds const wait_duration(500);
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
BOOST_CHECK(boost::get_system_time()<timeout2);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
reader.join();
}
void test_timed_lock_times_out_if_write_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread writer(simple_writing_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
boost::posix_time::milliseconds const timeout_resolution(50);
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
boost::posix_time::milliseconds const wait_duration(500);
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
finish_lock.unlock();
writer.join();
}
void test_timed_lock_succeeds_if_no_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
boost::posix_time::milliseconds const timeout_resolution(50);
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
BOOST_CHECK(boost::get_system_time()<timeout);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
boost::posix_time::milliseconds const wait_duration(500);
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
BOOST_CHECK(boost::get_system_time()<timeout2);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
}
void test_timed_lock_times_out_if_read_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::thread::sleep(delay(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
boost::posix_time::milliseconds const timeout_resolution(50);
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
BOOST_CHECK((timeout-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
boost::posix_time::milliseconds const wait_duration(500);
boost::system_time const timeout2=boost::get_system_time()+wait_duration;
timed_lock_succeeded=rw_mutex.timed_lock(wait_duration);
BOOST_CHECK((timeout2-timeout_resolution)<boost::get_system_time());
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
finish_lock.unlock();
reader.join();
}
void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
{
boost::shared_mutex rw_mutex;
boost::mutex finish_mutex;
boost::mutex unblocked_mutex;
unsigned unblocked_count=0;
boost::mutex::scoped_lock finish_lock(finish_mutex);
boost::thread reader(simple_reading_thread(rw_mutex,finish_mutex,unblocked_mutex,unblocked_count));
boost::this_thread::sleep(boost::posix_time::seconds(1));
CHECK_LOCKED_VALUE_EQUAL(unblocked_mutex,unblocked_count,1u);
boost::system_time const start=boost::get_system_time();
boost::system_time const timeout=start+boost::posix_time::milliseconds(500);
bool timed_lock_succeeded=rw_mutex.timed_lock(timeout);
BOOST_CHECK(!timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock();
}
boost::posix_time::milliseconds const wait_duration(500);
timed_lock_succeeded=rw_mutex.timed_lock_shared(wait_duration);
BOOST_CHECK(timed_lock_succeeded);
if(timed_lock_succeeded)
{
rw_mutex.unlock_shared();
}
finish_lock.unlock();
reader.join();
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_times_out_if_write_lock_held));
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_no_lock_held));
test->add(BOOST_TEST_CASE(&test_timed_lock_shared_succeeds_if_read_lock_held));
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_write_lock_held));
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_if_read_lock_held));
test->add(BOOST_TEST_CASE(&test_timed_lock_succeeds_if_no_lock_held));
test->add(BOOST_TEST_CASE(&test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held));
return test;
}

View File

@@ -1,5 +1,6 @@
// Copyright (C) 2001-2003
// William E. Kempf
// Copyright (C) 2008 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)
@@ -8,6 +9,9 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/xtime.hpp>
#include <boost/bind.hpp>
#include <boost/ref.hpp>
#include <boost/utility.hpp>
#include <boost/test/unit_test.hpp>
@@ -21,12 +25,16 @@ void simple_thread()
test_value = 999;
}
void comparison_thread(boost::thread* parent)
void comparison_thread(boost::thread::id parent)
{
boost::thread thrd;
BOOST_CHECK(thrd != *parent);
boost::thread thrd2;
BOOST_CHECK(thrd == thrd2);
boost::thread::id const my_id=boost::this_thread::get_id();
BOOST_CHECK(my_id != parent);
boost::thread::id const my_id2=boost::this_thread::get_id();
BOOST_CHECK(my_id == my_id2);
boost::thread::id const no_thread_id=boost::thread::id();
BOOST_CHECK(my_id != no_thread_id);
}
void test_sleep()
@@ -52,18 +60,162 @@ void test_creation()
timed_test(&do_test_creation, 1);
}
void do_test_comparison()
void do_test_id_comparison()
{
boost::thread self;
boost::thread thrd(bind(&comparison_thread, &self));
boost::thread::id const self=boost::this_thread::get_id();
boost::thread thrd(boost::bind(&comparison_thread, self));
thrd.join();
}
void test_comparison()
void test_id_comparison()
{
timed_test(&do_test_comparison, 1);
timed_test(&do_test_id_comparison, 1);
}
void interruption_point_thread(boost::mutex* m,bool* failed)
{
boost::mutex::scoped_lock lk(*m);
boost::this_thread::interruption_point();
*failed=true;
}
void do_test_thread_interrupts_at_interruption_point()
{
boost::mutex m;
bool failed=false;
boost::mutex::scoped_lock lk(m);
boost::thread thrd(boost::bind(&interruption_point_thread,&m,&failed));
thrd.interrupt();
lk.unlock();
thrd.join();
BOOST_CHECK(!failed);
}
void test_thread_interrupts_at_interruption_point()
{
timed_test(&do_test_thread_interrupts_at_interruption_point, 1);
}
void disabled_interruption_point_thread(boost::mutex* m,bool* failed)
{
boost::mutex::scoped_lock lk(*m);
boost::this_thread::disable_interruption dc;
boost::this_thread::interruption_point();
*failed=false;
}
void do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
{
boost::mutex m;
bool failed=true;
boost::mutex::scoped_lock lk(m);
boost::thread thrd(boost::bind(&disabled_interruption_point_thread,&m,&failed));
thrd.interrupt();
lk.unlock();
thrd.join();
BOOST_CHECK(!failed);
}
void test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point()
{
timed_test(&do_test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point, 1);
}
struct non_copyable_functor:
boost::noncopyable
{
unsigned value;
non_copyable_functor():
value(0)
{}
void operator()()
{
value=999;
}
};
void do_test_creation_through_reference_wrapper()
{
non_copyable_functor f;
boost::thread thrd(boost::ref(f));
thrd.join();
BOOST_CHECK_EQUAL(f.value, 999u);
}
void test_creation_through_reference_wrapper()
{
timed_test(&do_test_creation_through_reference_wrapper, 1);
}
struct long_running_thread
{
boost::condition_variable cond;
boost::mutex mut;
bool done;
long_running_thread():
done(false)
{}
void operator()()
{
boost::mutex::scoped_lock lk(mut);
while(!done)
{
cond.wait(lk);
}
}
};
void do_test_timed_join()
{
long_running_thread f;
boost::thread thrd(boost::ref(f));
BOOST_CHECK(thrd.joinable());
boost::system_time xt=delay(3);
bool const joined=thrd.timed_join(xt);
BOOST_CHECK(in_range(boost::get_xtime(xt), 2));
BOOST_CHECK(!joined);
BOOST_CHECK(thrd.joinable());
{
boost::mutex::scoped_lock lk(f.mut);
f.done=true;
f.cond.notify_one();
}
xt=delay(3);
bool const joined2=thrd.timed_join(xt);
boost::system_time const now=boost::get_system_time();
BOOST_CHECK(xt>now);
BOOST_CHECK(joined2);
BOOST_CHECK(!thrd.joinable());
}
void test_timed_join()
{
timed_test(&do_test_timed_join, 10);
}
void test_swap()
{
boost::thread t(simple_thread);
boost::thread t2(simple_thread);
boost::thread::id id1=t.get_id();
boost::thread::id id2=t2.get_id();
t.swap(t2);
BOOST_CHECK(t.get_id()==id2);
BOOST_CHECK(t2.get_id()==id1);
swap(t,t2);
BOOST_CHECK(t.get_id()==id1);
BOOST_CHECK(t2.get_id()==id2);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
@@ -71,7 +223,12 @@ boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
test->add(BOOST_TEST_CASE(test_sleep));
test->add(BOOST_TEST_CASE(test_creation));
test->add(BOOST_TEST_CASE(test_comparison));
test->add(BOOST_TEST_CASE(test_id_comparison));
test->add(BOOST_TEST_CASE(test_thread_interrupts_at_interruption_point));
test->add(BOOST_TEST_CASE(test_thread_no_interrupt_if_interrupts_disabled_at_interruption_point));
test->add(BOOST_TEST_CASE(test_creation_through_reference_wrapper));
test->add(BOOST_TEST_CASE(test_timed_join));
test->add(BOOST_TEST_CASE(test_swap));
return test;
}

149
test/test_thread_id.cpp Normal file
View File

@@ -0,0 +1,149 @@
// Copyright (C) 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/thread.hpp>
#include <boost/test/unit_test.hpp>
#include <boost/bind.hpp>
void do_nothing()
{}
void test_thread_id_for_default_constructed_thread_is_default_constructed_id()
{
boost::thread t;
BOOST_CHECK(t.get_id()==boost::thread::id());
}
void test_thread_id_for_running_thread_is_not_default_constructed_id()
{
boost::thread t(do_nothing);
BOOST_CHECK(t.get_id()!=boost::thread::id());
t.join();
}
void test_different_threads_have_different_ids()
{
boost::thread t(do_nothing);
boost::thread t2(do_nothing);
BOOST_CHECK(t.get_id()!=t2.get_id());
t.join();
t2.join();
}
void test_thread_ids_have_a_total_order()
{
boost::thread t(do_nothing);
boost::thread t2(do_nothing);
boost::thread t3(do_nothing);
BOOST_CHECK(t.get_id()!=t2.get_id());
BOOST_CHECK(t.get_id()!=t3.get_id());
BOOST_CHECK(t2.get_id()!=t3.get_id());
BOOST_CHECK((t.get_id()<t2.get_id()) != (t2.get_id()<t.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) != (t3.get_id()<t.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) != (t3.get_id()<t2.get_id()));
BOOST_CHECK((t.get_id()>t2.get_id()) != (t2.get_id()>t.get_id()));
BOOST_CHECK((t.get_id()>t3.get_id()) != (t3.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()>t3.get_id()) != (t3.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>t.get_id()));
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>t3.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>t2.get_id()));
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>t3.get_id()));
BOOST_CHECK((t.get_id()<t2.get_id()) == (t2.get_id()>=t.get_id()));
BOOST_CHECK((t2.get_id()<t.get_id()) == (t.get_id()>=t2.get_id()));
BOOST_CHECK((t.get_id()<t3.get_id()) == (t3.get_id()>=t.get_id()));
BOOST_CHECK((t3.get_id()<t.get_id()) == (t.get_id()>=t3.get_id()));
BOOST_CHECK((t2.get_id()<t3.get_id()) == (t3.get_id()>=t2.get_id()));
BOOST_CHECK((t3.get_id()<t2.get_id()) == (t2.get_id()>=t3.get_id()));
BOOST_CHECK((t.get_id()<=t2.get_id()) == (t2.get_id()>t.get_id()));
BOOST_CHECK((t2.get_id()<=t.get_id()) == (t.get_id()>t2.get_id()));
BOOST_CHECK((t.get_id()<=t3.get_id()) == (t3.get_id()>t.get_id()));
BOOST_CHECK((t3.get_id()<=t.get_id()) == (t.get_id()>t3.get_id()));
BOOST_CHECK((t2.get_id()<=t3.get_id()) == (t3.get_id()>t2.get_id()));
BOOST_CHECK((t3.get_id()<=t2.get_id()) == (t2.get_id()>t3.get_id()));
if((t.get_id()<t2.get_id()) && (t2.get_id()<t3.get_id()))
{
BOOST_CHECK(t.get_id()<t3.get_id());
}
else if((t.get_id()<t3.get_id()) && (t3.get_id()<t2.get_id()))
{
BOOST_CHECK(t.get_id()<t2.get_id());
}
else if((t2.get_id()<t3.get_id()) && (t3.get_id()<t.get_id()))
{
BOOST_CHECK(t2.get_id()<t.get_id());
}
else if((t2.get_id()<t.get_id()) && (t.get_id()<t3.get_id()))
{
BOOST_CHECK(t2.get_id()<t3.get_id());
}
else if((t3.get_id()<t.get_id()) && (t.get_id()<t2.get_id()))
{
BOOST_CHECK(t3.get_id()<t2.get_id());
}
else if((t3.get_id()<t2.get_id()) && (t2.get_id()<t.get_id()))
{
BOOST_CHECK(t3.get_id()<t.get_id());
}
else
{
BOOST_CHECK(false);
}
boost::thread::id default_id;
BOOST_CHECK(default_id < t.get_id());
BOOST_CHECK(default_id < t2.get_id());
BOOST_CHECK(default_id < t3.get_id());
BOOST_CHECK(default_id <= t.get_id());
BOOST_CHECK(default_id <= t2.get_id());
BOOST_CHECK(default_id <= t3.get_id());
BOOST_CHECK(!(default_id > t.get_id()));
BOOST_CHECK(!(default_id > t2.get_id()));
BOOST_CHECK(!(default_id > t3.get_id()));
BOOST_CHECK(!(default_id >= t.get_id()));
BOOST_CHECK(!(default_id >= t2.get_id()));
BOOST_CHECK(!(default_id >= t3.get_id()));
t.join();
t2.join();
t3.join();
}
void get_thread_id(boost::thread::id* id)
{
*id=boost::this_thread::get_id();
}
void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
{
boost::thread::id id;
boost::thread t(boost::bind(get_thread_id,&id));
boost::thread::id t_id=t.get_id();
t.join();
BOOST_CHECK(id==t_id);
}
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
{
boost::unit_test_framework::test_suite* test =
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
test->add(BOOST_TEST_CASE(test_thread_id_for_default_constructed_thread_is_default_constructed_id));
test->add(BOOST_TEST_CASE(test_thread_id_for_running_thread_is_not_default_constructed_id));
test->add(BOOST_TEST_CASE(test_different_threads_have_different_ids));
test->add(BOOST_TEST_CASE(test_thread_ids_have_a_total_order));
test->add(BOOST_TEST_CASE(test_thread_id_of_running_thread_returned_by_this_thread_get_id));
return test;
}

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