mirror of
https://github.com/boostorg/thread.git
synced 2026-02-03 09:42:16 +00:00
Compare commits
7 Commits
boost-1.46
...
boost-1.49
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cf4dd909d5 | ||
|
|
09362f0eac | ||
|
|
32b3f3f569 | ||
|
|
8affa33718 | ||
|
|
b991c9a8a0 | ||
|
|
ab665c8c56 | ||
|
|
7ec9804540 |
@@ -5,7 +5,45 @@
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:changes Changes since boost 1.40]
|
||||
[section:changes Changes since]
|
||||
|
||||
[heading Changes since boost 1.41]
|
||||
|
||||
Fixed Bugs:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2309 #2309] Lack of g++ symbol visibility support in Boost.Thread.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2639 #2639] documentation should be extended(defer_lock, try_to_lock, ...).
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3639 #3639] Boost.Thread doesn't build with Sun-5.9 on Linux.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3762 #3762] Thread can't be compiled with winscw (Codewarrior by Nokia).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3885 #3885] document about mix usage of boost.thread and native thread api.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3975 #3975] Incorrect precondition for promise::set_wait_callback().
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4048 #4048] thread::id formatting involves locale
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4315 #4315] gcc 4.4 Warning: inline ... declared as dllimport: attribute ignored.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4480 #4480] OpenVMS patches for compiler issues workarounds.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4819 #4819] boost.thread's documentation misprints.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5040 #5040] future.hpp in boost::thread does not compile with /clr.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5423 #5423] thread issues with C++0x.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5502 #5502] race condition between shared_mutex timed_lock and lock_shared.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5594 #5594] boost::shared_mutex not fully compatible with Windows CE.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5617 #5617] boost::thread::id copy ctor.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5739 #5739] set-but-not-used warnings with gcc-4.6.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5826 #5826] threads.cpp: resource leak on threads creation failure.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5839 #5839] thread.cpp: ThreadProxy leaks on exceptions.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/5859 #5859] win32 shared_mutex constructor leaks on exceptions.
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6100 #6100] Compute hardware_concurrency() using get_nprocs() on GLIBC systems.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6141 #6141] Compilation error when boost.thread and boost.move are used together.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6168 #6168] recursive_mutex is using wrong config symbol (possible typo).
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6175 #6175] Compile error with SunStudio.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6200 #6200] patch to have condition_variable and mutex error better handle EINTR.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6207 #6207] shared_lock swap compiler error on clang 3.0 c++11.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6208 #6208] try_lock_wrapper swap compiler error on clang 3.0 c++11.
|
||||
|
||||
|
||||
[heading Changes since boost 1.40]
|
||||
|
||||
The 1.41.0 release of Boost adds futures to the thread library. There are also a few minor changes.
|
||||
|
||||
@@ -85,3 +123,22 @@ been moved to __thread_id__.
|
||||
unlocked one level, and not completely. This prior behaviour was not guaranteed and did not feature in the tests.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:future Future]
|
||||
|
||||
The following features will be included in next releases. By order of priority:
|
||||
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6194 #6194] Adapt to Boost.Move.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/4710 #4710] Missing async().
|
||||
* [@http://svn.boost.org/trac/boost/ticket/6195 #6195] Provide the standard time related interface using Boost.Chrono.
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2637 #2637] shared mutex lock
|
||||
* Lock guards
|
||||
* [@http://svn.boost.org/trac/boost/ticket/1850 #1850] request for unlock_guard (and/or unique_unlock) to compliment lock_guard/unique_lock
|
||||
* [@http://svn.boost.org/trac/boost/ticket/3567 #3567] Request for shared_lock_guard
|
||||
* [@http://svn.boost.org/trac/boost/ticket/2741 #2741] Proposal to manage portable and non portable thread attributes.
|
||||
* #2880 Request for Thread scheduler support for boost ..
|
||||
* #3696 Boost Thread library lacks any way to set priority of threads
|
||||
* #5956 Add optional stack_size argument to thread::start_thread()
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
100
doc/compliance.qbk
Normal file
100
doc/compliance.qbk
Normal file
@@ -0,0 +1,100 @@
|
||||
[/
|
||||
(C) Copyright 2011 Vicente J. Botet Escriba.
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or copy at
|
||||
http://www.boost.org/LICENSE_1_0.txt).
|
||||
]
|
||||
|
||||
[section:compliance Compliance with standard]
|
||||
|
||||
[section:cpp11 C++11 standard Thread library]
|
||||
|
||||
|
||||
[table Compliance C++11 standard
|
||||
[[Section] [Description] [Status] [Comments] [Ticket]]
|
||||
[[30] [Thread support library] [Partial] [-] [-]]
|
||||
[[30.1] [General] [-] [-] [-]]
|
||||
[[30.2] [Requirements] [-] [-] [-]]
|
||||
[[30.2.1] [Template parameter names] [-] [-] [-]]
|
||||
[[30.2.2] [Exceptions] [No] [-] [#12]]
|
||||
[[30.2.3] [Native handles] [Yes] [-] [-]]
|
||||
[[30.2.4] [Timing specifications] [No] [-] [#6195]]
|
||||
[[30.2.5] [Requirements for Lockable types] [Partial] [-] [-]]
|
||||
[[30.2.5.1] [In general] [-] [-] [-]]
|
||||
[[30.2.5.2] [BasicLockable requirements] [No] [-] [#13]]
|
||||
[[30.2.5.3] [Lockable requirements] [yes] [-] [-]]
|
||||
[[30.2.5.4] [TimedLockable requirements] [Partial] [chrono] [#6195]]
|
||||
[[30.2.6] [decay_copy] [-] [-] [-]]
|
||||
[[30.3] [Threads] [Partial] [-] [-]]
|
||||
[[30.3.1] [Class thread] [Partial] [-] [-]]
|
||||
[[30.3.1.1] [Class thread::id] [Partial] [Missing noexcept, template <> struct hash<thread::id>] [#3,#4]]
|
||||
[[30.3.1.2] [thread constructors] [Partial] [Missing noexcept and move semantics] [#3,#6194]]
|
||||
[[30.3.1.3] [thread destructor] [Yes] [-] [-]]
|
||||
[[30.3.1.4] [thread assignment] [Partial] [move semantics] [-]]
|
||||
[[30.3.1.5] [thread members] [Partial] [Missing noexcept, chrono] [#3,#6195]]
|
||||
[[30.3.1.6] [thread static members] [Partial] [Missing noexcept] [#3,#6195]]
|
||||
[[30.3.1.7] [thread specialized algorithms] [Yes] [-] [-]]
|
||||
[[30.3.2] [Namespace this_thread] [Partial] [chrono] [#6195]]
|
||||
[[30.4] [Mutual exclusion] [Partial] [-] [-]]
|
||||
[[30.4.1] [Mutex requirements] [Partial] [-] [-]]
|
||||
[[30.4.1.1] [In general] [Partial] [-] [-]]
|
||||
[[30.4.1.2] [Mutex types] [Partial] [noexcept,delete] [#3,#5]]
|
||||
[[30.4.1.2.1] [Class mutex] [Partial] [noexcept,delete] [#3,#5]]
|
||||
[[30.4.1.2.2] [Class recursive_mutex] [Partial] [noexcept,delete] [#3,#5]]
|
||||
[[30.4.1.3] [Timed mutex types] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
|
||||
[[30.4.1.3.1] [Class timed_mutex] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
|
||||
[[30.4.1.3.1] [Class recursive_timed_mutex] [Partial] [noexcept,chrono,delete] [#3,#6195,#5]]
|
||||
[[30.4.2] [Locks] [Partial] [noexcept,chrono,move,delete,bool] [#3,#6195,#5,#6]]
|
||||
[[30.4.2.1] [Class template lock_guard] [Partial] [cons/dest delete] [#5]]
|
||||
[[30.4.2.2] [Class template unique_lock] [Partial] [noexcept, chrono, move, delete] [#3,#6195,#5,#6]]
|
||||
[[30.4.2.2.1] [unique_lock constructors, destructor, and assignment] [Partial] [noexcept, chrono, move, delete] [#3,#6195,#5,#6]]
|
||||
[[30.4.2.2.2] [unique_lock locking] [Partial] [chrono] [,#6195,]]
|
||||
[[30.4.2.2.3] [unique_lock modifiers] [Yes] [-] [-]]
|
||||
[[30.4.2.2.4] [unique_lock observers] [Partial] [explicit operator bool] [#6]]
|
||||
[[30.4.3] [Generic locking algorithms] [Partial] [Variadic,] [#7]]
|
||||
[[30.4.4] [Call once] [Partial] [move,variadic] [#6194,#7]]
|
||||
[[30.4.4.1] [Struct once_flag] [Yes] [-] [-]]
|
||||
[[30.4.4.2] [Function call_once] [Yes] [-] [-]]
|
||||
[[30.5] [Condition variables] [Partial] [chrono,cv_status,notify_all_at_thread_exit] [#6195,#8,#9]]
|
||||
[[30.5 6-10] [Function notify_all_at_thread_exit] [No] [-] [#9]]
|
||||
[[30.5.1] [Class condition_variable] [Partial] [chrono,cv_status] [#6195,#8]]
|
||||
[[30.5.2] [Class condition_variable_any] [Partial] [chrono,cv_status] [#6195,#8]]
|
||||
[[30.6] [Futures] [Partial] [-] [-]]
|
||||
[[30.6.1] [Overview] [Partial] [-] [-]]
|
||||
[[30.6.2] [Error handling] [No] [-] [-]]
|
||||
[[30.6.3] [Class future_error] [No] [-] [-]]
|
||||
[[30.6.4] [Shared state] [No] [-] [-]]
|
||||
[[30.6.5] [Class template promise] [Partial] [allocator,move,delete] [#10,#6194,#5]]
|
||||
[[30.6.6] [Class template future] [No] [unique_future is the closest to future] [#11]]
|
||||
[[30.6.7] [Class template shared_future] [Partial] [allocator,move,delete] [#10,#6194,#5]]
|
||||
[[30.6.8] [Function template async] [No] [async] [#4710]]
|
||||
[[30.6.8] [Class template packaged_task] [Partial] [-] [-]]
|
||||
]
|
||||
|
||||
|
||||
[table Extension
|
||||
[[Section] [Description] [Comments]]
|
||||
[[30.3.1.5.x] [interrupt] [-]]
|
||||
[[30.3.1.5.y] [operator==,operator!=] [-]]
|
||||
[[30.3.2.x] [Interruprion] [-]]
|
||||
[[30.3.2.y] [at_thread_exit] [-]]
|
||||
[[30.4.3.x] [Generic locking algorithms begin/end] [-]]
|
||||
[[30.x] [Barriers] [-]]
|
||||
[[30.y] [Thread Local Storage] [-]]
|
||||
[[30.z] [Class thread_group] [-]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:shared Shared Mutex library extension]
|
||||
|
||||
[table Clock Requirements
|
||||
[[Section] [Description] [Status] [Comments]]
|
||||
[[XXXX] [DDDD] [SSSS] [CCCC]]
|
||||
[[XXXX] [DDDD] [SSSS] [CCCC]]
|
||||
]
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[endsect]
|
||||
@@ -701,7 +701,7 @@ required for storage of the result cannot be allocated.]]
|
||||
|
||||
[variablelist
|
||||
|
||||
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __packaged_task__ shall be well-formed. Invoking a copy of
|
||||
[[Preconditions:] [The expression `f(t)` where `t` is a lvalue of type __promise__ shall be well-formed. Invoking a copy of
|
||||
`f` shall have the same effect as invoking `f`]]
|
||||
|
||||
[[Effects:] [Store a copy of `f` with the asynchronous result associated with `*this` as a ['wait callback]. This will replace any
|
||||
|
||||
@@ -310,6 +310,25 @@ without blocking.]]
|
||||
|
||||
[section:locks Lock Types]
|
||||
|
||||
[section:lock_tags Lock option tags]
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
struct defer_lock_t {};
|
||||
struct try_to_lock_t {};
|
||||
struct adopt_lock_t {};
|
||||
const defer_lock_t defer_lock;
|
||||
const try_to_lock_t try_to_lock;
|
||||
const adopt_lock_t adopt_lock;
|
||||
|
||||
These tags are used in scoped locks constructors to specify a specific behavior.
|
||||
|
||||
*`defer_lock_t`: is used to construct the scoped lock without locking it.
|
||||
*`try_to_lock_t`: is used to construct the scoped lock trying to lock it.
|
||||
*`adopt_lock_t`: is used to construct the scoped lock without locking it but adopting ownership.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:lock_guard Class template `lock_guard`]
|
||||
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
@@ -166,3 +166,5 @@
|
||||
[include time.qbk]
|
||||
|
||||
[include acknowledgements.qbk]
|
||||
|
||||
[include compliance.qbk]
|
||||
|
||||
@@ -163,6 +163,44 @@ Each instance of __thread_id__ either refers to some thread, or __not_a_thread__
|
||||
compare equal to each other, but not equal to any instances that refer to an actual thread of execution. The comparison operators on
|
||||
__thread_id__ yield a total order for every non-equal thread ID.
|
||||
|
||||
[heading Using native interfaces with Boost.Thread resources]
|
||||
|
||||
|
||||
__thread__ class has members `native_handle_type` and `native_handle` providing access to the underlying native handle.
|
||||
|
||||
This native handle can be used to change for example the scheduling.
|
||||
|
||||
|
||||
In general, it is not safe to use this handle with operations that can conflict with the ones provided by Boost.Thread. An example of bad usage could be detaching a thread directly as it will not change the internals of the __thread__ instance, so for example the joinable function will continue to return true, while the native thread is no more joinable.
|
||||
|
||||
thread t(fct);
|
||||
thread::native_handle_type hnd=t.native_handle();
|
||||
pthread_detach(hnd);
|
||||
assert(t.joinable());
|
||||
|
||||
[heading Using Boost.Thread interfaces in a native thread]
|
||||
|
||||
|
||||
Any thread of execution created using the native interface is called a native thread in this documentation.
|
||||
|
||||
The first example of a native thread of execution is the main thread.
|
||||
|
||||
The user can access to some synchronization functions related to the native current thread using the `boost::this_thread` `yield`, `sleep`, functions.
|
||||
|
||||
|
||||
int main() {
|
||||
// ...
|
||||
boost::this_thread::sleep();
|
||||
// ...
|
||||
}
|
||||
|
||||
|
||||
Of course all the synchronization facilities provided by Boost.Thread are also available on native threads.
|
||||
|
||||
The `boost::this_thread` interrupt related functions behave in a degraded mode when called from a thread created using the native interface, i.e. `boost::this_thread::interruption_enabled()` returns false. As consequence the use of `boost::this_thread::disable_interruption` and `boost::this_thread::restore_interruption` will do nothing and calls to `boost::this_thread::interrupt_point()` will be just ignored.
|
||||
|
||||
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` wiil returns false for the native threads.
|
||||
|
||||
[section:thread Class `thread`]
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
@@ -675,7 +713,7 @@ execution.]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section:less_than_or_equal `operator>=`]
|
||||
[section:less_than_or_equal `operator<=`]
|
||||
|
||||
bool operator<=(const id& y) const;
|
||||
|
||||
|
||||
@@ -41,6 +41,11 @@ order. If a cleanup routine sets the value of associated with an instance of `bo
|
||||
cleaned up, that value is added to the cleanup list. Cleanup finishes when there are no outstanding instances of
|
||||
`boost::thread_specific_ptr` with values.
|
||||
|
||||
Note: on some platforms, cleanup of thread-specific data is not
|
||||
performed for threads created with the platform's native API. On those
|
||||
platforms such cleanup is only done for threads that are started with
|
||||
`boost::thread` unless `boost::on_thread_exit()` is called manually
|
||||
from that thread.
|
||||
|
||||
[section:thread_specific_ptr Class `thread_specific_ptr`]
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (C) 2001-2003
|
||||
// William E. Kempf
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifndef BOOST_THREAD_CONFIG_WEK01032003_HPP
|
||||
@@ -10,6 +10,15 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
|
||||
#if !defined BOOST_THREAD_VERSION
|
||||
#define BOOST_THREAD_VERSION 1
|
||||
#else
|
||||
#if BOOST_THREAD_VERSION!=1 && BOOST_THREAD_VERSION!=2
|
||||
#error "BOOST_THREAD_VERSION must be 1 or 2"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
|
||||
# pragma warn -8008 // Condition always true/false
|
||||
# pragma warn -8080 // Identifier declared but never used
|
||||
@@ -53,12 +62,18 @@
|
||||
|
||||
#if defined(BOOST_HAS_DECLSPEC)
|
||||
# if defined(BOOST_THREAD_BUILD_DLL) //Build dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_EXPORT
|
||||
//# define BOOST_THREAD_DECL __declspec(dllexport)
|
||||
|
||||
# elif defined(BOOST_THREAD_USE_DLL) //Use dll
|
||||
# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_IMPORT
|
||||
//# define BOOST_THREAD_DECL __declspec(dllimport)
|
||||
# else
|
||||
# define BOOST_THREAD_DECL
|
||||
# endif
|
||||
#elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) || (__GNUC__ > 4)
|
||||
# define BOOST_THREAD_DECL BOOST_SYMBOL_VISIBLE
|
||||
|
||||
#else
|
||||
# define BOOST_THREAD_DECL
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
@@ -69,7 +84,7 @@
|
||||
#if !defined(BOOST_ALL_NO_LIB) && !defined(BOOST_THREAD_NO_LIB) && !defined(BOOST_THREAD_BUILD_DLL) && !defined(BOOST_THREAD_BUILD_LIB)
|
||||
//
|
||||
// Tell the autolink to link dynamically, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
// once it's done with it:
|
||||
//
|
||||
#if defined(BOOST_THREAD_USE_DLL)
|
||||
# define BOOST_DYN_LINK
|
||||
|
||||
@@ -6,15 +6,20 @@
|
||||
#ifndef BOOST_THREAD_MOVE_HPP
|
||||
#define BOOST_THREAD_MOVE_HPP
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#endif
|
||||
|
||||
#include <boost/move/move.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename T>
|
||||
@@ -41,18 +46,19 @@ namespace boost
|
||||
|
||||
#ifndef BOOST_NO_SFINAE
|
||||
template<typename T>
|
||||
typename enable_if<boost::is_convertible<T&,detail::thread_move_t<T> >, detail::thread_move_t<T> >::type move(T& t)
|
||||
typename enable_if<boost::is_convertible<T&,boost::detail::thread_move_t<T> >, boost::detail::thread_move_t<T> >::type move(T& t)
|
||||
{
|
||||
return detail::thread_move_t<T>(t);
|
||||
return boost::detail::thread_move_t<T>(t);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template<typename T>
|
||||
detail::thread_move_t<T> move(detail::thread_move_t<T> t)
|
||||
boost::detail::thread_move_t<T> move(boost::detail::thread_move_t<T> t)
|
||||
{
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-10 Anthony Williams
|
||||
|
||||
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
#include <ostream>
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <memory>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <boost/io/ios_state.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -55,7 +56,7 @@ namespace boost
|
||||
thread_data(detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
#endif
|
||||
#endif
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
@@ -80,7 +81,7 @@ namespace boost
|
||||
thread_data(boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
@@ -99,14 +100,14 @@ namespace boost
|
||||
thread_data(const boost::reference_wrapper<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
|
||||
void run()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class BOOST_THREAD_DECL thread
|
||||
{
|
||||
private:
|
||||
@@ -114,11 +115,11 @@ namespace boost
|
||||
thread& operator=(thread&);
|
||||
|
||||
void release_handle();
|
||||
|
||||
|
||||
detail::thread_data_ptr thread_info;
|
||||
|
||||
void start_thread();
|
||||
|
||||
|
||||
explicit thread(detail::thread_data_ptr data);
|
||||
|
||||
detail::thread_data_ptr get_thread_info BOOST_PREVENT_MACRO_SUBSTITUTION () const;
|
||||
@@ -149,8 +150,8 @@ namespace boost
|
||||
struct dummy;
|
||||
public:
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
thread(const volatile thread&);
|
||||
#endif
|
||||
thread(const volatile thread&);
|
||||
#endif
|
||||
thread();
|
||||
~thread();
|
||||
|
||||
@@ -175,7 +176,7 @@ namespace boost
|
||||
{
|
||||
thread_info.swap(other.thread_info);
|
||||
}
|
||||
|
||||
|
||||
thread& operator=(thread&& other)
|
||||
{
|
||||
thread_info=other.thread_info;
|
||||
@@ -187,7 +188,7 @@ namespace boost
|
||||
{
|
||||
return static_cast<thread&&>(*this);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
#ifdef BOOST_NO_SFINAE
|
||||
template <class F>
|
||||
@@ -204,7 +205,7 @@ namespace boost
|
||||
start_thread();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template <class F>
|
||||
explicit thread(detail::thread_move_t<F> f):
|
||||
thread_info(make_thread_info(f))
|
||||
@@ -217,13 +218,13 @@ namespace boost
|
||||
thread_info=x->thread_info;
|
||||
x->thread_info.reset();
|
||||
}
|
||||
|
||||
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
thread& operator=(thread x)
|
||||
{
|
||||
swap(x);
|
||||
return *this;
|
||||
}
|
||||
thread& operator=(thread x)
|
||||
{
|
||||
swap(x);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
thread& operator=(detail::thread_move_t<thread> x)
|
||||
{
|
||||
@@ -231,12 +232,12 @@ namespace boost
|
||||
swap(new_thread);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
operator detail::thread_move_t<thread>()
|
||||
{
|
||||
return move();
|
||||
}
|
||||
|
||||
|
||||
detail::thread_move_t<thread> move()
|
||||
{
|
||||
detail::thread_move_t<thread> x(*this);
|
||||
@@ -312,7 +313,7 @@ namespace boost
|
||||
thread_info.swap(x.thread_info);
|
||||
}
|
||||
|
||||
class id;
|
||||
class BOOST_SYMBOL_VISIBLE id;
|
||||
id get_id() const;
|
||||
|
||||
|
||||
@@ -340,7 +341,7 @@ namespace boost
|
||||
{
|
||||
this_thread::yield();
|
||||
}
|
||||
|
||||
|
||||
static inline void sleep(const system_time& xt)
|
||||
{
|
||||
this_thread::sleep(xt);
|
||||
@@ -355,7 +356,7 @@ namespace boost
|
||||
{
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
inline thread&& move(thread& t)
|
||||
{
|
||||
@@ -380,17 +381,17 @@ namespace boost
|
||||
bool BOOST_THREAD_DECL interruption_enabled();
|
||||
bool BOOST_THREAD_DECL interruption_requested();
|
||||
|
||||
inline void sleep(xtime const& abs_time)
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(xtime const& abs_time)
|
||||
{
|
||||
sleep(system_time(abs_time));
|
||||
}
|
||||
}
|
||||
|
||||
class thread::id
|
||||
class BOOST_SYMBOL_VISIBLE thread::id
|
||||
{
|
||||
private:
|
||||
detail::thread_data_ptr thread_data;
|
||||
|
||||
|
||||
id(detail::thread_data_ptr thread_data_):
|
||||
thread_data(thread_data_)
|
||||
{}
|
||||
@@ -400,32 +401,36 @@ namespace boost
|
||||
id():
|
||||
thread_data()
|
||||
{}
|
||||
|
||||
|
||||
id(const id& other):
|
||||
thread_data(other.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);
|
||||
@@ -434,12 +439,14 @@ namespace boost
|
||||
#ifndef BOOST_NO_IOSTREAM
|
||||
#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
template<class charT, class traits>
|
||||
friend std::basic_ostream<charT, traits>&
|
||||
friend BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const id& x)
|
||||
{
|
||||
if(x.thread_data)
|
||||
{
|
||||
return os<<x.thread_data;
|
||||
io::ios_flags_saver ifs( os );
|
||||
return os<< std::hex << x.thread_data;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -448,7 +455,8 @@ namespace boost
|
||||
}
|
||||
#else
|
||||
template<class charT, class traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
print(std::basic_ostream<charT, traits>& os) const
|
||||
{
|
||||
if(thread_data)
|
||||
@@ -467,7 +475,8 @@ namespace boost
|
||||
|
||||
#if !defined(BOOST_NO_IOSTREAM) && defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template<class charT, class traits>
|
||||
std::basic_ostream<charT, traits>&
|
||||
BOOST_SYMBOL_VISIBLE
|
||||
std::basic_ostream<charT, traits>&
|
||||
operator<<(std::basic_ostream<charT, traits>& os, const thread::id& x)
|
||||
{
|
||||
return x.print(os);
|
||||
@@ -478,12 +487,12 @@ namespace boost
|
||||
{
|
||||
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
|
||||
@@ -492,26 +501,33 @@ namespace boost
|
||||
{}
|
||||
virtual void operator()()=0;
|
||||
};
|
||||
|
||||
|
||||
template<typename F>
|
||||
struct thread_exit_function:
|
||||
thread_exit_function_base
|
||||
{
|
||||
F f;
|
||||
|
||||
|
||||
thread_exit_function(F f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
|
||||
void operator()()
|
||||
{
|
||||
f();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
void BOOST_THREAD_DECL add_thread_exit_function(thread_exit_function_base*);
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <>
|
||||
struct has_move_emulation_enabled_aux<thread>
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
template<typename F>
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
namespace boost
|
||||
{
|
||||
|
||||
class thread_interrupted
|
||||
class BOOST_SYMBOL_VISIBLE thread_interrupted
|
||||
{};
|
||||
|
||||
class thread_exception:
|
||||
class BOOST_SYMBOL_VISIBLE thread_exception:
|
||||
public std::exception
|
||||
{
|
||||
protected:
|
||||
@@ -55,7 +55,7 @@ namespace boost
|
||||
int m_sys_err;
|
||||
};
|
||||
|
||||
class condition_error:
|
||||
class BOOST_SYMBOL_VISIBLE condition_error:
|
||||
public std::exception
|
||||
{
|
||||
public:
|
||||
@@ -66,7 +66,7 @@ namespace boost
|
||||
};
|
||||
|
||||
|
||||
class lock_error:
|
||||
class BOOST_SYMBOL_VISIBLE lock_error:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
@@ -87,7 +87,7 @@ namespace boost
|
||||
}
|
||||
};
|
||||
|
||||
class thread_resource_error:
|
||||
class BOOST_SYMBOL_VISIBLE thread_resource_error:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
@@ -109,7 +109,7 @@ namespace boost
|
||||
|
||||
};
|
||||
|
||||
class unsupported_thread_option:
|
||||
class BOOST_SYMBOL_VISIBLE unsupported_thread_option:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
@@ -131,7 +131,7 @@ namespace boost
|
||||
|
||||
};
|
||||
|
||||
class invalid_thread_argument:
|
||||
class BOOST_SYMBOL_VISIBLE invalid_thread_argument:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
@@ -153,7 +153,7 @@ namespace boost
|
||||
|
||||
};
|
||||
|
||||
class thread_permission_error:
|
||||
class BOOST_SYMBOL_VISIBLE thread_permission_error:
|
||||
public thread_exception
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// (C) Copyright 2008-10 Anthony Williams
|
||||
// (C) Copyright 2008-10 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
@@ -111,7 +111,7 @@ namespace boost
|
||||
do_callback(lock);
|
||||
return external_waiters.insert(external_waiters.end(),&cv);
|
||||
}
|
||||
|
||||
|
||||
void remove_external_waiter(waiter_list::iterator it)
|
||||
{
|
||||
boost::lock_guard<boost::mutex> lock(mutex);
|
||||
@@ -132,7 +132,7 @@ namespace boost
|
||||
struct relocker
|
||||
{
|
||||
boost::unique_lock<boost::mutex>& lock;
|
||||
|
||||
|
||||
relocker(boost::unique_lock<boost::mutex>& lock_):
|
||||
lock(lock_)
|
||||
{
|
||||
@@ -155,7 +155,7 @@ namespace boost
|
||||
local_callback();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void wait(bool rethrow=true)
|
||||
{
|
||||
@@ -185,7 +185,7 @@ namespace boost
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void mark_exceptional_finish_internal(boost::exception_ptr const& e)
|
||||
{
|
||||
exception=e;
|
||||
@@ -213,7 +213,7 @@ namespace boost
|
||||
{
|
||||
callback=boost::bind(f,boost::ref(*u));
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
future_object_base(future_object_base const&);
|
||||
future_object_base& operator=(future_object_base const&);
|
||||
@@ -238,7 +238,7 @@ namespace boost
|
||||
{
|
||||
storage.reset(new T(t));
|
||||
}
|
||||
|
||||
|
||||
static void init(storage_type& storage,rvalue_source_type t)
|
||||
{
|
||||
storage.reset(new T(static_cast<rvalue_source_type>(t)));
|
||||
@@ -249,7 +249,7 @@ namespace boost
|
||||
storage.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct future_traits<T&>
|
||||
{
|
||||
@@ -296,7 +296,7 @@ namespace boost
|
||||
typedef typename future_traits<T>::source_reference_type source_reference_type;
|
||||
typedef typename future_traits<T>::rvalue_source_type rvalue_source_type;
|
||||
typedef typename future_traits<T>::move_dest_type move_dest_type;
|
||||
|
||||
|
||||
storage_type result;
|
||||
|
||||
future_object():
|
||||
@@ -353,6 +353,8 @@ namespace boost
|
||||
struct future_object<void>:
|
||||
detail::future_object_base
|
||||
{
|
||||
typedef void move_dest_type;
|
||||
|
||||
future_object()
|
||||
{}
|
||||
|
||||
@@ -371,7 +373,7 @@ namespace boost
|
||||
{
|
||||
wait();
|
||||
}
|
||||
|
||||
|
||||
future_state::state get_state()
|
||||
{
|
||||
boost::lock_guard<boost::mutex> guard(mutex);
|
||||
@@ -394,7 +396,7 @@ namespace boost
|
||||
{
|
||||
struct registered_waiter;
|
||||
typedef std::vector<registered_waiter>::size_type count_type;
|
||||
|
||||
|
||||
struct registered_waiter
|
||||
{
|
||||
boost::shared_ptr<detail::future_object_base> future;
|
||||
@@ -408,44 +410,54 @@ namespace boost
|
||||
{}
|
||||
|
||||
};
|
||||
|
||||
|
||||
struct all_futures_lock
|
||||
{
|
||||
count_type count;
|
||||
#ifdef _MANAGED
|
||||
typedef std::ptrdiff_t count_type_portable;
|
||||
#else
|
||||
typedef count_type count_type_portable;
|
||||
#endif
|
||||
count_type_portable count;
|
||||
|
||||
boost::scoped_array<boost::unique_lock<boost::mutex> > locks;
|
||||
|
||||
|
||||
all_futures_lock(std::vector<registered_waiter>& futures):
|
||||
count(futures.size()),locks(new boost::unique_lock<boost::mutex>[count])
|
||||
{
|
||||
for(count_type i=0;i<count;++i)
|
||||
for(count_type_portable i=0;i<count;++i)
|
||||
{
|
||||
#if defined __DECCXX || defined __SUNPRO_CC
|
||||
locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex).move();
|
||||
#else
|
||||
locks[i]=boost::unique_lock<boost::mutex>(futures[i].future->mutex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lock()
|
||||
{
|
||||
boost::lock(locks.get(),locks.get()+count);
|
||||
}
|
||||
|
||||
|
||||
void unlock()
|
||||
{
|
||||
for(count_type i=0;i<count;++i)
|
||||
for(count_type_portable i=0;i<count;++i)
|
||||
{
|
||||
locks[i].unlock();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
boost::condition_variable_any cv;
|
||||
std::vector<registered_waiter> futures;
|
||||
count_type future_count;
|
||||
|
||||
|
||||
public:
|
||||
future_waiter():
|
||||
future_count(0)
|
||||
{}
|
||||
|
||||
|
||||
template<typename F>
|
||||
void add(F& f)
|
||||
{
|
||||
@@ -471,7 +483,7 @@ namespace boost
|
||||
cv.wait(lk);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
~future_waiter()
|
||||
{
|
||||
for(count_type i=0;i<futures.size();++i)
|
||||
@@ -479,9 +491,9 @@ namespace boost
|
||||
futures[i].future->remove_external_waiter(futures[i].wait_iterator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
template <typename R>
|
||||
@@ -495,13 +507,13 @@ namespace boost
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_future_type<unique_future<T> >
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=true);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_future_type<shared_future<T> >
|
||||
{
|
||||
@@ -531,7 +543,7 @@ namespace boost
|
||||
f2.wait();
|
||||
f3.wait();
|
||||
}
|
||||
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4>
|
||||
void wait_for_all(F1& f1,F2& f2,F3& f3,F4& f4)
|
||||
{
|
||||
@@ -556,7 +568,7 @@ namespace boost
|
||||
{
|
||||
if(begin==end)
|
||||
return end;
|
||||
|
||||
|
||||
detail::future_waiter waiter;
|
||||
for(Iterator current=begin;current!=end;++current)
|
||||
{
|
||||
@@ -583,7 +595,7 @@ namespace boost
|
||||
waiter.add(f3);
|
||||
return waiter.wait();
|
||||
}
|
||||
|
||||
|
||||
template<typename F1,typename F2,typename F3,typename F4>
|
||||
unsigned wait_for_any(F1& f1,F2& f2,F3& f3,F4& f4)
|
||||
{
|
||||
@@ -606,7 +618,7 @@ namespace boost
|
||||
waiter.add(f5);
|
||||
return waiter.wait();
|
||||
}
|
||||
|
||||
|
||||
template <typename R>
|
||||
class promise;
|
||||
|
||||
@@ -620,7 +632,7 @@ namespace boost
|
||||
unique_future& operator=(unique_future& rhs);// = delete;
|
||||
|
||||
typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
|
||||
|
||||
|
||||
future_ptr future;
|
||||
|
||||
friend class shared_future<R>;
|
||||
@@ -639,7 +651,7 @@ namespace boost
|
||||
|
||||
unique_future()
|
||||
{}
|
||||
|
||||
|
||||
~unique_future()
|
||||
{}
|
||||
|
||||
@@ -689,7 +701,7 @@ namespace boost
|
||||
|
||||
return future->get();
|
||||
}
|
||||
|
||||
|
||||
// functions to check state, and wait for ready
|
||||
state get_state() const
|
||||
{
|
||||
@@ -699,23 +711,23 @@ namespace boost
|
||||
}
|
||||
return future->get_state();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_ready() const
|
||||
{
|
||||
return get_state()==future_state::ready;
|
||||
}
|
||||
|
||||
|
||||
bool has_exception() const
|
||||
{
|
||||
return future && future->has_exception();
|
||||
}
|
||||
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return future && future->has_value();
|
||||
}
|
||||
|
||||
|
||||
void wait() const
|
||||
{
|
||||
if(!future)
|
||||
@@ -724,13 +736,13 @@ namespace boost
|
||||
}
|
||||
future->wait(false);
|
||||
}
|
||||
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration const& rel_time) const
|
||||
{
|
||||
return timed_wait_until(boost::get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
|
||||
bool timed_wait_until(boost::system_time const& abs_time) const
|
||||
{
|
||||
if(!future)
|
||||
@@ -739,14 +751,21 @@ namespace boost
|
||||
}
|
||||
return future->timed_wait_until(abs_time);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct has_move_emulation_enabled_aux<unique_future<T> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
template <typename R>
|
||||
class shared_future
|
||||
{
|
||||
typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
|
||||
|
||||
|
||||
future_ptr future;
|
||||
|
||||
// shared_future(const unique_future<R>& other);
|
||||
@@ -755,7 +774,7 @@ namespace boost
|
||||
friend class detail::future_waiter;
|
||||
friend class promise<R>;
|
||||
friend class packaged_task<R>;
|
||||
|
||||
|
||||
shared_future(future_ptr future_):
|
||||
future(future_)
|
||||
{}
|
||||
@@ -799,7 +818,7 @@ namespace boost
|
||||
other.future.reset();
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
#else
|
||||
shared_future(boost::detail::thread_move_t<shared_future> other):
|
||||
future(other->future)
|
||||
{
|
||||
@@ -837,6 +856,7 @@ namespace boost
|
||||
}
|
||||
|
||||
// retrieving the value
|
||||
//typename detail::future_object<R>::move_dest_type get()
|
||||
R get()
|
||||
{
|
||||
if(!future)
|
||||
@@ -846,7 +866,7 @@ namespace boost
|
||||
|
||||
return future->get();
|
||||
}
|
||||
|
||||
|
||||
// functions to check state, and wait for ready
|
||||
state get_state() const
|
||||
{
|
||||
@@ -856,18 +876,18 @@ namespace boost
|
||||
}
|
||||
return future->get_state();
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool is_ready() const
|
||||
{
|
||||
return get_state()==future_state::ready;
|
||||
}
|
||||
|
||||
|
||||
bool has_exception() const
|
||||
{
|
||||
return future && future->has_exception();
|
||||
}
|
||||
|
||||
|
||||
bool has_value() const
|
||||
{
|
||||
return future && future->has_value();
|
||||
@@ -881,13 +901,13 @@ namespace boost
|
||||
}
|
||||
future->wait(false);
|
||||
}
|
||||
|
||||
|
||||
template<typename Duration>
|
||||
bool timed_wait(Duration const& rel_time) const
|
||||
{
|
||||
return timed_wait_until(boost::get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
|
||||
bool timed_wait_until(boost::system_time const& abs_time) const
|
||||
{
|
||||
if(!future)
|
||||
@@ -896,17 +916,24 @@ namespace boost
|
||||
}
|
||||
return future->timed_wait_until(abs_time);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct has_move_emulation_enabled_aux<shared_future<T> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
template <typename R>
|
||||
class promise
|
||||
{
|
||||
typedef boost::shared_ptr<detail::future_object<R> > future_ptr;
|
||||
|
||||
|
||||
future_ptr future;
|
||||
bool future_obtained;
|
||||
|
||||
|
||||
promise(promise & rhs);// = delete;
|
||||
promise & operator=(promise & rhs);// = delete;
|
||||
|
||||
@@ -918,14 +945,14 @@ namespace boost
|
||||
atomic_compare_exchange(&future,&blank,future_ptr(new detail::future_object<R>));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
// template <class Allocator> explicit promise(Allocator a);
|
||||
|
||||
promise():
|
||||
future(),future_obtained(false)
|
||||
{}
|
||||
|
||||
|
||||
~promise()
|
||||
{
|
||||
if(future)
|
||||
@@ -975,8 +1002,8 @@ namespace boost
|
||||
{
|
||||
return boost::detail::thread_move_t<promise>(*this);
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
void swap(promise& other)
|
||||
{
|
||||
future.swap(other.future);
|
||||
@@ -1035,17 +1062,17 @@ namespace boost
|
||||
lazy_init();
|
||||
future->set_wait_callback(f,this);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
template <>
|
||||
class promise<void>
|
||||
{
|
||||
typedef boost::shared_ptr<detail::future_object<void> > future_ptr;
|
||||
|
||||
|
||||
future_ptr future;
|
||||
bool future_obtained;
|
||||
|
||||
|
||||
promise(promise & rhs);// = delete;
|
||||
promise & operator=(promise & rhs);// = delete;
|
||||
|
||||
@@ -1063,7 +1090,7 @@ namespace boost
|
||||
promise():
|
||||
future(),future_obtained(false)
|
||||
{}
|
||||
|
||||
|
||||
~promise()
|
||||
{
|
||||
if(future)
|
||||
@@ -1114,7 +1141,7 @@ namespace boost
|
||||
return boost::detail::thread_move_t<promise>(*this);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void swap(promise& other)
|
||||
{
|
||||
future.swap(other.future);
|
||||
@@ -1125,7 +1152,7 @@ namespace boost
|
||||
unique_future<void> get_future()
|
||||
{
|
||||
lazy_init();
|
||||
|
||||
|
||||
if(future_obtained)
|
||||
{
|
||||
boost::throw_exception(future_already_retrieved());
|
||||
@@ -1162,9 +1189,16 @@ namespace boost
|
||||
lazy_init();
|
||||
future->set_wait_callback(f,this);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct has_move_emulation_enabled_aux<promise<T> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename R>
|
||||
@@ -1199,12 +1233,12 @@ namespace boost
|
||||
this->mark_exceptional_finish_internal(boost::copy_exception(boost::broken_promise()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void do_run()=0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename R,typename F>
|
||||
struct task_object:
|
||||
task_base<R>
|
||||
@@ -1213,10 +1247,16 @@ namespace boost
|
||||
task_object(F const& f_):
|
||||
f(f_)
|
||||
{}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
task_object(F&& f_):
|
||||
f(f_)
|
||||
{}
|
||||
#else
|
||||
task_object(boost::detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
void do_run()
|
||||
{
|
||||
try
|
||||
@@ -1238,10 +1278,16 @@ namespace boost
|
||||
task_object(F const& f_):
|
||||
f(f_)
|
||||
{}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
task_object(F&& f_):
|
||||
f(f_)
|
||||
{}
|
||||
#else
|
||||
task_object(boost::detail::thread_move_t<F> f_):
|
||||
f(f_)
|
||||
{}
|
||||
|
||||
#endif
|
||||
|
||||
void do_run()
|
||||
{
|
||||
try
|
||||
@@ -1257,7 +1303,7 @@ namespace boost
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename R>
|
||||
class packaged_task
|
||||
@@ -1267,12 +1313,12 @@ namespace boost
|
||||
|
||||
packaged_task(packaged_task&);// = delete;
|
||||
packaged_task& operator=(packaged_task&);// = delete;
|
||||
|
||||
|
||||
public:
|
||||
packaged_task():
|
||||
future_obtained(false)
|
||||
{}
|
||||
|
||||
|
||||
// construction and destruction
|
||||
template <class F>
|
||||
explicit packaged_task(F const& f):
|
||||
@@ -1281,11 +1327,18 @@ namespace boost
|
||||
explicit packaged_task(R(*f)()):
|
||||
task(new detail::task_object<R,R(*)()>(f)),future_obtained(false)
|
||||
{}
|
||||
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template <class F>
|
||||
explicit packaged_task(F&& f):
|
||||
task(new detail::task_object<R,F>(f)),future_obtained(false)
|
||||
{}
|
||||
#else
|
||||
template <class F>
|
||||
explicit packaged_task(boost::detail::thread_move_t<F> f):
|
||||
task(new detail::task_object<R,F>(f)),future_obtained(false)
|
||||
{}
|
||||
#endif
|
||||
|
||||
// template <class F, class Allocator>
|
||||
// explicit packaged_task(F const& f, Allocator a);
|
||||
@@ -1334,7 +1387,7 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
void swap(packaged_task& other)
|
||||
void swap(packaged_task& other)
|
||||
{
|
||||
task.swap(other.task);
|
||||
std::swap(future_obtained,other.future_obtained);
|
||||
@@ -1357,7 +1410,7 @@ namespace boost
|
||||
boost::throw_exception(future_already_retrieved());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// execution
|
||||
void operator()()
|
||||
@@ -1374,9 +1427,16 @@ namespace boost
|
||||
{
|
||||
task->set_wait_callback(f,this);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename T>
|
||||
struct has_move_emulation_enabled_aux<packaged_task<T> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace boost
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct has_member_lock<T,true>
|
||||
{
|
||||
@@ -80,22 +80,22 @@ namespace boost
|
||||
{
|
||||
true_type dummy[2];
|
||||
};
|
||||
|
||||
|
||||
template<typename U,typename V>
|
||||
static true_type has_member(V (U::*)());
|
||||
template<typename U>
|
||||
static false_type has_member(U);
|
||||
|
||||
|
||||
BOOST_STATIC_CONSTANT(
|
||||
bool,value=sizeof(has_member_lock<T>::has_member(&T::lock))==sizeof(true_type));
|
||||
};
|
||||
|
||||
|
||||
template<typename T,bool=has_member_called_unlock<T>::value >
|
||||
struct has_member_unlock
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct has_member_unlock<T,true>
|
||||
{
|
||||
@@ -104,22 +104,22 @@ namespace boost
|
||||
{
|
||||
true_type dummy[2];
|
||||
};
|
||||
|
||||
|
||||
template<typename U,typename V>
|
||||
static true_type has_member(V (U::*)());
|
||||
template<typename U>
|
||||
static false_type has_member(U);
|
||||
|
||||
|
||||
BOOST_STATIC_CONSTANT(
|
||||
bool,value=sizeof(has_member_unlock<T>::has_member(&T::unlock))==sizeof(true_type));
|
||||
};
|
||||
|
||||
|
||||
template<typename T,bool=has_member_called_try_lock<T>::value >
|
||||
struct has_member_try_lock
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value=false);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct has_member_try_lock<T,true>
|
||||
{
|
||||
@@ -128,18 +128,18 @@ namespace boost
|
||||
{
|
||||
true_type dummy[2];
|
||||
};
|
||||
|
||||
|
||||
template<typename U>
|
||||
static true_type has_member(bool (U::*)());
|
||||
template<typename U>
|
||||
static false_type has_member(U);
|
||||
|
||||
|
||||
BOOST_STATIC_CONSTANT(
|
||||
bool,value=sizeof(has_member_try_lock<T>::has_member(&T::try_lock))==sizeof(true_type));
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_mutex_type
|
||||
@@ -147,7 +147,7 @@ namespace boost
|
||||
BOOST_STATIC_CONSTANT(bool, value = detail::has_member_lock<T>::value &&
|
||||
detail::has_member_unlock<T>::value &&
|
||||
detail::has_member_try_lock<T>::value);
|
||||
|
||||
|
||||
};
|
||||
#else
|
||||
template<typename T>
|
||||
@@ -155,7 +155,7 @@ namespace boost
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct defer_lock_t
|
||||
{};
|
||||
@@ -163,7 +163,7 @@ namespace boost
|
||||
{};
|
||||
struct adopt_lock_t
|
||||
{};
|
||||
|
||||
|
||||
const defer_lock_t defer_lock={};
|
||||
const try_to_lock_t try_to_lock={};
|
||||
const adopt_lock_t adopt_lock={};
|
||||
@@ -182,7 +182,7 @@ namespace boost
|
||||
template<typename Mutex>
|
||||
class try_lock_wrapper;
|
||||
}
|
||||
|
||||
|
||||
#ifdef BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES
|
||||
template<typename T>
|
||||
struct is_mutex_type<unique_lock<T> >
|
||||
@@ -201,7 +201,7 @@ namespace boost
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
struct is_mutex_type<detail::try_lock_wrapper<T> >
|
||||
{
|
||||
@@ -213,7 +213,7 @@ namespace boost
|
||||
class recursive_mutex;
|
||||
class recursive_timed_mutex;
|
||||
class shared_mutex;
|
||||
|
||||
|
||||
template<>
|
||||
struct is_mutex_type<mutex>
|
||||
{
|
||||
@@ -277,13 +277,13 @@ namespace boost
|
||||
unique_lock& operator=(unique_lock&);
|
||||
unique_lock& operator=(upgrade_lock<Mutex>& other);
|
||||
public:
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
unique_lock(const volatile unique_lock&);
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
unique_lock(const volatile unique_lock&);
|
||||
#endif
|
||||
unique_lock():
|
||||
m(0),is_locked(false)
|
||||
{}
|
||||
|
||||
|
||||
explicit unique_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
@@ -363,12 +363,12 @@ namespace boost
|
||||
return detail::thread_move_t<unique_lock<Mutex> >(*this);
|
||||
}
|
||||
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
unique_lock& operator=(unique_lock<Mutex> other)
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
#if BOOST_WORKAROUND(__SUNPRO_CC, < 0x5100)
|
||||
unique_lock& operator=(unique_lock<Mutex> other)
|
||||
{
|
||||
swap(other);
|
||||
return *this;
|
||||
}
|
||||
#else
|
||||
unique_lock& operator=(detail::thread_move_t<unique_lock<Mutex> > other)
|
||||
{
|
||||
@@ -395,7 +395,7 @@ namespace boost
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
|
||||
|
||||
~unique_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
@@ -427,7 +427,7 @@ namespace boost
|
||||
is_locked=m->timed_lock(relative_time);
|
||||
return is_locked;
|
||||
}
|
||||
|
||||
|
||||
bool timed_lock(::boost::system_time const& absolute_time)
|
||||
{
|
||||
is_locked=m->timed_lock(absolute_time);
|
||||
@@ -447,7 +447,7 @@ namespace boost
|
||||
m->unlock();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
|
||||
typedef void (unique_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
@@ -518,6 +518,13 @@ namespace boost
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename Mutex>
|
||||
struct has_move_emulation_enabled_aux<unique_lock<Mutex> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
template<typename Mutex>
|
||||
class shared_lock
|
||||
{
|
||||
@@ -531,7 +538,7 @@ namespace boost
|
||||
shared_lock():
|
||||
m(0),is_locked(false)
|
||||
{}
|
||||
|
||||
|
||||
explicit shared_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
@@ -553,7 +560,9 @@ namespace boost
|
||||
{
|
||||
timed_lock(target_time);
|
||||
}
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
|
||||
#else
|
||||
shared_lock(detail::thread_move_t<shared_lock<Mutex> > other):
|
||||
m(other->m),is_locked(other->is_locked)
|
||||
{
|
||||
@@ -614,6 +623,7 @@ namespace boost
|
||||
swap(temp);
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
void swap(shared_lock&& other)
|
||||
@@ -638,7 +648,7 @@ namespace boost
|
||||
{
|
||||
return m;
|
||||
}
|
||||
|
||||
|
||||
~shared_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
@@ -692,7 +702,7 @@ namespace boost
|
||||
m->unlock_shared();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
|
||||
typedef void (shared_lock<Mutex>::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
@@ -709,12 +719,25 @@ namespace boost
|
||||
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename Mutex>
|
||||
struct has_move_emulation_enabled_aux<shared_lock<Mutex> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename Mutex>
|
||||
void swap(shared_lock<Mutex>&& lhs,shared_lock<Mutex>&& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
template<typename Mutex>
|
||||
void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
#else
|
||||
template<typename Mutex>
|
||||
void swap(shared_lock<Mutex>& lhs,shared_lock<Mutex>& rhs)
|
||||
@@ -736,7 +759,7 @@ namespace boost
|
||||
upgrade_lock():
|
||||
m(0),is_locked(false)
|
||||
{}
|
||||
|
||||
|
||||
explicit upgrade_lock(Mutex& m_):
|
||||
m(&m_),is_locked(false)
|
||||
{
|
||||
@@ -753,7 +776,7 @@ namespace boost
|
||||
{
|
||||
try_lock();
|
||||
}
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
upgrade_lock(upgrade_lock<Mutex>&& other):
|
||||
m(other.m),is_locked(other.is_locked)
|
||||
{
|
||||
@@ -835,7 +858,7 @@ namespace boost
|
||||
std::swap(m,other.m);
|
||||
std::swap(is_locked,other.is_locked);
|
||||
}
|
||||
|
||||
|
||||
~upgrade_lock()
|
||||
{
|
||||
if(owns_lock())
|
||||
@@ -870,7 +893,7 @@ namespace boost
|
||||
m->unlock_upgrade();
|
||||
is_locked=false;
|
||||
}
|
||||
|
||||
|
||||
typedef void (upgrade_lock::*bool_type)();
|
||||
operator bool_type() const
|
||||
{
|
||||
@@ -888,6 +911,12 @@ namespace boost
|
||||
friend class unique_lock<Mutex>;
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename Mutex>
|
||||
struct has_move_emulation_enabled_aux<upgrade_lock<Mutex> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
template<typename Mutex>
|
||||
@@ -933,13 +962,13 @@ namespace boost
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_HAS_RVALUE_REFS
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
upgrade_to_unique_lock(upgrade_to_unique_lock<Mutex>&& other):
|
||||
source(other.source),exclusive(move(other.exclusive))
|
||||
{
|
||||
other.source=0;
|
||||
}
|
||||
|
||||
|
||||
upgrade_to_unique_lock& operator=(upgrade_to_unique_lock<Mutex>&& other)
|
||||
{
|
||||
upgrade_to_unique_lock temp(other);
|
||||
@@ -952,7 +981,7 @@ namespace boost
|
||||
{
|
||||
other->source=0;
|
||||
}
|
||||
|
||||
|
||||
upgrade_to_unique_lock& operator=(detail::thread_move_t<upgrade_to_unique_lock<Mutex> > other)
|
||||
{
|
||||
upgrade_to_unique_lock temp(other);
|
||||
@@ -980,6 +1009,13 @@ namespace boost
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
template <typename Mutex>
|
||||
struct has_move_emulation_enabled_aux<upgrade_to_unique_lock<Mutex> >
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
template<typename Mutex>
|
||||
@@ -990,7 +1026,7 @@ namespace boost
|
||||
public:
|
||||
try_lock_wrapper()
|
||||
{}
|
||||
|
||||
|
||||
explicit try_lock_wrapper(Mutex& m):
|
||||
base(m,try_to_lock)
|
||||
{}
|
||||
@@ -1098,6 +1134,11 @@ namespace boost
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
template<typename Mutex>
|
||||
void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs)
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
#else
|
||||
template<typename Mutex>
|
||||
void swap(try_lock_wrapper<Mutex>& lhs,try_lock_wrapper<Mutex>& rhs)
|
||||
@@ -1105,7 +1146,7 @@ namespace boost
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template<typename MutexType1,typename MutexType2>
|
||||
unsigned try_lock_internal(MutexType1& m1,MutexType2& m2)
|
||||
{
|
||||
@@ -1234,7 +1275,7 @@ namespace boost
|
||||
template<bool x>
|
||||
struct is_mutex_type_wrapper
|
||||
{};
|
||||
|
||||
|
||||
template<typename MutexType1,typename MutexType2>
|
||||
void lock_impl(MutexType1& m1,MutexType2& m2,is_mutex_type_wrapper<true>)
|
||||
{
|
||||
@@ -1262,7 +1303,7 @@ namespace boost
|
||||
template<typename Iterator>
|
||||
void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>);
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<typename MutexType1,typename MutexType2>
|
||||
void lock(MutexType1& m1,MutexType2& m2)
|
||||
@@ -1407,7 +1448,7 @@ namespace boost
|
||||
{
|
||||
typedef int type;
|
||||
};
|
||||
|
||||
|
||||
template<typename Iterator>
|
||||
struct try_lock_impl_return<Iterator,false>
|
||||
{
|
||||
@@ -1423,7 +1464,7 @@ namespace boost
|
||||
template<typename Iterator>
|
||||
Iterator try_lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>);
|
||||
}
|
||||
|
||||
|
||||
template<typename MutexType1,typename MutexType2>
|
||||
typename detail::try_lock_impl_return<MutexType1>::type try_lock(MutexType1& m1,MutexType2& m2)
|
||||
{
|
||||
@@ -1465,7 +1506,7 @@ namespace boost
|
||||
{
|
||||
return ((int)detail::try_lock_internal(m1,m2,m3,m4,m5))-1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -1474,13 +1515,13 @@ namespace boost
|
||||
{
|
||||
Iterator begin;
|
||||
Iterator end;
|
||||
|
||||
|
||||
range_lock_guard(Iterator begin_,Iterator end_):
|
||||
begin(begin_),end(end_)
|
||||
{
|
||||
lock(begin,end);
|
||||
boost::lock(begin,end);
|
||||
}
|
||||
|
||||
|
||||
void release()
|
||||
{
|
||||
begin=end;
|
||||
@@ -1505,21 +1546,21 @@ namespace boost
|
||||
}
|
||||
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
|
||||
unique_lock<lock_type> guard(*begin,try_to_lock);
|
||||
|
||||
|
||||
if(!guard.owns_lock())
|
||||
{
|
||||
return begin;
|
||||
}
|
||||
Iterator const failed=try_lock(++begin,end);
|
||||
Iterator const failed=boost::try_lock(++begin,end);
|
||||
if(failed==end)
|
||||
{
|
||||
guard.release();
|
||||
}
|
||||
|
||||
|
||||
return failed;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
@@ -1527,7 +1568,7 @@ namespace boost
|
||||
void lock_impl(Iterator begin,Iterator end,is_mutex_type_wrapper<false>)
|
||||
{
|
||||
typedef typename std::iterator_traits<Iterator>::value_type lock_type;
|
||||
|
||||
|
||||
if(begin==end)
|
||||
{
|
||||
return;
|
||||
@@ -1536,14 +1577,14 @@ namespace boost
|
||||
Iterator second=begin;
|
||||
++second;
|
||||
Iterator next=second;
|
||||
|
||||
|
||||
for(;;)
|
||||
{
|
||||
unique_lock<lock_type> begin_lock(*begin,defer_lock);
|
||||
if(start_with_begin)
|
||||
{
|
||||
begin_lock.lock();
|
||||
Iterator const failed_lock=try_lock(next,end);
|
||||
Iterator const failed_lock=boost::try_lock(next,end);
|
||||
if(failed_lock==end)
|
||||
{
|
||||
begin_lock.release();
|
||||
@@ -1557,7 +1598,7 @@ namespace boost
|
||||
detail::range_lock_guard<Iterator> guard(next,end);
|
||||
if(begin_lock.try_lock())
|
||||
{
|
||||
Iterator const failed_lock=try_lock(second,next);
|
||||
Iterator const failed_lock=boost::try_lock(second,next);
|
||||
if(failed_lock==next)
|
||||
{
|
||||
begin_lock.release();
|
||||
@@ -1575,9 +1616,9 @@ namespace boost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
// (C) Copyright 2007-10 Anthony Williams
|
||||
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include "thread_data.hpp"
|
||||
#include "condition_variable_fwd.hpp"
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
#include <boost/thread/pthread/thread_data.hpp>
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -18,14 +18,14 @@ namespace boost
|
||||
{
|
||||
void BOOST_THREAD_DECL interruption_point();
|
||||
}
|
||||
|
||||
|
||||
namespace thread_cv_detail
|
||||
{
|
||||
template<typename MutexType>
|
||||
struct lock_on_exit
|
||||
{
|
||||
MutexType* m;
|
||||
|
||||
|
||||
lock_on_exit():
|
||||
m(0)
|
||||
{}
|
||||
@@ -44,30 +44,44 @@ namespace boost
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
inline void condition_variable::wait(unique_lock<mutex>& m)
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
int const res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
BOOST_ASSERT(!res);
|
||||
int res=0;
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
do {
|
||||
res = pthread_cond_wait(&cond,&internal_mutex);
|
||||
} while (res == EINTR);
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error());
|
||||
}
|
||||
}
|
||||
|
||||
inline bool condition_variable::timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
int const cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
int cond_res;
|
||||
{
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
struct timespec const timeout=detail::get_timespec(wait_until);
|
||||
cond_res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(cond_res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
BOOST_ASSERT(!cond_res);
|
||||
if(cond_res)
|
||||
{
|
||||
boost::throw_exception(condition_error());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -76,13 +90,13 @@ namespace boost
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
|
||||
inline void condition_variable::notify_all()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock internal_lock(&internal_mutex);
|
||||
BOOST_VERIFY(!pthread_cond_broadcast(&cond));
|
||||
}
|
||||
|
||||
|
||||
class condition_variable_any
|
||||
{
|
||||
pthread_mutex_t internal_mutex;
|
||||
@@ -111,7 +125,7 @@ namespace boost
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
}
|
||||
|
||||
|
||||
template<typename lock_type>
|
||||
void wait(lock_type& m)
|
||||
{
|
||||
@@ -121,8 +135,8 @@ namespace boost
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
res=pthread_cond_wait(&cond,&internal_mutex);
|
||||
this_thread::interruption_point();
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(condition_error());
|
||||
@@ -134,7 +148,7 @@ namespace boost
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
@@ -145,8 +159,8 @@ namespace boost
|
||||
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
|
||||
guard.activate(m);
|
||||
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
|
||||
this_thread::interruption_point();
|
||||
}
|
||||
this_thread::interruption_point();
|
||||
if(res==ETIMEDOUT)
|
||||
{
|
||||
return false;
|
||||
@@ -197,7 +211,7 @@ namespace boost
|
||||
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);
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace boost
|
||||
private:
|
||||
pthread_mutex_t internal_mutex;
|
||||
pthread_cond_t cond;
|
||||
|
||||
|
||||
condition_variable(condition_variable&);
|
||||
condition_variable& operator=(condition_variable&);
|
||||
|
||||
@@ -44,7 +44,11 @@ namespace boost
|
||||
~condition_variable()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&internal_mutex));
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
int ret;
|
||||
do {
|
||||
ret = pthread_cond_destroy(&cond);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
}
|
||||
|
||||
void wait(unique_lock<mutex>& m);
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
#if _POSIX_TIMEOUTS >= 0 && _POSIX_C_SOURCE>=200112L
|
||||
#define BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
#endif
|
||||
#endif
|
||||
@@ -31,7 +31,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
mutex(mutex const&);
|
||||
mutex& operator=(mutex const&);
|
||||
mutex& operator=(mutex const&);
|
||||
pthread_mutex_t m;
|
||||
public:
|
||||
mutex()
|
||||
@@ -44,12 +44,20 @@ namespace boost
|
||||
}
|
||||
~mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_destroy(&m);
|
||||
} while (ret == EINTR);
|
||||
}
|
||||
|
||||
|
||||
void lock()
|
||||
{
|
||||
int const res=pthread_mutex_lock(&m);
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_lock(&m);
|
||||
} while (res == EINTR);
|
||||
if(res)
|
||||
{
|
||||
boost::throw_exception(lock_error(res));
|
||||
@@ -58,17 +66,26 @@ namespace boost
|
||||
|
||||
void unlock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
int ret;
|
||||
do
|
||||
{
|
||||
ret = pthread_mutex_unlock(&m);
|
||||
} while (ret == EINTR);
|
||||
BOOST_VERIFY(!ret);
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
int res;
|
||||
do
|
||||
{
|
||||
res = pthread_mutex_trylock(&m);
|
||||
} while (res == EINTR);
|
||||
if(res && (res!=EBUSY))
|
||||
{
|
||||
boost::throw_exception(lock_error(res));
|
||||
}
|
||||
|
||||
|
||||
return !res;
|
||||
}
|
||||
|
||||
@@ -88,7 +105,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
timed_mutex(timed_mutex const&);
|
||||
timed_mutex& operator=(timed_mutex const&);
|
||||
timed_mutex& operator=(timed_mutex const&);
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_TIMEDLOCK
|
||||
@@ -141,7 +158,7 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
@@ -179,7 +196,7 @@ namespace boost
|
||||
is_locked=false;
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// once.hpp
|
||||
//
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
// (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
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#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>
|
||||
|
||||
@@ -35,7 +34,7 @@ namespace boost
|
||||
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}
|
||||
|
||||
@@ -49,7 +48,7 @@ namespace boost
|
||||
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);
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
#endif
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <errno.h>
|
||||
#include "timespec.hpp"
|
||||
#include "pthread_mutex_scoped_lock.hpp"
|
||||
#include <boost/thread/pthread/timespec.hpp>
|
||||
#include <boost/thread/pthread/pthread_mutex_scoped_lock.hpp>
|
||||
|
||||
#ifdef _POSIX_TIMEOUTS
|
||||
#if _POSIX_TIMEOUTS >= 0
|
||||
@@ -26,7 +26,7 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK)
|
||||
#if defined(BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE) && defined(BOOST_PTHREAD_HAS_TIMEDLOCK)
|
||||
#define BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
#endif
|
||||
|
||||
@@ -38,9 +38,9 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
recursive_mutex(recursive_mutex const&);
|
||||
recursive_mutex& operator=(recursive_mutex const&);
|
||||
recursive_mutex& operator=(recursive_mutex const&);
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE
|
||||
#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
pthread_cond_t cond;
|
||||
bool is_locked;
|
||||
pthread_t owner;
|
||||
@@ -49,9 +49,9 @@ namespace boost
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
#ifdef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE
|
||||
#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
@@ -63,7 +63,7 @@ namespace boost
|
||||
BOOST_VERIFY(!pthread_mutexattr_destroy(&attr));
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
@@ -90,12 +90,12 @@ namespace boost
|
||||
~recursive_mutex()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_destroy(&m));
|
||||
#ifndef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE
|
||||
#ifndef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
BOOST_VERIFY(!pthread_cond_destroy(&cond));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_PTHREAD_HAS_MUTEXATTR_SETTYPE
|
||||
#ifdef BOOST_HAS_PTHREAD_MUTEXATTR_SETTYPE
|
||||
void lock()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_lock(&m));
|
||||
@@ -105,7 +105,7 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
@@ -127,7 +127,7 @@ namespace boost
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
@@ -146,7 +146,7 @@ namespace boost
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
@@ -172,7 +172,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
recursive_timed_mutex(recursive_timed_mutex const&);
|
||||
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
|
||||
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
|
||||
private:
|
||||
pthread_mutex_t m;
|
||||
#ifndef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
@@ -186,7 +186,7 @@ namespace boost
|
||||
{
|
||||
#ifdef BOOST_USE_PTHREAD_RECURSIVE_TIMEDLOCK
|
||||
pthread_mutexattr_t attr;
|
||||
|
||||
|
||||
int const init_attr_res=pthread_mutexattr_init(&attr);
|
||||
if(init_attr_res)
|
||||
{
|
||||
@@ -197,7 +197,7 @@ namespace boost
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
|
||||
|
||||
int const res=pthread_mutex_init(&m,&attr);
|
||||
if(res)
|
||||
{
|
||||
@@ -245,7 +245,7 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(!pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
int const res=pthread_mutex_trylock(&m);
|
||||
@@ -275,7 +275,7 @@ namespace boost
|
||||
++count;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
while(is_locked)
|
||||
{
|
||||
BOOST_VERIFY(!pthread_cond_wait(&cond,&m));
|
||||
@@ -294,7 +294,7 @@ namespace boost
|
||||
}
|
||||
BOOST_VERIFY(!pthread_cond_signal(&cond));
|
||||
}
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
boost::pthread::pthread_mutex_scoped_lock const local_lock(&m);
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace boost
|
||||
bool upgrade;
|
||||
bool exclusive_waiting_blocked;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
state_data state;
|
||||
@@ -41,7 +41,7 @@ namespace boost
|
||||
exclusive_cond.notify_one();
|
||||
shared_cond.notify_all();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex()
|
||||
@@ -58,7 +58,7 @@ namespace boost
|
||||
{
|
||||
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);
|
||||
@@ -69,7 +69,7 @@ namespace boost
|
||||
bool try_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
|
||||
if(state.exclusive || state.exclusive_waiting_blocked)
|
||||
{
|
||||
return false;
|
||||
@@ -85,7 +85,7 @@ namespace boost
|
||||
{
|
||||
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))
|
||||
@@ -107,7 +107,7 @@ namespace boost
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
bool const last_reader=!--state.shared_count;
|
||||
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(state.upgrade)
|
||||
@@ -128,7 +128,7 @@ namespace boost
|
||||
{
|
||||
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;
|
||||
@@ -150,7 +150,7 @@ namespace boost
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
state.exclusive_waiting_blocked=false;
|
||||
exclusive_cond.notify_one();
|
||||
release_waiters();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
@@ -169,7 +169,7 @@ namespace boost
|
||||
bool try_lock()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
|
||||
if(state.shared_count || state.exclusive)
|
||||
{
|
||||
return false;
|
||||
@@ -179,7 +179,7 @@ namespace boost
|
||||
state.exclusive=true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void unlock()
|
||||
@@ -248,7 +248,7 @@ namespace boost
|
||||
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;
|
||||
@@ -278,7 +278,7 @@ namespace boost
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
@@ -287,7 +287,7 @@ namespace boost
|
||||
state.exclusive_waiting_blocked=false;
|
||||
release_waiters();
|
||||
}
|
||||
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
boost::mutex::scoped_lock lk(state_change);
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <boost/optional.hpp>
|
||||
#include <pthread.h>
|
||||
#include <boost/assert.hpp>
|
||||
#include "condition_variable_fwd.hpp"
|
||||
#include <boost/thread/pthread/condition_variable_fwd.hpp>
|
||||
#include <map>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
@@ -21,7 +21,7 @@
|
||||
namespace boost
|
||||
{
|
||||
class thread;
|
||||
|
||||
|
||||
namespace detail
|
||||
{
|
||||
struct tss_cleanup_function;
|
||||
@@ -39,7 +39,7 @@ namespace boost
|
||||
|
||||
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>
|
||||
{
|
||||
@@ -89,7 +89,7 @@ namespace boost
|
||||
throw thread_interrupted();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void operator=(interruption_checker&);
|
||||
public:
|
||||
explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
|
||||
@@ -129,14 +129,26 @@ namespace boost
|
||||
namespace this_thread
|
||||
{
|
||||
void BOOST_THREAD_DECL yield();
|
||||
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
|
||||
|
||||
#ifdef __DECXXX
|
||||
/// Workaround of DECCXX issue of incorrect template substitution
|
||||
template<typename TimeDuration>
|
||||
inline void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
|
||||
template<>
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
#else
|
||||
void BOOST_THREAD_DECL sleep(system_time const& abs_time);
|
||||
|
||||
template<typename TimeDuration>
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
this_thread::sleep(get_system_time()+rel_time);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,14 +3,14 @@
|
||||
|
||||
// basic_recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// (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/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/basic_timed_mutex.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace boost
|
||||
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();
|
||||
@@ -83,7 +83,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool try_basic_lock(long current_thread_id)
|
||||
{
|
||||
if(mutex.try_lock())
|
||||
@@ -94,7 +94,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool try_timed_lock(long current_thread_id,::boost::system_time const& target)
|
||||
{
|
||||
if(mutex.timed_lock(target))
|
||||
@@ -105,7 +105,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
typedef basic_recursive_mutex_impl<basic_timed_mutex> basic_recursive_mutex;
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
// basic_timed_mutex_win32.hpp
|
||||
//
|
||||
// (C) Copyright 2006-8 Anthony Williams
|
||||
// (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/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/interlocked_read.hpp>
|
||||
#include <boost/thread/thread_time.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <boost/detail/interlocked.hpp>
|
||||
@@ -52,13 +52,13 @@ namespace boost
|
||||
win32::CloseHandle(old_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool try_lock()
|
||||
{
|
||||
return !win32::interlocked_bit_test_and_set(&active_count,lock_flag_bit);
|
||||
}
|
||||
|
||||
|
||||
void lock()
|
||||
{
|
||||
if(try_lock())
|
||||
@@ -112,8 +112,8 @@ namespace boost
|
||||
old_count=current;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool timed_lock(::boost::system_time const& wait_until)
|
||||
{
|
||||
if(try_lock())
|
||||
@@ -171,7 +171,7 @@ namespace boost
|
||||
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);
|
||||
@@ -196,9 +196,9 @@ namespace boost
|
||||
}
|
||||
return current_event;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
// (C) Copyright 2007-8 Anthony Williams
|
||||
|
||||
#include <boost/thread/mutex.hpp>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <boost/thread/win32/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/win32/interlocked_read.hpp>
|
||||
#include <boost/thread/xtime.hpp>
|
||||
#include <vector>
|
||||
#include <boost/intrusive_ptr.hpp>
|
||||
@@ -26,7 +26,7 @@ namespace boost
|
||||
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:
|
||||
@@ -38,7 +38,7 @@ namespace boost
|
||||
|
||||
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)),
|
||||
@@ -55,7 +55,7 @@ namespace boost
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&waiters);
|
||||
}
|
||||
|
||||
|
||||
void remove_waiter()
|
||||
{
|
||||
BOOST_INTERLOCKED_DECREMENT(&waiters);
|
||||
@@ -97,7 +97,7 @@ namespace boost
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->references);
|
||||
}
|
||||
|
||||
|
||||
inline void intrusive_ptr_release(basic_cv_list_entry * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->references))
|
||||
@@ -125,13 +125,13 @@ namespace boost
|
||||
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)
|
||||
{}
|
||||
@@ -146,13 +146,13 @@ namespace boost
|
||||
{
|
||||
lock.lock();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private:
|
||||
relocker(relocker&);
|
||||
void operator=(relocker&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
entry_ptr get_wait_entry()
|
||||
{
|
||||
@@ -177,15 +177,15 @@ namespace boost
|
||||
return generations.back();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
struct entry_manager
|
||||
{
|
||||
entry_ptr const entry;
|
||||
|
||||
|
||||
entry_manager(entry_ptr const& entry_):
|
||||
entry(entry_)
|
||||
{}
|
||||
|
||||
|
||||
~entry_manager()
|
||||
{
|
||||
entry->remove_waiter();
|
||||
@@ -200,14 +200,14 @@ namespace boost
|
||||
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();
|
||||
@@ -219,7 +219,7 @@ namespace boost
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
woken=entry->woken();
|
||||
}
|
||||
return woken;
|
||||
@@ -235,7 +235,7 @@ namespace boost
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
basic_condition_variable(const basic_condition_variable& other);
|
||||
basic_condition_variable& operator=(const basic_condition_variable& other);
|
||||
|
||||
@@ -243,7 +243,7 @@ namespace boost
|
||||
basic_condition_variable():
|
||||
total_count(0),active_generation_count(0),wake_sem(0)
|
||||
{}
|
||||
|
||||
|
||||
~basic_condition_variable()
|
||||
{}
|
||||
|
||||
@@ -267,7 +267,7 @@ namespace boost
|
||||
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))
|
||||
@@ -288,7 +288,7 @@ namespace boost
|
||||
wake_sem=detail::win32::handle(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
@@ -301,10 +301,10 @@ namespace boost
|
||||
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());
|
||||
@@ -315,7 +315,7 @@ namespace boost
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool timed_wait(unique_lock<mutex>& m,boost::system_time const& wait_until)
|
||||
{
|
||||
@@ -348,7 +348,7 @@ namespace boost
|
||||
return do_wait(m,wait_duration.total_milliseconds(),pred);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class condition_variable_any:
|
||||
private detail::basic_condition_variable
|
||||
{
|
||||
@@ -358,10 +358,10 @@ namespace boost
|
||||
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)
|
||||
{
|
||||
@@ -373,7 +373,7 @@ namespace boost
|
||||
{
|
||||
while(!pred()) wait(m);
|
||||
}
|
||||
|
||||
|
||||
template<typename lock_type>
|
||||
bool timed_wait(lock_type& m,boost::system_time const& wait_until)
|
||||
{
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
// accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "basic_timed_mutex.hpp"
|
||||
#include <boost/thread/win32/basic_timed_mutex.hpp>
|
||||
#include <boost/utility.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
// recursive_mutex.hpp
|
||||
//
|
||||
// (C) Copyright 2006-7 Anthony Williams
|
||||
// (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
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
|
||||
#include <boost/utility.hpp>
|
||||
#include "basic_recursive_mutex.hpp"
|
||||
#include <boost/thread/win32/basic_recursive_mutex.hpp>
|
||||
#include <boost/thread/exceptions.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
recursive_mutex(recursive_mutex const&);
|
||||
recursive_mutex& operator=(recursive_mutex const&);
|
||||
recursive_mutex& operator=(recursive_mutex const&);
|
||||
public:
|
||||
recursive_mutex()
|
||||
{
|
||||
@@ -46,7 +46,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
recursive_timed_mutex(recursive_timed_mutex const&);
|
||||
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
|
||||
recursive_timed_mutex& operator=(recursive_timed_mutex const&);
|
||||
public:
|
||||
recursive_timed_mutex()
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace boost
|
||||
{
|
||||
private:
|
||||
shared_mutex(shared_mutex const&);
|
||||
shared_mutex& operator=(shared_mutex const&);
|
||||
shared_mutex& operator=(shared_mutex const&);
|
||||
private:
|
||||
struct state_data
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace boost
|
||||
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)
|
||||
@@ -67,20 +67,31 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[exclusive_sem],1,0)!=0);
|
||||
}
|
||||
|
||||
|
||||
if(old_state.shared_waiting || old_state.exclusive_waiting)
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::ReleaseSemaphore(semaphores[unlock_sem],old_state.shared_waiting + (old_state.exclusive_waiting?1:0),0)!=0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public:
|
||||
shared_mutex()
|
||||
{
|
||||
semaphores[unlock_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
upgrade_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
|
||||
semaphores[exclusive_sem]=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
|
||||
if (!semaphores[exclusive_sem])
|
||||
{
|
||||
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
upgrade_sem=detail::win32::create_anonymous_semaphore_nothrow(0,LONG_MAX);
|
||||
if (!upgrade_sem)
|
||||
{
|
||||
detail::win32::release_semaphore(semaphores[unlock_sem],LONG_MAX);
|
||||
detail::win32::release_semaphore(semaphores[exclusive_sem],LONG_MAX);
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
state_data state_={0};
|
||||
state=state_;
|
||||
}
|
||||
@@ -106,7 +117,7 @@ namespace boost
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
@@ -165,7 +176,7 @@ namespace boost
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
unsigned long const res=detail::win32::WaitForSingleObject(semaphores[unlock_sem],::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(res==detail::win32::timeout)
|
||||
{
|
||||
@@ -202,7 +213,7 @@ namespace boost
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
BOOST_ASSERT(res==0);
|
||||
}
|
||||
}
|
||||
@@ -214,7 +225,7 @@ namespace boost
|
||||
{
|
||||
state_data new_state=old_state;
|
||||
bool const last_reader=!--new_state.shared_count;
|
||||
|
||||
|
||||
if(last_reader)
|
||||
{
|
||||
if(new_state.upgrade)
|
||||
@@ -232,7 +243,7 @@ namespace boost
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
@@ -278,7 +289,7 @@ namespace boost
|
||||
{
|
||||
new_state.exclusive=true;
|
||||
}
|
||||
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
@@ -306,7 +317,7 @@ namespace boost
|
||||
{
|
||||
boost::throw_exception(boost::lock_error());
|
||||
}
|
||||
|
||||
|
||||
new_state.exclusive_waiting_blocked=true;
|
||||
}
|
||||
else
|
||||
@@ -326,7 +337,12 @@ namespace boost
|
||||
{
|
||||
return true;
|
||||
}
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,true,::boost::detail::get_milliseconds_until(wait_until));
|
||||
#ifndef UNDER_CE
|
||||
const bool wait_all = true;
|
||||
#else
|
||||
const bool wait_all = false;
|
||||
#endif
|
||||
unsigned long const wait_res=detail::win32::WaitForMultipleObjects(2,semaphores,wait_all,::boost::detail::get_milliseconds_until(wait_until));
|
||||
if(wait_res==detail::win32::timeout)
|
||||
{
|
||||
for(;;)
|
||||
@@ -426,7 +442,7 @@ namespace boost
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
BOOST_VERIFY(!detail::win32::WaitForSingleObject(semaphores[unlock_sem],detail::win32::infinite));
|
||||
}
|
||||
}
|
||||
@@ -450,7 +466,7 @@ namespace boost
|
||||
}
|
||||
new_state.upgrade=true;
|
||||
}
|
||||
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
@@ -469,7 +485,7 @@ namespace boost
|
||||
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)
|
||||
@@ -479,7 +495,7 @@ namespace boost
|
||||
}
|
||||
new_state.shared_waiting=0;
|
||||
}
|
||||
|
||||
|
||||
state_data const current_state=interlocked_compare_exchange(&state,new_state,old_state);
|
||||
if(current_state==old_state)
|
||||
{
|
||||
@@ -500,13 +516,13 @@ namespace boost
|
||||
{
|
||||
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)
|
||||
{
|
||||
@@ -545,7 +561,7 @@ namespace boost
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
|
||||
void unlock_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
@@ -570,7 +586,7 @@ namespace boost
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
|
||||
void unlock_upgrade_and_lock_shared()
|
||||
{
|
||||
state_data old_state=state;
|
||||
@@ -594,7 +610,7 @@ namespace boost
|
||||
}
|
||||
release_waiters(old_state);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#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/thread/win32/thread_primitives.hpp>
|
||||
#include <boost/thread/win32/thread_heap_alloc.hpp>
|
||||
|
||||
#include <boost/config/abi_prefix.hpp>
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace boost
|
||||
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
|
||||
|
||||
struct BOOST_SYMBOL_VISIBLE thread_data_base
|
||||
{
|
||||
long count;
|
||||
detail::win32::handle_manager thread_handle;
|
||||
@@ -48,7 +48,7 @@ namespace boost
|
||||
{
|
||||
BOOST_INTERLOCKED_INCREMENT(&p->count);
|
||||
}
|
||||
|
||||
|
||||
friend void intrusive_ptr_release(thread_data_base * p)
|
||||
{
|
||||
if(!BOOST_INTERLOCKED_DECREMENT(&p->count))
|
||||
@@ -61,7 +61,7 @@ namespace boost
|
||||
{
|
||||
BOOST_VERIFY(detail::win32::SetEvent(interruption_handle)!=0);
|
||||
}
|
||||
|
||||
|
||||
typedef detail::win32::handle native_handle_type;
|
||||
|
||||
virtual void run()=0;
|
||||
@@ -69,7 +69,7 @@ namespace boost
|
||||
|
||||
typedef boost::intrusive_ptr<detail::thread_data_base> thread_data_ptr;
|
||||
|
||||
struct timeout
|
||||
struct BOOST_SYMBOL_VISIBLE timeout
|
||||
{
|
||||
unsigned long start;
|
||||
uintmax_t milliseconds;
|
||||
@@ -92,7 +92,7 @@ namespace boost
|
||||
abs_time(abs_time_)
|
||||
{}
|
||||
|
||||
struct remaining_time
|
||||
struct BOOST_SYMBOL_VISIBLE remaining_time
|
||||
{
|
||||
bool more;
|
||||
unsigned long milliseconds;
|
||||
@@ -130,7 +130,7 @@ namespace boost
|
||||
{
|
||||
return milliseconds==~uintmax_t(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static timeout sentinel()
|
||||
{
|
||||
@@ -139,15 +139,15 @@ namespace boost
|
||||
private:
|
||||
struct sentinel_type
|
||||
{};
|
||||
|
||||
|
||||
explicit timeout(sentinel_type):
|
||||
start(0),milliseconds(~uintmax_t(0)),relative(true)
|
||||
{}
|
||||
};
|
||||
|
||||
inline unsigned long pin_to_zero(long value)
|
||||
inline uintmax_t pin_to_zero(intmax_t value)
|
||||
{
|
||||
return (value<0)?0u:(unsigned long)value;
|
||||
return (value<0)?0u:(uintmax_t)value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,26 +156,26 @@ namespace boost
|
||||
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)
|
||||
inline void interruptible_wait(uintmax_t milliseconds)
|
||||
{
|
||||
interruptible_wait(detail::win32::invalid_handle_value,milliseconds);
|
||||
}
|
||||
inline void interruptible_wait(system_time const& abs_time)
|
||||
inline BOOST_SYMBOL_VISIBLE 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)
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(TimeDuration const& rel_time)
|
||||
{
|
||||
interruptible_wait(detail::pin_to_zero(rel_time.total_milliseconds()));
|
||||
}
|
||||
inline void sleep(system_time const& abs_time)
|
||||
inline BOOST_SYMBOL_VISIBLE void sleep(system_time const& abs_time)
|
||||
{
|
||||
interruptible_wait(abs_time);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#include <boost/config/abi_suffix.hpp>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#ifndef THREAD_HEAP_ALLOC_HPP
|
||||
#define THREAD_HEAP_ALLOC_HPP
|
||||
#include <new>
|
||||
#include "thread_primitives.hpp"
|
||||
#include <boost/thread/win32/thread_primitives.hpp>
|
||||
#include <stdexcept>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
@@ -56,7 +56,7 @@ namespace boost
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
inline /*BOOST_THREAD_DECL*/ void* allocate_raw_heap_memory(unsigned size)
|
||||
inline void* allocate_raw_heap_memory(unsigned size)
|
||||
{
|
||||
void* const heap_memory=detail::win32::HeapAlloc(detail::win32::GetProcessHeap(),0,size);
|
||||
if(!heap_memory)
|
||||
@@ -66,11 +66,11 @@ namespace boost
|
||||
return heap_memory;
|
||||
}
|
||||
|
||||
inline /*BOOST_THREAD_DECL*/ void free_raw_heap_memory(void* heap_memory)
|
||||
inline 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()
|
||||
{
|
||||
@@ -226,7 +226,7 @@ namespace boost
|
||||
{
|
||||
return heap_new_impl<T,A1&>(a1);
|
||||
}
|
||||
|
||||
|
||||
template<typename T,typename A1,typename A2>
|
||||
inline T* heap_new(A1 const& a1,A2 const& a2)
|
||||
{
|
||||
@@ -372,8 +372,8 @@ namespace boost
|
||||
{
|
||||
return heap_new_impl<T,A1&,A2&,A3&,A4&>(a1,a2,a3,a4);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
template<typename T>
|
||||
inline void heap_delete(T* data)
|
||||
{
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
// win32_thread_primitives.hpp
|
||||
//
|
||||
// (C) Copyright 2005-7 Anthony Williams
|
||||
// (C) Copyright 2007 David Deakins
|
||||
// (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
|
||||
@@ -94,7 +94,7 @@ namespace boost
|
||||
{
|
||||
namespace win32
|
||||
{
|
||||
|
||||
|
||||
# ifdef _WIN64
|
||||
typedef unsigned __int64 ulong_ptr;
|
||||
# else
|
||||
@@ -170,20 +170,20 @@ namespace boost
|
||||
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)
|
||||
#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
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
@@ -193,17 +193,26 @@ namespace boost
|
||||
|
||||
inline handle create_anonymous_semaphore(long initial_count,long max_count)
|
||||
{
|
||||
#if !defined(BOOST_NO_ANSI_APIS)
|
||||
#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
|
||||
#endif
|
||||
if(!res)
|
||||
{
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
inline handle create_anonymous_semaphore_nothrow(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
|
||||
return res;
|
||||
}
|
||||
|
||||
inline handle duplicate_handle(handle source)
|
||||
{
|
||||
@@ -237,7 +246,7 @@ namespace boost
|
||||
BOOST_VERIFY(CloseHandle(handle_to_manage));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
explicit handle_manager(handle handle_to_manage_):
|
||||
handle_to_manage(handle_to_manage_)
|
||||
@@ -245,7 +254,7 @@ namespace boost
|
||||
handle_manager():
|
||||
handle_to_manage(0)
|
||||
{}
|
||||
|
||||
|
||||
handle_manager& operator=(handle new_handle)
|
||||
{
|
||||
cleanup();
|
||||
@@ -279,13 +288,13 @@ namespace boost
|
||||
{
|
||||
return !handle_to_manage;
|
||||
}
|
||||
|
||||
|
||||
~handle_manager()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -318,7 +327,7 @@ namespace boost
|
||||
{
|
||||
return _interlockedbittestandreset(x,bit)!=0;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -337,7 +346,7 @@ namespace boost
|
||||
mov edx,x;
|
||||
lock bts [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
inline bool interlocked_bit_test_and_reset(long* x,long bit)
|
||||
@@ -347,9 +356,9 @@ namespace boost
|
||||
mov edx,x;
|
||||
lock btr [edx],eax;
|
||||
setc al;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
16
src/pthread/once.cpp
Executable file → Normal file
16
src/pthread/once.cpp
Executable file → Normal file
@@ -22,16 +22,18 @@ namespace boost
|
||||
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)
|
||||
extern "C"
|
||||
{
|
||||
free(data);
|
||||
}
|
||||
static 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));
|
||||
static 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()
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// William E. Kempf
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/thread/detail/config.hpp>
|
||||
@@ -14,7 +14,7 @@
|
||||
#include <boost/thread/once.hpp>
|
||||
#include <boost/thread/tss.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#ifdef __linux__
|
||||
#ifdef __GLIBC__
|
||||
#include <sys/sysinfo.h>
|
||||
#elif defined(__APPLE__) || defined(__FreeBSD__)
|
||||
#include <sys/types.h>
|
||||
@@ -50,7 +50,7 @@ namespace boost
|
||||
|
||||
extern "C"
|
||||
{
|
||||
void tls_destructor(void* data)
|
||||
static void tls_destructor(void* data)
|
||||
{
|
||||
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
|
||||
if(thread_info)
|
||||
@@ -86,14 +86,14 @@ namespace boost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void create_current_thread_tls_key()
|
||||
{
|
||||
BOOST_VERIFY(!pthread_key_create(¤t_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);
|
||||
@@ -106,12 +106,12 @@ namespace boost
|
||||
BOOST_VERIFY(!pthread_setspecific(current_thread_tls_key,new_data));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
extern "C"
|
||||
{
|
||||
void* thread_proxy(void* param)
|
||||
static 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();
|
||||
@@ -146,7 +146,7 @@ namespace boost
|
||||
{
|
||||
interrupt_enabled=false;
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{}
|
||||
|
||||
@@ -207,7 +207,7 @@ namespace boost
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
@@ -215,7 +215,7 @@ namespace boost
|
||||
local_thread_info->done_condition.wait(lock);
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
@@ -236,7 +236,7 @@ namespace boost
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
@@ -250,7 +250,7 @@ namespace boost
|
||||
if(local_thread_info)
|
||||
{
|
||||
bool do_join=false;
|
||||
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(local_thread_info->data_mutex);
|
||||
while(!local_thread_info->done)
|
||||
@@ -261,7 +261,7 @@ namespace boost
|
||||
}
|
||||
}
|
||||
do_join=!local_thread_info->join_started;
|
||||
|
||||
|
||||
if(do_join)
|
||||
{
|
||||
local_thread_info->join_started=true;
|
||||
@@ -282,7 +282,7 @@ namespace boost
|
||||
local_thread_info->joined=true;
|
||||
local_thread_info->done_condition.notify_all();
|
||||
}
|
||||
|
||||
|
||||
if(thread_info==local_thread_info)
|
||||
{
|
||||
thread_info.reset();
|
||||
@@ -301,7 +301,7 @@ namespace boost
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info;
|
||||
thread_info.swap(local_thread_info);
|
||||
|
||||
|
||||
if(local_thread_info)
|
||||
{
|
||||
lock_guard<mutex> lock(local_thread_info->data_mutex);
|
||||
@@ -316,11 +316,15 @@ namespace boost
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
|
||||
|
||||
#ifdef __DECXXX
|
||||
/// Workaround of DECCXX issue of incorrect template substitution
|
||||
template<>
|
||||
#endif
|
||||
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);
|
||||
@@ -329,7 +333,7 @@ namespace boost
|
||||
else
|
||||
{
|
||||
xtime const xt=get_xtime(st);
|
||||
|
||||
|
||||
for (int foo=0; foo < 5; ++foo)
|
||||
{
|
||||
# if defined(BOOST_HAS_PTHREAD_DELAY_NP)
|
||||
@@ -339,7 +343,7 @@ namespace boost
|
||||
# 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);
|
||||
@@ -382,7 +386,7 @@ namespace boost
|
||||
#elif defined(BOOST_HAS_UNISTD_H) && defined(_SC_NPROCESSORS_ONLN)
|
||||
int const count=sysconf(_SC_NPROCESSORS_ONLN);
|
||||
return (count>0)?count:0;
|
||||
#elif defined(_GNU_SOURCE)
|
||||
#elif defined(__GLIBC__)
|
||||
return get_nprocs();
|
||||
#else
|
||||
return 0;
|
||||
@@ -444,8 +448,8 @@ namespace boost
|
||||
return pthread_t();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace this_thread
|
||||
{
|
||||
@@ -468,13 +472,13 @@ namespace boost
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
@@ -497,7 +501,7 @@ namespace boost
|
||||
detail::get_current_thread_data()->interrupt_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
@@ -513,7 +517,7 @@ namespace boost
|
||||
detail::get_current_thread_data()->interrupt_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(detail::get_current_thread_data())
|
||||
@@ -570,7 +574,7 @@ namespace boost
|
||||
detail::thread_data_base* const current_thread_data(get_or_make_current_thread_data());
|
||||
current_thread_data->tss_data.erase(key);
|
||||
}
|
||||
|
||||
|
||||
void set_tss_data(void const* key,
|
||||
boost::shared_ptr<tss_cleanup_function> func,
|
||||
void* tss_data,bool cleanup_existing)
|
||||
|
||||
@@ -21,7 +21,7 @@ inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
{
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&xt, boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
|
||||
xt.sec += (milliseconds / MILLISECONDS_PER_SECOND);
|
||||
xt.nsec += ((milliseconds % MILLISECONDS_PER_SECOND) *
|
||||
@@ -33,7 +33,6 @@ inline void to_time(int milliseconds, boost::xtime& xt)
|
||||
xt.nsec -= NANOSECONDS_PER_SECOND;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_HAS_PTHREADS)
|
||||
inline void to_timespec(const boost::xtime& xt, timespec& ts)
|
||||
{
|
||||
@@ -58,7 +57,7 @@ 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);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
{
|
||||
@@ -89,7 +88,7 @@ inline void to_duration(boost::xtime xt, int& milliseconds)
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
milliseconds = 0;
|
||||
@@ -111,7 +110,7 @@ inline void to_microduration(boost::xtime xt, int& microseconds)
|
||||
boost::xtime cur;
|
||||
int res = 0;
|
||||
res = boost::xtime_get(&cur, boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC);
|
||||
BOOST_ASSERT(res == boost::TIME_UTC); (void)res;
|
||||
|
||||
if (boost::xtime_cmp(xt, cur) <= 0)
|
||||
microseconds = 0;
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <algorithm>
|
||||
#include <windows.h>
|
||||
#ifndef UNDER_CE
|
||||
#include <process.h>
|
||||
#endif
|
||||
@@ -20,6 +19,8 @@
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
#include <boost/date_time/posix_time/conversion.hpp>
|
||||
#include <windows.h>
|
||||
#include <memory>
|
||||
|
||||
namespace boost
|
||||
{
|
||||
@@ -32,7 +33,12 @@ namespace boost
|
||||
{
|
||||
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);
|
||||
#if defined(UNDER_CE)
|
||||
// Windows CE does not define the TLS_OUT_OF_INDEXES constant.
|
||||
BOOST_ASSERT(current_thread_tls_key!=0xFFFFFFFF);
|
||||
#else
|
||||
BOOST_ASSERT(current_thread_tls_key!=TLS_OUT_OF_INDEXES);
|
||||
#endif
|
||||
}
|
||||
|
||||
void cleanup_tls_key()
|
||||
@@ -62,7 +68,7 @@ namespace boost
|
||||
boost::throw_exception(thread_resource_error());
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_THREADEX
|
||||
#ifndef BOOST_HAS_THREADEX
|
||||
// Windows CE doesn't define _beginthreadex
|
||||
|
||||
struct ThreadProxyData
|
||||
@@ -75,22 +81,25 @@ namespace boost
|
||||
|
||||
DWORD WINAPI ThreadProxy(LPVOID args)
|
||||
{
|
||||
ThreadProxyData* data=reinterpret_cast<ThreadProxyData*>(args);
|
||||
std::auto_ptr<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;
|
||||
ThreadProxyData* data = new ThreadProxyData(start_address,arglist);
|
||||
HANDLE hthread=CreateThread(static_cast<LPSECURITY_ATTRIBUTES>(security),stack_size,ThreadProxy,
|
||||
new ThreadProxyData(start_address,arglist),initflag,&threadID);
|
||||
if (hthread!=0)
|
||||
*thrdaddr=threadID;
|
||||
data,initflag,&threadID);
|
||||
if (hthread==0) {
|
||||
delete data;
|
||||
return 0;
|
||||
}
|
||||
*thrdaddr=threadID;
|
||||
return reinterpret_cast<uintptr_t const>(hthread);
|
||||
}
|
||||
|
||||
@@ -157,11 +166,11 @@ namespace boost
|
||||
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));
|
||||
@@ -213,7 +222,7 @@ namespace boost
|
||||
++count;
|
||||
interruption_enabled=false;
|
||||
}
|
||||
|
||||
|
||||
void run()
|
||||
{}
|
||||
private:
|
||||
@@ -245,14 +254,14 @@ namespace boost
|
||||
}
|
||||
return current_thread_data;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
thread::~thread()
|
||||
{
|
||||
detach();
|
||||
}
|
||||
|
||||
|
||||
thread::id thread::get_id() const
|
||||
{
|
||||
return thread::id((get_thread_info)());
|
||||
@@ -286,7 +295,7 @@ namespace boost
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void thread::detach()
|
||||
{
|
||||
release_handle();
|
||||
@@ -296,7 +305,7 @@ namespace boost
|
||||
{
|
||||
thread_info=0;
|
||||
}
|
||||
|
||||
|
||||
void thread::interrupt()
|
||||
{
|
||||
detail::thread_data_ptr local_thread_info=(get_thread_info)();
|
||||
@@ -305,20 +314,20 @@ namespace boost
|
||||
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)();
|
||||
@@ -369,7 +378,7 @@ namespace boost
|
||||
target_time.abs_time.time_of_day().ticks_per_second();
|
||||
if(ticks_per_second>hundred_nanoseconds_in_one_second)
|
||||
{
|
||||
posix_time::time_duration::tick_type const
|
||||
posix_time::time_duration::tick_type const
|
||||
ticks_per_hundred_nanoseconds=
|
||||
ticks_per_second/hundred_nanoseconds_in_one_second;
|
||||
due_time.QuadPart+=
|
||||
@@ -387,7 +396,7 @@ namespace boost
|
||||
return due_time;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool interruptible_wait(detail::win32::handle handle_to_wait_for,detail::timeout target_time)
|
||||
{
|
||||
@@ -408,10 +417,10 @@ namespace boost
|
||||
}
|
||||
|
||||
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();
|
||||
@@ -422,7 +431,7 @@ namespace boost
|
||||
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)
|
||||
{
|
||||
@@ -438,17 +447,17 @@ namespace boost
|
||||
}
|
||||
}
|
||||
#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);
|
||||
@@ -495,12 +504,12 @@ namespace boost
|
||||
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);
|
||||
@@ -510,7 +519,7 @@ namespace boost
|
||||
{
|
||||
detail::win32::Sleep(0);
|
||||
}
|
||||
|
||||
|
||||
disable_interruption::disable_interruption():
|
||||
interruption_was_enabled(interruption_enabled())
|
||||
{
|
||||
@@ -519,7 +528,7 @@ namespace boost
|
||||
get_current_thread_data()->interruption_enabled=false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
disable_interruption::~disable_interruption()
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
@@ -535,7 +544,7 @@ namespace boost
|
||||
get_current_thread_data()->interruption_enabled=true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
restore_interruption::~restore_interruption()
|
||||
{
|
||||
if(get_current_thread_data())
|
||||
@@ -582,7 +591,7 @@ namespace boost
|
||||
}
|
||||
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))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
|
||||
|
||||
#if defined(__MINGW32__) && !defined(_WIN64)
|
||||
#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__)
|
||||
|
||||
#include <boost/thread/detail/tss_hooks.hpp>
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
#if (__MINGW32_MAJOR_VERSION >3) || ((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
|
||||
#if defined(__MINGW64__) || (__MINGW32_MAJOR_VERSION >3) || \
|
||||
((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
|
||||
extern "C"
|
||||
{
|
||||
PIMAGE_TLS_CALLBACK __crt_xl_tls_callback__ __attribute__ ((section(".CRT$XLB"))) = on_tls_callback;
|
||||
|
||||
@@ -62,4 +62,29 @@ rule thread-run ( sources )
|
||||
[ compile-fail no_implicit_move_from_lvalue_thread.cpp ]
|
||||
[ compile-fail no_implicit_assign_from_lvalue_thread.cpp ]
|
||||
;
|
||||
|
||||
|
||||
#explicit tickets ;
|
||||
test-suite tickets
|
||||
:
|
||||
[ thread-run test_6170.cpp ]
|
||||
;
|
||||
|
||||
|
||||
explicit oth_tickets ;
|
||||
test-suite oth_tickets
|
||||
:
|
||||
[ thread-run test_2501.cpp ]
|
||||
[ thread-run test_4521.cpp ]
|
||||
[ thread-run test_4648.cpp ]
|
||||
[ thread-run test_4882.cpp ]
|
||||
[ thread-run test_5351.cpp ]
|
||||
[ thread-run test_5502.cpp ]
|
||||
[ thread-run test_5542_1.cpp ]
|
||||
[ thread-run test_5542_2.cpp ]
|
||||
[ thread-run test_5542_3.cpp ]
|
||||
[ thread-run test_6130.cpp ]
|
||||
[ thread-run test_6174.cpp ]
|
||||
;
|
||||
|
||||
}
|
||||
|
||||
10
test/test_2501.cpp
Normal file
10
test/test_2501.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
int main() {
|
||||
|
||||
boost::shared_mutex mtx; boost::upgrade_lock<boost::shared_mutex> lk(mtx);
|
||||
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> lk2(lk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
21
test/test_4521.cpp
Normal file
21
test/test_4521.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
int calculate_the_answer_to_life_the_universe_and_everything()
|
||||
{
|
||||
return 42;
|
||||
}
|
||||
|
||||
int main() {
|
||||
boost::packaged_task<int> pt(calculate_the_answer_to_life_the_universe_and_everything);
|
||||
boost::unique_future<int> fi=pt.get_future();
|
||||
|
||||
boost::thread task(boost::move(pt)); // launch task on a thread
|
||||
|
||||
fi.wait(); // wait for it to finish
|
||||
|
||||
//assert(fi.is_ready());
|
||||
//assert(fi.has_value());
|
||||
//assert(!fi.has_exception());
|
||||
//assert(fi.get_state()==boost::future_state::ready);
|
||||
//assert(fi.get()==42);
|
||||
}
|
||||
42
test/test_4648.cpp
Normal file
42
test/test_4648.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include <iostream>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/current_function.hpp>
|
||||
|
||||
class boostThreadLocksTest
|
||||
{
|
||||
public:
|
||||
boost::shared_mutex myMutex;
|
||||
//boost::upgrade_lock<boost::shared_mutex> myLock;
|
||||
static int firstFunction(boostThreadLocksTest *pBoostThreadLocksTest);
|
||||
static int secondFunction(boostThreadLocksTest *pBoostThreadLocksTest,
|
||||
boost::upgrade_lock<boost::shared_mutex>& upgr);
|
||||
boostThreadLocksTest()
|
||||
:myMutex()
|
||||
//, myLock(myMutex,boost::defer_lock_t())
|
||||
{};
|
||||
};
|
||||
|
||||
int boostThreadLocksTest::firstFunction(boostThreadLocksTest *pBoostThreadLocksTest)
|
||||
{
|
||||
std::cout<<"Entering "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
|
||||
boost::upgrade_lock<boost::shared_mutex> myLock(pBoostThreadLocksTest->myMutex);
|
||||
pBoostThreadLocksTest->secondFunction(pBoostThreadLocksTest, myLock);
|
||||
std::cout<<"Returned From Call "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
|
||||
std::cout<<"Returning from "<<boost::this_thread::get_id()<<" "<<"firstFunction"<<std::endl;
|
||||
return(0);
|
||||
}
|
||||
int boostThreadLocksTest::secondFunction(boostThreadLocksTest *pBoostThreadLocksTest, boost::upgrade_lock<boost::shared_mutex>& upgr) {
|
||||
std::cout<<"Before Exclusive Locking "<<boost::this_thread::get_id()<<" "<<"secondFunction"<<std::endl;
|
||||
boost::upgrade_to_unique_lock<boost::shared_mutex> localUniqueLock(upgr);
|
||||
std::cout<<"After Exclusive Locking "<<boost::this_thread::get_id()<<" "<<"secondFunction"<<std::endl;
|
||||
return(0);
|
||||
}
|
||||
int main() {
|
||||
boostThreadLocksTest myObject;
|
||||
boost::thread_group myThreadGroup;
|
||||
myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
|
||||
myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
|
||||
myThreadGroup.create_thread(boost::bind(boostThreadLocksTest::firstFunction,&myObject));
|
||||
myThreadGroup.join_all();
|
||||
return 0;
|
||||
}
|
||||
50
test/test_4882.cpp
Normal file
50
test/test_4882.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
boost::shared_mutex mutex;
|
||||
|
||||
void thread()
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
try
|
||||
{
|
||||
for (int i =0; i<10; ++i)
|
||||
{
|
||||
boost::system_time timeout = boost::get_system_time() + boost::posix_time::milliseconds(50);
|
||||
|
||||
if (mutex.timed_lock(timeout))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
boost::this_thread::sleep(boost::posix_time::milliseconds(10));
|
||||
mutex.unlock();
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (boost::lock_error& le)
|
||||
{
|
||||
std::cerr << "lock_error exception\n";
|
||||
}
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
const int nrThreads = 20;
|
||||
boost::thread* threads[nrThreads];
|
||||
|
||||
for (int i = 0; i < nrThreads; ++i)
|
||||
threads[i] = new boost::thread(&thread);
|
||||
|
||||
for (int i = 0; i < nrThreads; ++i)
|
||||
{
|
||||
threads[i]->join();
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
delete threads[i];
|
||||
}
|
||||
std::cout << __FILE__ << ":" << __LINE__ << std::endl;
|
||||
return 0;
|
||||
}
|
||||
45
test/test_5351.cpp
Normal file
45
test/test_5351.cpp
Normal file
@@ -0,0 +1,45 @@
|
||||
#include <iostream>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_types.hpp>
|
||||
#include <boost/thread/future.hpp>
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost;
|
||||
|
||||
int foo()
|
||||
{
|
||||
this_thread::sleep(seconds(10));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
boost::packaged_task<int> pt(&foo);
|
||||
boost::unique_future<int> fi = pt.get_future();
|
||||
boost::thread task(boost::move(pt)); // launch task on a thread
|
||||
|
||||
task.interrupt();
|
||||
|
||||
try
|
||||
{
|
||||
int v = fi.get();
|
||||
}
|
||||
catch (boost::thread_interrupted& exc)
|
||||
{
|
||||
std::cout << "OK: " << std::endl;
|
||||
return 0;
|
||||
}
|
||||
catch (boost::exception& exc)
|
||||
{
|
||||
std::cout << __LINE__ << " ERROR: " << boost::diagnostic_information(exc) << std::endl;
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
std::cout << __LINE__ << " ERROR: " << std::endl;
|
||||
return 2;
|
||||
}
|
||||
std::cout << __LINE__ << " ERROR: " << std::endl;
|
||||
return 3;
|
||||
}
|
||||
86
test/test_5502.cpp
Normal file
86
test/test_5502.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
// bm.cpp
|
||||
|
||||
// g++ test.cpp -lboost_thread-mt && ./a.out
|
||||
|
||||
// the ration of XXX and YYY determines
|
||||
// if this works or deadlocks
|
||||
int XXX = 20;
|
||||
int YYY = 10;
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
void sleepmillis(useconds_t miliis)
|
||||
{
|
||||
usleep(miliis * 1000);
|
||||
}
|
||||
|
||||
void worker1(boost::shared_mutex * lk, int * x)
|
||||
{
|
||||
(*x)++; // 1
|
||||
cout << "lock b try " << *x << endl;
|
||||
while (1)
|
||||
{
|
||||
if (lk->timed_lock(boost::posix_time::milliseconds(XXX))) break;
|
||||
sleepmillis(YYY);
|
||||
}
|
||||
cout << "lock b got " << *x << endl;
|
||||
(*x)++; // 2
|
||||
lk->unlock();
|
||||
}
|
||||
|
||||
void worker2(boost::shared_mutex * lk, int * x)
|
||||
{
|
||||
cout << "lock c try" << endl;
|
||||
lk->lock_shared();
|
||||
(*x)++;
|
||||
cout << "lock c got" << endl;
|
||||
lk->unlock_shared();
|
||||
cout << "lock c unlocked" << endl;
|
||||
(*x)++;
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
// create
|
||||
boost::shared_mutex* lk = new boost::shared_mutex();
|
||||
|
||||
// read lock
|
||||
cout << "lock a" << endl;
|
||||
lk->lock_shared();
|
||||
|
||||
int x1 = 0;
|
||||
boost::thread t1(boost::bind(worker1, lk, &x1));
|
||||
while (!x1)
|
||||
;
|
||||
BOOST_TEST(x1 == 1);
|
||||
sleepmillis(500);
|
||||
BOOST_TEST(x1 == 1);
|
||||
|
||||
int x2 = 0;
|
||||
boost::thread t2(boost::bind(worker2, lk, &x2));
|
||||
t2.join();
|
||||
BOOST_TEST(x2 == 2);
|
||||
|
||||
lk->unlock_shared();
|
||||
cout << "unlock a" << endl;
|
||||
|
||||
for (int i = 0; i < 2000; i++)
|
||||
{
|
||||
if (x1 == 2) break;
|
||||
sleepmillis(10);
|
||||
}
|
||||
|
||||
BOOST_TEST(x1 == 2);
|
||||
t1.join();
|
||||
delete lk;
|
||||
|
||||
return 0;
|
||||
}
|
||||
62
test/test_5542_1.cpp
Normal file
62
test/test_5542_1.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include <iostream>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
class Worker
|
||||
{
|
||||
public:
|
||||
|
||||
Worker()
|
||||
{
|
||||
// the thread is not-a-thread until we call start()
|
||||
}
|
||||
|
||||
void start(int N)
|
||||
{
|
||||
std::cout << "start\n";
|
||||
m_Thread = boost::thread(&Worker::processQueue, this, N);
|
||||
std::cout << "started\n";
|
||||
}
|
||||
|
||||
void join()
|
||||
{
|
||||
m_Thread.join();
|
||||
}
|
||||
|
||||
void processQueue(unsigned N)
|
||||
{
|
||||
float ms = N * 1e3;
|
||||
boost::posix_time::milliseconds workTime(ms);
|
||||
|
||||
std::cout << "Worker: started, will work for "
|
||||
<< ms << "ms"
|
||||
<< std::endl;
|
||||
|
||||
// We're busy, honest!
|
||||
boost::this_thread::sleep(workTime);
|
||||
|
||||
std::cout << "Worker: completed" << std::endl;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
boost::thread m_Thread;
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cout << "main: startup" << std::endl;
|
||||
|
||||
Worker worker;
|
||||
|
||||
std::cout << "main: create worker" << std::endl;
|
||||
|
||||
worker.start(3);
|
||||
|
||||
std::cout << "main: waiting for thread" << std::endl;
|
||||
|
||||
worker.join();
|
||||
|
||||
std::cout << "main: done" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
test/test_5542_2.cpp
Normal file
11
test/test_5542_2.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
void run_thread() {
|
||||
return;
|
||||
}
|
||||
|
||||
int main() {
|
||||
boost::thread t(run_thread);
|
||||
return 0;
|
||||
}
|
||||
|
||||
30
test/test_5542_3.cpp
Normal file
30
test/test_5542_3.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include <iostream>
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/date_time.hpp>
|
||||
|
||||
void workerFunc()
|
||||
{
|
||||
boost::posix_time::seconds workTime(3);
|
||||
|
||||
std::cout << "Worker: running" << std::endl;
|
||||
|
||||
// Pretend to do something useful...
|
||||
boost::this_thread::sleep(workTime);
|
||||
|
||||
std::cout << "Worker: finished" << std::endl;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
std::cout << "main: startup" << std::endl;
|
||||
|
||||
boost::thread workerThread(workerFunc);
|
||||
|
||||
std::cout << "main: waiting for thread" << std::endl;
|
||||
|
||||
workerThread.join();
|
||||
|
||||
std::cout << "main: done" << std::endl;
|
||||
|
||||
return 0;
|
||||
}
|
||||
22
test/test_6130.cpp
Normal file
22
test/test_6130.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <boost/thread.hpp>
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
boost::mutex mtx;
|
||||
boost::condition_variable cv;
|
||||
|
||||
int main()
|
||||
{
|
||||
for (int i=0; i<3; ++i) {
|
||||
const time_t wait_time = ::time(0)+1;
|
||||
|
||||
boost::mutex::scoped_lock lk(mtx);
|
||||
const bool res = cv.timed_wait(lk, boost::posix_time::from_time_t(wait_time));
|
||||
const time_t end_time = ::time(0);
|
||||
assert(end_time >= wait_time);
|
||||
std::cerr << end_time - wait_time << " OK\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
26
test/test_6170.cpp
Normal file
26
test/test_6170.cpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <boost/thread/shared_mutex.hpp>
|
||||
#include <boost/thread/locks.hpp>
|
||||
|
||||
// Including this will cause ambiguous errors in boost::move
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
using namespace boost;
|
||||
|
||||
typedef upgrade_lock<shared_mutex> auto_upgrade_lock;
|
||||
typedef upgrade_to_unique_lock<shared_mutex> auto_upgrade_unique_lock;
|
||||
|
||||
void testUpgrade(void)
|
||||
{
|
||||
shared_mutex mtx;
|
||||
auto_upgrade_lock lock(mtx);
|
||||
// Do some read-only stuff
|
||||
|
||||
auto_upgrade_unique_lock writeLock(lock);
|
||||
// Do some write-only stuff with the upgraded lock
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
testUpgrade();
|
||||
return 0;
|
||||
}
|
||||
35
test/test_6174.cpp
Normal file
35
test/test_6174.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
struct MovableButNonCopyable {
|
||||
#ifndef BOOST_NO_DEFAULTED_FUNCTIONS
|
||||
MovableButNonCopyable() = default;
|
||||
MovableButNonCopyable(MovableButNonCopyable const&) = delete;
|
||||
MovableButNonCopyable& operator=(MovableButNonCopyable const&) = delete;
|
||||
MovableButNonCopyable(MovableButNonCopyable&&) = default;
|
||||
MovableButNonCopyable& operator=(MovableButNonCopyable&&) = default;
|
||||
#else
|
||||
MovableButNonCopyable() {};
|
||||
MovableButNonCopyable(MovableButNonCopyable&&) {};
|
||||
MovableButNonCopyable& operator=(MovableButNonCopyable&&) {
|
||||
return *this;
|
||||
};
|
||||
private:
|
||||
MovableButNonCopyable(MovableButNonCopyable const&);
|
||||
MovableButNonCopyable& operator=(MovableButNonCopyable const&);
|
||||
#endif
|
||||
};
|
||||
int main()
|
||||
{
|
||||
boost::packaged_task<MovableButNonCopyable>(MovableButNonCopyable());
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -55,9 +55,9 @@ void test_barrier()
|
||||
BOOST_CHECK_EQUAL(global_parameter,5);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: barrier test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_barrier));
|
||||
|
||||
@@ -178,9 +178,9 @@ 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::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_waits));
|
||||
|
||||
@@ -211,9 +211,9 @@ void test_condition_notify_all()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_all));
|
||||
|
||||
@@ -144,9 +144,9 @@ void test_condition_notify_one()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_condition_notify_one));
|
||||
|
||||
@@ -162,9 +162,9 @@ void test_timed_wait_times_out()
|
||||
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::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: condition test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_timed_wait_times_out));
|
||||
|
||||
@@ -1157,9 +1157,9 @@ void test_wait_for_all_five_futures()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: futures test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_initial_state));
|
||||
|
||||
@@ -568,9 +568,9 @@ void test_try_lock_five()
|
||||
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: generic locks test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_lock_two_uncontended));
|
||||
|
||||
@@ -11,9 +11,9 @@ 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::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: hardware concurrency test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_hardware_concurrency_is_non_zero));
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
// 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>
|
||||
@@ -546,9 +545,9 @@ void test_shared_lock()
|
||||
BOOST_CHECK(dummy.shared_timed_locked_absolute);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: lock concept test suite");
|
||||
|
||||
typedef boost::mpl::vector<boost::mutex,boost::try_mutex,boost::timed_mutex,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// Copyright (C) 2007-8 Anthony Williams
|
||||
//
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
@@ -89,10 +89,17 @@ namespace user_test_ns
|
||||
}
|
||||
|
||||
bool move_called=false;
|
||||
|
||||
|
||||
struct nc:
|
||||
public boost::shared_ptr<int>
|
||||
{
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
nc() {}
|
||||
nc(nc&&)
|
||||
{
|
||||
move_called=true;
|
||||
}
|
||||
#endif
|
||||
nc move()
|
||||
{
|
||||
move_called=true;
|
||||
@@ -101,16 +108,30 @@ namespace user_test_ns
|
||||
};
|
||||
}
|
||||
|
||||
#ifdef BOOST_NO_RVALUE_REFERENCES
|
||||
namespace boost
|
||||
{
|
||||
template <>
|
||||
struct has_move_emulation_enabled_aux<user_test_ns::nc>
|
||||
: BOOST_MOVE_BOOST_NS::integral_constant<bool, true>
|
||||
{};
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_move_for_user_defined_type_unaffected()
|
||||
{
|
||||
user_test_ns::nc src;
|
||||
#ifndef BOOST_NO_RVALUE_REFERENCES
|
||||
user_test_ns::nc dest=boost::move(src);
|
||||
#else
|
||||
user_test_ns::nc dest=move(src);
|
||||
#endif
|
||||
BOOST_CHECK(user_test_ns::move_called);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_move_from_lvalue_on_construction));
|
||||
|
||||
@@ -331,9 +331,9 @@ void test_recursive_timed_mutex()
|
||||
timed_test(&do_test_recursive_timed_mutex, 3);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_mutex));
|
||||
|
||||
@@ -178,9 +178,9 @@ void test_call_once_retried_on_exception()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: call_once test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_call_once));
|
||||
|
||||
@@ -270,9 +270,9 @@ void test_unlocking_last_reader_only_unblocks_one_writer()
|
||||
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::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_multiple_readers));
|
||||
|
||||
@@ -283,9 +283,9 @@ void test_if_other_thread_has_upgrade_lock_try_lock_upgrade_returns_false()
|
||||
writer.join();
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: shared_mutex test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_only_one_upgrade_lock_permitted));
|
||||
|
||||
@@ -251,9 +251,9 @@ void test_timed_lock_times_out_but_read_lock_succeeds_if_read_lock_held()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::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));
|
||||
|
||||
@@ -216,9 +216,9 @@ void test_swap()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_sleep));
|
||||
|
||||
@@ -61,9 +61,9 @@ void test_can_use_function_object_for_exit_func()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: futures test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_exit_func_runs_when_thread_exits));
|
||||
|
||||
@@ -135,9 +135,9 @@ void test_thread_id_of_running_thread_returned_by_this_thread_get_id()
|
||||
BOOST_CHECK(id==t_id);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::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));
|
||||
|
||||
@@ -209,9 +209,9 @@ void test_thread_member_function_one_argument()
|
||||
}
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread launching test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_thread_function_no_arguments));
|
||||
|
||||
@@ -44,9 +44,9 @@ void test_move_assign()
|
||||
BOOST_CHECK_EQUAL(the_id,y_id);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_move_on_construction));
|
||||
|
||||
@@ -25,9 +25,9 @@ void test_move_from_function_move_return()
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_move_return));
|
||||
|
||||
@@ -25,9 +25,9 @@ void test_move_from_function_return_local()
|
||||
BOOST_CHECK_EQUAL(the_id,x_id);
|
||||
}
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: thread move test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_move_from_function_return_local));
|
||||
|
||||
@@ -343,9 +343,9 @@ void test_tss_cleanup_not_called_for_null_pointer()
|
||||
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: tss test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(test_tss));
|
||||
|
||||
@@ -95,9 +95,9 @@ void test_xtime_condvar_backwards_compatibility()
|
||||
|
||||
|
||||
|
||||
boost::unit_test_framework::test_suite* init_unit_test_suite(int, char*[])
|
||||
boost::unit_test::test_suite* init_unit_test_suite(int, char*[])
|
||||
{
|
||||
boost::unit_test_framework::test_suite* test =
|
||||
boost::unit_test::test_suite* test =
|
||||
BOOST_TEST_SUITE("Boost.Threads: xtime test suite");
|
||||
|
||||
test->add(BOOST_TEST_CASE(&test_xtime_cmp));
|
||||
|
||||
Reference in New Issue
Block a user