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

Compare commits

...

66 Commits

Author SHA1 Message Date
Vicente J. Botet Escriba
748fdee203 #130 - Bug in boost::condition_variable on Windows. 2017-08-28 22:07:02 +02:00
Vicente J. Botet Escriba
db6de8fd42 #130 - Bug in boost::condition_variable on Windows. 2017-08-28 22:06:53 +02:00
Vicente J. Botet Escriba
32229388f5 make use of timespec_now_realtime to fix issues with timespec_now. 2017-08-16 23:14:06 +02:00
Vicente J. Botet Escriba
333365aefe Merge branch 'develop' 2017-06-11 11:33:12 +02:00
Vicente J. Botet Escriba
d4cff01c72 #12519. 2017-06-11 11:30:59 +02:00
Vicente J. Botet Escriba
5f7dc381c7 Merge pull request #125 from vslavik/fix-comparison
Don't compare shared_ptr<> to 0
2017-06-07 17:57:21 +02:00
Václav Slavík
ea0bc01400 Don't compare shared_ptr<> to 0
Update the code to consistently use a check for .get() == 0, as was
already done in most, but not all, places, to avoid issues with
ambiguous overloaded operator== and operator!=.
2017-06-07 17:24:40 +02:00
Vicente J. Botet Escriba
3bc883d114 Merge pull request #124 from florianbehrens/patch-1
Fixed future::then template argument in documentation.
2017-05-24 12:18:21 +02:00
Florian Behrens
2e2850ff94 Fixed future::then template argument in documentation. 2017-05-24 12:03:38 +02:00
Vicente J. Botet Escriba
1a8019f499 Merge pull request #123 from Lastique/fix_entry_manager
Fix entry_manager constructor not accepting entry_ptr rvalue
2017-05-23 21:54:30 +02:00
Andrey Semashev
bf4b38b0af Fixed entry_manager constructor not accepting entry_ptr rvalue. This resolves compilation failures with MinGW. 2017-05-22 13:11:11 +03:00
Vicente J. Botet Escriba
f78b10a450 Merge pull request #122 from vincenthsu/develop
Fix sync_bounded_queue<>::size()
2017-05-11 01:33:43 +02:00
Vincent Hsu
603689372c Fix sync_bounded_queue<>::size() 2017-05-10 13:12:01 +08:00
Vicente J. Botet Escriba
5b05d6a8c8 fix compile error. 2017-05-07 16:01:10 +02:00
Vicente J. Botet Escriba
12c0fe14cd fix compile error. 2017-05-07 09:05:12 +02:00
Vicente J. Botet Escriba
ace2b8f89e rollback and use RAII. 2017-05-06 23:04:52 +02:00
Vicente J. Botet Escriba
24188f295c fix missing remove aiter while return. 2017-05-06 22:53:41 +02:00
Vicente J. Botet Escriba
653671bc0e fix compilation error. 2017-05-06 14:43:49 +02:00
Vicente J. Botet Escriba
c251497758 Avoid throwing on destructor: condition_variable. 2017-05-06 12:09:23 +02:00
Vicente J. Botet Escriba
69435fa44e try to fix lock on destructor issues. 2017-05-06 03:58:13 +02:00
Vicente J. Botet Escriba
6bc6fcab9a fix compilation error :( 2017-05-04 19:16:04 +02:00
Vicente J. Botet Escriba
50bac8c0eb fix compilation error :( 2017-05-04 07:58:58 +02:00
Vicente J. Botet Escriba
d709d4707c comment failing test. It is surely a bad test. 2017-05-01 03:39:53 +02:00
Vicente J. Botet Escriba
879db6841d try to fix compilation error on windows condition_variable.hpp. 2017-05-01 02:58:45 +02:00
Vicente J. Botet Escriba
2ce385b949 Add missing iostream. 2017-04-29 18:19:02 +02:00
Vicente J. Botet Escriba
21458fcc67 Add missing iostream. 2017-04-29 17:56:32 +02:00
Vicente J. Botet Escriba
d83b7ddc0f Merge branch 'develop' of github.com:boostorg/thread into develop 2017-04-29 17:35:01 +02:00
Vicente J. Botet Escriba
5ee3e8d04b manage with #12888. 2017-04-29 16:17:07 +02:00
Vicente J. Botet Escriba
dcafe1e17d Add noexcept(false) in destructor that could throw in C++11. 2017-04-29 16:15:57 +02:00
Vicente J. Botet Escriba
8dfa7c2e42 fix issue throw() noexcept issue. 2017-04-29 16:14:41 +02:00
Vicente J. Botet Escriba
c83d30f526 manage with #12874. 2017-04-29 16:13:52 +02:00
Vicente J. Botet Escriba
51b367df53 manage with 12958. 2017-04-29 16:12:35 +02:00
Vicente J. Botet Escriba
da83662e1a added test for 12949. 2017-04-29 16:11:31 +02:00
Vicente J. Botet Escriba
36861e5b67 Comment error. Need to be fixed. 2017-04-29 16:10:43 +02:00
Vicente J. Botet Escriba
67df4dd84e Merge pull request #120 from MarcelRaad/patch-2
Remove wrong MSVC version check
2017-04-21 02:10:19 +02:00
Marcel Raad
676521808d Remove wrong MSVC version check
There is no compiler with (_MSC_VER > 2000) and taking the legacy codepath would probably break compilation again when there is. As (_MSC_VER < 1300) (that would be MSVC up to 6.0 from 1998) is not supported by Boost anymore anyway and cannot compile Boost.Thread, this codepath can just be removed completely.
2017-03-24 22:28:41 +01:00
Vicente J. Botet Escriba
5363e099e4 Merge branch 'develop' 2017-03-03 07:28:59 +01:00
Vicente J. Botet Escriba
65f98979ff replace and by && to make the code portable 2017-03-01 19:39:56 +01:00
Vicente J. Botet Escriba
496acc1161 disable some tests with C++98. 2017-02-28 23:29:28 +01:00
Vicente J. Botet Escriba
30dff7f84a try to fix MONOTONIC timming issue. 2017-02-28 23:28:44 +01:00
Vicente J. Botet Escriba
7cb5d5bb46 Merge pull request #118 from Oberon00/loop-executor-no-polling
Loop executor: Don't poll but wait in loop() + test enhanchment.
2017-02-28 19:55:10 +01:00
Christian Neumüller
74c98b7fab loop_executor: (Re)activate and enhanche test. 2017-02-28 18:50:09 +01:00
Christian Neumüller
2ed0c2ad5f Loop executor: Don't poll but wait in loop(). 2017-02-28 18:50:08 +01:00
Vicente J. Botet Escriba
c969a6cf9c Fix uninitialized variables in scoped thread examples. Disable detach example for clang std::thread, it crashes. 2017-02-28 08:22:15 +01:00
Vicente J. Botet Escriba
c7348b29cf Compile conditionally to try to fix the timespec monotonic issue. This is not a final solution as we need to add two defines while building Boost.Thread, but atleast will allow to check if the solution work. 2017-02-25 22:41:00 +01:00
Vicente J. Botet Escriba
f79d51f099 Merge branch 'develop' 2017-02-25 13:57:19 +01:00
Vicente J. Botet Escriba
0d850b47ab Merge branch 'develop' of github.com:boostorg/thread into develop 2017-02-24 15:21:19 +01:00
Vicente J. Botet Escriba
9bbf9bed80 rollback MONOTONIC_CLOCK change as it seems it introduce regressions. 2017-02-24 15:20:04 +01:00
Vicente J. Botet Escriba
aadf0acce3 Merge pull request #114 from aargor/develop
Update MSC version check for VS2017RTW
2017-02-24 15:08:13 +01:00
Aaron Gorenstein
bd0379af57 Update MSC version check for VS2017RTW 2017-02-21 13:35:44 -08:00
Vicente J. Botet Escriba
336259c36a Merge branch 'develop' 2017-02-19 11:27:10 +01:00
Vicente J. Botet Escriba
544eda51bd make use of MONOTONIC_CLOCK when available. 2017-02-18 10:34:36 +01:00
Vicente J. Botet Escriba
e16705a72a Added more functors to scoped threads. 2017-02-18 10:22:34 +01:00
Vicente J. Botet Escriba
61a26492c3 use SFINAE for wait_for_all is_future_type. 2017-02-18 10:21:45 +01:00
Vicente J. Botet Escriba
854c61f597 Added Thread parameter in scoped_thread and thread_guard classes. 2017-01-25 13:20:08 +01:00
Vicente J. Botet Escriba
4d4ddcdc36 Merge branch 'develop' of github.com:boostorg/thread into develop 2017-01-25 08:13:22 +01:00
Vicente J. Botet Escriba
9347d9b731 Added Thread parameter in scoped_thread and thread_guard classes. 2017-01-25 08:13:04 +01:00
Vicente J. Botet Escriba
0a4733c9ad Merge pull request #110 from Lastique/fix_mingw
Compilation fixes for MinGW. Support for MSVC on ARM.
2017-01-22 10:19:54 +01:00
Andrey Semashev
b96d05461f Compilation fixes for MinGW. Support for MSVC on ARM.
1. Apparently, some versions of MinGW declare interlocked intrinsics
without volatile qualifiers. To avoid compilation failures cast away
volatile from pointers. This should also work with qualified pointers as
well.

2. Changed interlocked read/write helpers for MSVC. VS2012 and later have
the option to change volatile behavior to the standard C++. In that mode,
volatile no longer enforces memory ordering. To ensure the correct
behavior of the helpers, use compiler barriers to prohibit code
reordering. Also, limit the version to x86 only.

3. Added a separate version of interlocked read/write helpers for MSVC on
ARM. To avoid dependency on the compiler switch, use intrinsics to load
and store values and also emit the hardware memory fence.

4. Added two versions of interlocked read/write helpers for gcc and
compatible compilers. One version is based on __atomic intrinsics, the
other one (for older versions) uses inline assembler. These versions
should be more optimal than the generic fallback.
2017-01-07 20:08:30 +03:00
Vicente J. Botet Escriba
41f19bb098 Merge pull request #109 from jhunold/extra_semi
Remove trailing ";"
2017-01-06 20:58:30 +01:00
Jürgen Hunold
050a45aaa4 Remove trailing ";"
clang warning: extra ';' after member function definition [-Wextra-semi]
2017-01-06 10:01:37 +01:00
Vicente J. Botet Escriba
23cff22e5a fix category in thread_excaption. 2017-01-02 01:21:02 +01:00
Vicente J. Botet Escriba
a75995475a Merge pull request #107 from equal-l2/patch-1
fix typo
2016-12-19 23:54:49 +01:00
equal-l2
3ac5fd0916 fix typo
Just in case
2016-12-20 06:27:06 +09:00
Vicente J. Botet Escriba
56bce64d32 Merge pull request #106 from apolukhin/doc_clarify
Less ambiguous definition for lock(...) functions
2016-12-08 18:56:38 +01:00
Antony Polukhin
4385984215 Less ambiguous definition for lock(...) functions 2016-12-04 02:55:02 +03:00
44 changed files with 889 additions and 319 deletions

View File

@@ -358,7 +358,7 @@ The object's `name` virtual function returns a pointer to the string "future".]]
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
template<typename Ex, typename F>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(Ex& executor, F&& func); // EXTENSION
template<typename F>
@@ -898,7 +898,7 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
template<typename Ex, typename F>
__unique_future__<typename boost::result_of<F(__unique_future__)>::type>
then(Ex& executor, F&& func); // EXTENSION
template<typename F>
@@ -1387,7 +1387,7 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]
template<typename F>
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(F&& func) const; // EXTENSION
template<typename S, typename F>
template<typename Ex, typename F>
__unique_future__<typename boost::result_of<F(shared_future)>::type>
then(Ex& executor, F&& func) const; // EXTENSION
template<typename F>

View File

@@ -3034,8 +3034,8 @@ An instance of __reverse_lock doesn't ['own] the lock never.
[[Effects:] [Locks the __lockable_concept_type__ objects supplied as
arguments in an unspecified and indeterminate order in a way that
avoids deadlock. It is safe to call this function concurrently from
multiple threads with the same mutexes (or other lockable objects) in
different orders without risk of deadlock. If any of the __lock_ref__
multiple threads for any set of mutexes (or other lockable objects) in
any order without risk of deadlock. If any of the __lock_ref__
or __try_lock_ref__ operations on the supplied
__lockable_concept_type__ objects throws an exception any locks
acquired by the function will be released before the function exits.]]
@@ -3062,8 +3062,8 @@ are locked by the calling thread.]]
[[Effects:] [Locks all the __lockable_concept_type__ objects in the
supplied range in an unspecified and indeterminate order in a way that
avoids deadlock. It is safe to call this function concurrently from
multiple threads with the same mutexes (or other lockable objects) in
different orders without risk of deadlock. If any of the __lock_ref__
multiple threads for any set of mutexes (or other lockable objects) in
any order without risk of deadlock. If any of the __lock_ref__
or __try_lock_ref__ operations on the __lockable_concept_type__
objects in the supplied range throws an exception any locks acquired
by the function will be released before the function exits.]]

View File

@@ -15,11 +15,12 @@
struct detach;
struct join_if_joinable;
struct interrupt_and_join_if_joinable;
template <class CallableThread = join_if_joinable>
template <class CallableThread = join_if_joinable, class Thread = thread>
class strict_scoped_thread;
template <class CallableThread = join_if_joinable>
template <class CallableThread = join_if_joinable, class Thread = thread>
class scoped_thread;
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
template <class CallableThread, class Thread = thread>
void swap(scoped_thread<Callable, Thread>& lhs, scoped_threadCallable, Thread>& rhs) noexcept;
[section:motivation Motivation]
Based on the scoped_thread class defined in C++ Concurrency in Action Boost.Thread defines a thread wrapper class that instead of calling terminate if the thread is joinable on destruction, call a specific action given as template parameter.
@@ -54,7 +55,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
struct detach
{
void operator()(thread& t)
template <class Thread>
void operator()(Thread& t)
{
t.detach();
}
@@ -64,7 +66,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
struct join_if_joinable
{
void operator()(thread& t)
template <class Thread>
void operator()(Thread& t)
{
if (t.joinable())
{
@@ -79,7 +82,8 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
struct interrupt_and_join_if_joinable
{
void operator()(thread& t)
template <class Thread>
void operator()(Thread& t)
{
t.interrupt();
if (t.joinable())
@@ -96,7 +100,7 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
// #include <boost/thread/scoped_thread.hpp>
template <class CallableThread = join_if_joinable>
template <class CallableThread = join_if_joinable, class Thread = ::boost::thread>
class strict_scoped_thread
{
thread t_; // for exposition purposes only
@@ -105,7 +109,7 @@ The difference between strict_scoped_thread and scoped_thread is that the strict
strict_scoped_thread(strict_scoped_thread const&) = delete;
strict_scoped_thread& operator=(strict_scoped_thread const&) = delete;
explicit strict_scoped_thread(thread&& t) noexcept;
explicit strict_scoped_thread(Thread&& t) noexcept;
template <typename F&&, typename ...Args>
explicit strict_scoped_thread(F&&, Args&&...);
@@ -130,7 +134,7 @@ This wrapper can be used to join the thread before destroying it.
[section:default_constructor Constructor from a __thread]
explicit strict_scoped_thread(thread&& t) noexcept;
explicit strict_scoped_thread(Thread&& t) noexcept;
[variablelist
@@ -180,7 +184,7 @@ This wrapper can be used to join the thread before destroying it.
#include <boost/thread/scoped_thread.hpp>
template <class CallableThread>
template <class CallableThread, class Thread = thread>
class scoped_thread
{
thread t_; // for exposition purposes only
@@ -230,7 +234,8 @@ This wrapper can be used to join the thread before destroying it.
};
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
template <class CallableThread, class Thread = thread>
void swap(scoped_thread<CallableThread,Thread>& lhs,scoped_thread<CallableThread,Thread>& rhs) noexcept;
RAII __thread wrapper adding a specific destroyer allowing to master what can be done at destruction time.
@@ -504,7 +509,8 @@ any) to `*this` after having called to `CallableThread()(t_)`.
#include <boost/thread/scoped_thread.hpp>
void swap(scoped_thread& lhs,scoped_thread& rhs) noexcept;
template <class CallableThread, class Thread = thread>
void swap(scoped_thread<Callable, Thread>& lhs, scoped_threadCallable, Thread>& rhs) noexcept;
[variablelist

View File

@@ -17,6 +17,7 @@
#include <boost/thread/future.hpp>
#include <boost/assert.hpp>
#include <string>
#include <iostream>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
int p1()

View File

@@ -39,36 +39,23 @@ void do_something_in_current_thread()
{
}
//void do_something_with_current_thread(boost::thread&& th)
//{
// th.join();
//}
int main()
{
{
int some_local_state;
int some_local_state=0;
boost::strict_scoped_thread<> t( (boost::thread(func(some_local_state))));
do_something_in_current_thread();
}
{
int some_local_state;
int some_local_state=0;
boost::thread t(( func(some_local_state) ));
boost::strict_scoped_thread<> g( (boost::move(t)) );
do_something_in_current_thread();
}
// {
// int some_local_state;
// boost::thread t(( func(some_local_state) ));
// boost::strict_scoped_thread<> g( (boost::move(t)) );
//
// do_something_in_current_thread();
// do_something_with_current_thread(boost::thread(g));
// }
{
int some_local_state;
int some_local_state=0;
boost::scoped_thread<> t( (boost::thread(func(some_local_state))));
if (t.joinable())
@@ -76,14 +63,17 @@ int main()
else
do_something_in_current_thread();
}
#if 0
{
int some_local_state;
int some_local_state=0;
boost::thread t(( func(some_local_state) ));
boost::scoped_thread<> g( (boost::move(t)) );
t.detach();
if (g.joinable())
g.detach();
do_something_in_current_thread();
}
#endif
{
boost::scoped_thread<> g( &f, 1, 2 );
do_something_in_current_thread();

View File

@@ -0,0 +1,112 @@
// (C) Copyright 2009-2012 Anthony Williams
// (C) Copyright 2012 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if __cplusplus < 201103L
int main()
{
return 0;
}
#else
#define BOOST_THREAD_VERSION 3
#include <iostream>
#include <boost/thread/scoped_thread.hpp>
#include <thread>
#include <cassert>
void do_something(int& i)
{
++i;
}
void f(int, int)
{
}
struct func
{
int& i;
func(int& i_) :
i(i_)
{
}
void operator()()
{
for (unsigned j = 0; j < 1000000; ++j)
{
do_something(i);
}
}
};
void do_something_in_current_thread()
{
}
using strict_scoped_thread = boost::strict_scoped_thread<boost::join_if_joinable, std::thread>;
using scoped_thread = boost::scoped_thread<boost::join_if_joinable, std::thread>;
int main()
{
{
int some_local_state=0;
strict_scoped_thread t( (std::thread(func(some_local_state))));
do_something_in_current_thread();
}
{
int some_local_state=0;
std::thread t(( func(some_local_state) ));
strict_scoped_thread g( (boost::move(t)) );
do_something_in_current_thread();
}
{
int some_local_state=0;
std::thread t(( func(some_local_state) ));
strict_scoped_thread g( (std::move(t)) );
do_something_in_current_thread();
}
{
int some_local_state=1;
scoped_thread t( (std::thread(func(some_local_state))));
if (t.joinable()) {
t.join();
assert( ! t.joinable() );
}
else
do_something_in_current_thread();
}
#if 0
try
{
int some_local_state=1;
std::thread t(( func(some_local_state) ));
scoped_thread g( (boost::move(t)) );
if (g.joinable()) {
// CLANG crash here
g.detach();
assert( ! g.joinable() );
}
do_something_in_current_thread();
}
catch (...) {
assert( false);
}
#endif
{
scoped_thread g( &f, 1, 2 );
do_something_in_current_thread();
}
return 0;
}
#endif

View File

@@ -0,0 +1,66 @@
// (C) Copyright 2009-2012 Anthony Williams
// (C) Copyright 2012 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#if __cplusplus < 201103L
int main()
{
return 0;
}
#else
#include <iostream>
#include <string>
#include <boost/thread/thread_only.hpp>
#include <boost/thread/thread_guard.hpp>
#include <thread>
void do_something(int& i)
{
++i;
}
struct func
{
int& i;
func(int& i_):i(i_){}
void operator()()
{
for(unsigned j=0;j<1000000;++j)
{
do_something(i);
}
}
private:
func& operator=(func const&);
};
void do_something_in_current_thread()
{}
using thread_guard = boost::thread_guard<boost::join_if_joinable, std::thread>;
void f()
{
int some_local_state;
func my_func(some_local_state);
std::thread t(my_func);
thread_guard g(t);
do_something_in_current_thread();
}
int main()
{
f();
return 0;
}
#endif

View File

@@ -127,7 +127,7 @@ namespace concurrent
inline size_type size(lock_guard<mutex>& lk) const BOOST_NOEXCEPT
{
if (full(lk)) return capacity(lk);
return ((out_+capacity(lk)-in_) % capacity(lk));
return ((in_+capacity(lk)-out_) % capacity(lk));
}
inline void throw_if_closed(unique_lock<mutex>&);
@@ -484,7 +484,9 @@ namespace concurrent
queue_op_status sync_bounded_queue<ValueType>::wait_pull_front(ValueType& elem, unique_lock<mutex>& lk)
{
if (empty(lk) && closed(lk)) {return queue_op_status::closed;}
wait_until_not_empty(lk);
bool is_closed = false;
wait_until_not_empty(lk, is_closed);
if (is_closed) {return queue_op_status::closed;}
pull_front(elem, lk);
return queue_op_status::success;
}

View File

@@ -12,6 +12,8 @@
#include <boost/detail/workaround.hpp>
#include <boost/thread/detail/platform.hpp>
#define BOOST_THREAD_USEFIXES_TIMESPEC
//#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
//#define BOOST_THREAD_DONT_PROVIDE_INTERRUPTIONS
// ATTRIBUTE_MAY_ALIAS

View File

@@ -155,7 +155,15 @@ namespace boost
};
#endif
}
namespace thread_detail {
#ifdef BOOST_THREAD_USES_CHRONO
#if defined(BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC) && defined(BOOST_THREAD_USEFIXES_TIMESPEC)
typedef chrono::steady_clock internal_clock_t;
#else
typedef chrono::system_clock internal_clock_t;
#endif
#endif
}
class BOOST_THREAD_DECL thread
{
public:
@@ -482,13 +490,14 @@ namespace boost
return try_join_until(chrono::steady_clock::now() + rel_time);
}
#endif
template <class Clock, class Duration>
bool try_join_until(const chrono::time_point<Clock, Duration>& t)
{
using namespace chrono;
bool joined= false;
do {
system_clock::time_point s_now = system_clock::now();
thread_detail::internal_clock_t::time_point s_now = thread_detail::internal_clock_t::now();
typename Clock::duration d = ceil<nanoseconds>(t-Clock::now());
if (d <= Clock::duration::zero()) return false; // in case the Clock::time_point t is already reached
joined = try_join_until(s_now + d);
@@ -496,10 +505,10 @@ namespace boost
return true;
}
template <class Duration>
bool try_join_until(const chrono::time_point<chrono::system_clock, Duration>& t)
bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, Duration>& t)
{
using namespace chrono;
typedef time_point<system_clock, nanoseconds> nano_sys_tmpt;
typedef time_point<thread_detail::internal_clock_t, nanoseconds> nano_sys_tmpt;
return try_join_until(nano_sys_tmpt(ceil<nanoseconds>(t.time_since_epoch())));
}
#endif
@@ -514,7 +523,7 @@ namespace boost
//}
#ifdef BOOST_THREAD_USES_CHRONO
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
{
chrono::milliseconds rel_time= chrono::ceil<chrono::milliseconds>(tp-chrono::system_clock::now());
return do_try_join_until(rel_time.count());
@@ -535,7 +544,7 @@ namespace boost
}
#endif
#ifdef BOOST_THREAD_USES_CHRONO
bool try_join_until(const chrono::time_point<chrono::system_clock, chrono::nanoseconds>& tp)
bool try_join_until(const chrono::time_point<thread_detail::internal_clock_t, chrono::nanoseconds>& tp)
{
using namespace chrono;
nanoseconds d = tp.time_since_epoch();

View File

@@ -40,19 +40,19 @@ namespace boost
typedef system::system_error base_type;
public:
thread_exception()
: base_type(0,system::system_category())
: base_type(0,system::generic_category())
{}
thread_exception(int sys_error_code)
: base_type(sys_error_code, system::system_category())
: base_type(sys_error_code, system::generic_category())
{}
thread_exception( int ev, const char * what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
: base_type(system::error_code(ev, system::generic_category()), what_arg)
{
}
thread_exception( int ev, const std::string & what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
: base_type(system::error_code(ev, system::generic_category()), what_arg)
{
}
@@ -74,18 +74,18 @@ namespace boost
typedef system::system_error base_type;
public:
condition_error()
: base_type(system::error_code(0, system::system_category()), "Condition error")
: base_type(system::error_code(0, system::generic_category()), "Condition error")
{}
condition_error( int ev )
: base_type(system::error_code(ev, system::system_category()), "Condition error")
: base_type(system::error_code(ev, system::generic_category()), "Condition error")
{
}
condition_error( int ev, const char * what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
: base_type(system::error_code(ev, system::generic_category()), what_arg)
{
}
condition_error( int ev, const std::string & what_arg )
: base_type(system::error_code(ev, system::system_category()), what_arg)
: base_type(system::error_code(ev, system::generic_category()), what_arg)
{
}
};

View File

@@ -38,7 +38,7 @@ namespace boost
* \par Synchronization
* The completion of all the closures happen before the completion of the executor destructor.
*/
virtual ~executor() {};
virtual ~executor() {}
/**
* \par Effects

View File

@@ -41,7 +41,7 @@ namespace boost
* \par Synchronization
* The completion of all the closures happen before the completion of the executor destructor.
*/
~executor_ref() {};
~executor_ref() {}
/**
* \par Effects

View File

@@ -16,6 +16,7 @@
#include <boost/thread/detail/move.hpp>
#include <boost/thread/concurrent_queues/sync_queue.hpp>
#include <boost/thread/executors/work.hpp>
#include <boost/assert.hpp>
#include <boost/config/abi_prefix.hpp>
@@ -40,15 +41,33 @@ namespace executors
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool try_executing_one()
{
return execute_one(/*wait:*/false);
}
private:
/**
* Effects: Execute one task.
* Remark: If wait is true, waits until a task is available or the executor
* is closed. If wait is false, returns false immediately if no
* task is available.
* Returns: whether a task has been executed (if wait is true, only returns false if closed).
* Throws: whatever the current task constructor throws or the task() throws.
*/
bool execute_one(bool wait)
{
work task;
try
{
if (work_queue.try_pull(task) == queue_op_status::success)
queue_op_status status = wait ?
work_queue.wait_pull(task) :
work_queue.try_pull(task);
if (status == queue_op_status::success)
{
task();
return true;
}
BOOST_ASSERT(!wait || status == queue_op_status::closed);
return false;
}
catch (...)
@@ -57,21 +76,6 @@ namespace executors
//return false;
}
}
private:
/**
* Effects: schedule one task or yields
* Throws: whatever the current task constructor throws or the task() throws.
*/
void schedule_one_or_yield()
{
if ( ! try_executing_one())
{
this_thread::yield();
}
}
public:
/// loop_executor is not copyable.
@@ -101,10 +105,10 @@ namespace executors
*/
void loop()
{
while (!closed())
while (execute_one(/*wait:*/true))
{
schedule_one_or_yield();
}
BOOST_ASSERT(closed());
while (try_executing_one())
{
}

View File

@@ -1335,7 +1335,7 @@ namespace boost
bool valid() const BOOST_NOEXCEPT
{
return future_ != 0 && future_->valid();
return future_.get() != 0 && future_->valid();
}
void wait() const
@@ -1355,7 +1355,7 @@ namespace boost
boost::throw_exception(future_uninitialized());
}
return future_->mutex;
};
}
notify_when_ready_handle notify_when_ready(boost::condition_variable_any& cv)
{
@@ -1639,7 +1639,9 @@ namespace boost
base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other))))
{
}
#if defined BOOST_THREAD_PROVIDES_FUTURE_UNWRAP
inline explicit BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R> >) other); // EXTENSION
#endif
explicit BOOST_THREAD_FUTURE(BOOST_THREAD_RV_REF(shared_future<R>) other) :
base_type(boost::move(static_cast<base_type&>(BOOST_THREAD_RV(other))))
@@ -1680,7 +1682,7 @@ namespace boost
// retrieving the value
move_dest_type get()
{
if (this->future_ == 0)
if (this->future_.get() == 0)
{
boost::throw_exception(future_uninitialized());
}
@@ -1700,7 +1702,7 @@ namespace boost
get_or(BOOST_THREAD_RV_REF(R2) v)
{
if (this->future_ == 0)
if (this->future_.get() == 0)
{
boost::throw_exception(future_uninitialized());
}
@@ -1726,7 +1728,7 @@ namespace boost
typename boost::disable_if< is_void<R2>, move_dest_type>::type
get_or(R2 const& v) // EXTENSION
{
if (this->future_ == 0)
if (this->future_.get() == 0)
{
boost::throw_exception(future_uninitialized());
}
@@ -1941,7 +1943,7 @@ namespace boost
// retrieving the value
move_dest_type get()
{
if (this->future_ == 0)
if (this->future_.get() == 0)
{
boost::throw_exception(future_uninitialized());
}
@@ -1957,7 +1959,7 @@ namespace boost
}
move_dest_type get_or(BOOST_THREAD_RV_REF(R) v) // EXTENSION
{
if (this->future_ == 0)
if (this->future_.get() == 0)
{
boost::throw_exception(future_uninitialized());
}
@@ -1976,7 +1978,7 @@ namespace boost
move_dest_type get_or(R const& v) // EXTENSION
{
if (this->future_ == 0)
if (this->future_.get() == 0)
{
boost::throw_exception(future_uninitialized());
}
@@ -4747,7 +4749,7 @@ namespace detail {
inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type>
BOOST_THREAD_FUTURE<R>::then(launch policy, BOOST_THREAD_FWD_REF(F) func) {
typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -4811,7 +4813,7 @@ namespace detail {
inline BOOST_THREAD_FUTURE<typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type>
BOOST_THREAD_FUTURE<R>::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) {
typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -4835,7 +4837,7 @@ namespace detail {
return this->then(this->launch_policy(), boost::forward<F>(func));
#else
typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -4865,7 +4867,7 @@ namespace detail {
BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::then(launch policy, BOOST_THREAD_FWD_REF(F) func) {
typedef BOOST_THREAD_FUTURE<R2> R;
typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -4939,7 +4941,7 @@ namespace detail {
BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) {
typedef BOOST_THREAD_FUTURE<R2> R;
typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -4965,7 +4967,7 @@ namespace detail {
#else
typedef BOOST_THREAD_FUTURE<R2> R;
typedef typename boost::result_of<F(BOOST_THREAD_FUTURE<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -4995,7 +4997,7 @@ namespace detail {
shared_future<R>::then(launch policy, BOOST_THREAD_FWD_REF(F) func) const
{
typedef typename boost::result_of<F(shared_future<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
if (underlying_cast<int>(policy) & int(launch::async)) {
@@ -5064,7 +5066,7 @@ namespace detail {
shared_future<R>::then(Ex& ex, BOOST_THREAD_FWD_REF(F) func) const
{
typedef typename boost::result_of<F(shared_future<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
return BOOST_THREAD_MAKE_RV_REF((boost::detail::make_shared_future_executor_continuation_shared_state<Ex, shared_future<R>, future_type>(ex,
@@ -5085,7 +5087,7 @@ namespace detail {
return this->then(this->launch_policy(), boost::forward<F>(func));
#else
typedef typename boost::result_of<F(shared_future<R>)>::type future_type;
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
boost::unique_lock<boost::mutex> lock(this->future_->mutex);
launch policy = this->launch_policy(lock);
@@ -5257,7 +5259,7 @@ namespace detail
BOOST_THREAD_FUTURE<R2>
BOOST_THREAD_FUTURE<BOOST_THREAD_FUTURE<R2> >::unwrap()
{
BOOST_THREAD_ASSERT_PRECONDITION(this->future_!=0, future_uninitialized());
BOOST_THREAD_ASSERT_PRECONDITION(this->future_.get()!=0, future_uninitialized());
// keep state alive as we move ourself but hold the lock
shared_ptr<detail::shared_state_base> sentinel(this->future_);
@@ -5656,5 +5658,5 @@ namespace detail
#endif // BOOST_THREAD_PROVIDES_FUTURE_WHEN_ALL_WHEN_ANY
}
#endif // BOOST_NO_EXCEPTION
#endif // BOOST_NO_EXCEPTIONS
#endif // header

View File

@@ -60,7 +60,7 @@ namespace boost
}
#else
template<typename F1, typename... Fs>
void wait_for_all(F1& f1, Fs&... fs)
typename boost::enable_if<is_future_type<F1>,void>::type wait_for_all(F1& f1, Fs&... fs)
{
bool dummy[] = { (f1.wait(), true), (fs.wait(), true)... };

View File

@@ -45,9 +45,17 @@ namespace boost
m_.unlock();
m=&m_;
}
~lock_on_exit()
void deactivate()
{
if(m)
if (m)
{
m->lock();
}
m = 0;
}
~lock_on_exit() BOOST_NOEXCEPT_IF(false)
{
if (m)
{
m->lock();
}
@@ -70,10 +78,13 @@ namespace boost
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
pthread_mutex_t* the_mutex = &internal_mutex;
guard.activate(m);
res = pthread_cond_wait(&cond,the_mutex);
check_for_interruption.check();
guard.deactivate();
#else
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
#endif
res = pthread_cond_wait(&cond,the_mutex);
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
this_thread::interruption_point();
@@ -101,10 +112,13 @@ namespace boost
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
pthread_mutex_t* the_mutex = &internal_mutex;
guard.activate(m);
cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
check_for_interruption.check();
guard.deactivate();
#else
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
#endif
cond_res=pthread_cond_timedwait(&cond,the_mutex,&timeout);
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
this_thread::interruption_point();
@@ -176,6 +190,8 @@ namespace boost
#endif
guard.activate(m);
res=pthread_cond_wait(&cond,&internal_mutex);
check_for_interruption.check();
guard.deactivate();
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
this_thread::interruption_point();
@@ -404,6 +420,8 @@ namespace boost
#endif
guard.activate(m);
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
check_for_interruption.check();
guard.deactivate();
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
this_thread::interruption_point();

View File

@@ -17,6 +17,7 @@
#if defined BOOST_THREAD_USES_DATETIME
#include <boost/thread/xtime.hpp>
#endif
#ifdef BOOST_THREAD_USES_CHRONO
#include <boost/chrono/system_clocks.hpp>
#include <boost/chrono/ceil.hpp>
@@ -68,7 +69,20 @@ namespace boost
unique_lock<mutex>& lock,
struct timespec const &timeout)
{
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now()));
#if ! defined BOOST_THREAD_USEFIXES_TIMESPEC
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now()));
#elif ! defined BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
//using namespace chrono;
//nanoseconds ns = chrono::system_clock::now().time_since_epoch();
struct timespec ts = boost::detail::timespec_now_realtime();
//ts.tv_sec = static_cast<long>(chrono::duration_cast<chrono::seconds>(ns).count());
//ts.tv_nsec = static_cast<long>((ns - chrono::duration_cast<chrono::seconds>(ns)).count());
return do_wait_until(lock, boost::detail::timespec_plus(timeout, ts));
#else
// old behavior was fine for monotonic
return do_wait_until(lock, boost::detail::timespec_plus(timeout, boost::detail::timespec_now_realtime()));
#endif
}
public:

View File

@@ -1,6 +1,6 @@
#ifndef BOOST_PTHREAD_MUTEX_SCOPED_LOCK_HPP
#define BOOST_PTHREAD_MUTEX_SCOPED_LOCK_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
@@ -20,41 +20,47 @@ namespace boost
pthread_mutex_t* m;
bool locked;
public:
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_):
explicit pthread_mutex_scoped_lock(pthread_mutex_t* m_) BOOST_NOEXCEPT:
m(m_),locked(true)
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
void unlock()
void unlock() BOOST_NOEXCEPT
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
locked=false;
}
~pthread_mutex_scoped_lock()
void check() BOOST_NOEXCEPT
{
if(locked)
{
unlock();
}
}
~pthread_mutex_scoped_lock() BOOST_NOEXCEPT
{
if(locked)
{
unlock();
}
}
};
class pthread_mutex_scoped_unlock
{
pthread_mutex_t* m;
public:
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_):
explicit pthread_mutex_scoped_unlock(pthread_mutex_t* m_) BOOST_NOEXCEPT:
m(m_)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
~pthread_mutex_scoped_unlock()
~pthread_mutex_scoped_unlock() BOOST_NOEXCEPT
{
BOOST_VERIFY(!pthread_mutex_lock(m));
}
};
}
}

View File

@@ -177,6 +177,7 @@ namespace boost
thread_data_base* const thread_info;
pthread_mutex_t* m;
bool set;
bool done;
void check_for_interruption()
{
@@ -193,7 +194,7 @@ namespace boost
public:
explicit interruption_checker(pthread_mutex_t* cond_mutex,pthread_cond_t* cond):
thread_info(detail::get_current_thread_data()),m(cond_mutex),
set(thread_info && thread_info->interrupt_enabled)
set(thread_info && thread_info->interrupt_enabled), done(false)
{
if(set)
{
@@ -208,9 +209,10 @@ namespace boost
BOOST_VERIFY(!pthread_mutex_lock(m));
}
}
~interruption_checker()
void check()
{
if(set)
if ( ! done) {
if (set)
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
lock_guard<mutex> guard(thread_info->data_mutex);
@@ -221,6 +223,13 @@ namespace boost
{
BOOST_VERIFY(!pthread_mutex_unlock(m));
}
done = true;
}
}
~interruption_checker() BOOST_NOEXCEPT_IF(false)
{
check();
}
};
#endif

View File

@@ -75,6 +75,33 @@ namespace boost
{
timespec ts;
#if defined CLOCK_MONOTONIC && defined BOOST_THREAD_USEFIXES_TIMESPEC
if ( ::clock_gettime( CLOCK_MONOTONIC, &ts ) )
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
}
#elif defined(BOOST_THREAD_TIMESPEC_MAC_API)
timeval tv;
::gettimeofday(&tv, 0);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
#else
if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
}
#endif
return ts;
}
inline timespec timespec_now_realtime()
{
timespec ts;
#if defined(BOOST_THREAD_TIMESPEC_MAC_API)
timeval tv;
::gettimeofday(&tv, 0);
@@ -83,6 +110,8 @@ namespace boost
#else
if ( ::clock_gettime( CLOCK_REALTIME, &ts ) )
{
ts.tv_sec = 0;
ts.tv_nsec = 0;
BOOST_ASSERT(0 && "Boost::Thread - Internal Error");
}
#endif

View File

@@ -34,10 +34,10 @@ namespace boost
* boost::strict_scoped_thread<> t((boost::thread(F)));
*
*/
template <class CallableThread = join_if_joinable>
template <class CallableThread = join_if_joinable, class Thread=::boost::thread>
class strict_scoped_thread
{
thread t_;
Thread t_;
struct dummy;
public:
@@ -47,13 +47,13 @@ namespace boost
*
*/
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type>
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type>
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
#else
template <class F>
explicit strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f,
typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) :
typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) :
t_(boost::forward<F>(f)) {}
template <class F, class A1>
strict_scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
@@ -73,7 +73,7 @@ namespace boost
*
* Effects: move the thread to own @c t.
*/
explicit strict_scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT :
explicit strict_scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT :
t_(boost::move(t))
{
}
@@ -111,14 +111,15 @@ namespace boost
* t.interrupt();
*
*/
template <class CallableThread = join_if_joinable>
template <class CallableThread = join_if_joinable, class Thread=::boost::thread>
class scoped_thread
{
thread t_;
Thread t_;
struct dummy;
public:
typedef thread::id id;
typedef typename Thread::id id;
typedef typename Thread::native_handle_type native_handle_type;
BOOST_THREAD_MOVABLE_ONLY( scoped_thread) /// Movable only
@@ -137,13 +138,13 @@ namespace boost
*/
#if ! defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type>
template <class F, class ...Args, typename = typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type>
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(Args)... args) :
t_(boost::forward<F>(f), boost::forward<Args>(args)...) {}
#else
template <class F>
explicit scoped_thread(BOOST_THREAD_FWD_REF(F) f,
typename disable_if<is_same<typename decay<F>::type, thread>, void* >::type=0) :
typename disable_if<is_same<typename decay<F>::type, Thread>, void* >::type=0) :
t_(boost::forward<F>(f)) {}
template <class F, class A1>
scoped_thread(BOOST_THREAD_FWD_REF(F) f, BOOST_THREAD_FWD_REF(A1) a1) :
@@ -163,12 +164,12 @@ namespace boost
*
* Effects: move the thread to own @c t.
*/
explicit scoped_thread(BOOST_THREAD_RV_REF(thread) t) BOOST_NOEXCEPT :
explicit scoped_thread(BOOST_THREAD_RV_REF(Thread) t) BOOST_NOEXCEPT :
t_(boost::move(t))
{
}
// explicit operator thread()
// explicit operator Thread()
// {
// return boost::move(t_);
// }
@@ -213,7 +214,7 @@ namespace boost
}
// forwarded thread functions
inline thread::id get_id() const BOOST_NOEXCEPT
inline id get_id() const BOOST_NOEXCEPT
{
return t_.get_id();
}
@@ -242,7 +243,7 @@ namespace boost
}
#endif
thread::native_handle_type native_handle()BOOST_NOEXCEPT
native_handle_type native_handle()BOOST_NOEXCEPT
{
return t_.native_handle();
}
@@ -266,13 +267,13 @@ namespace boost
static unsigned hardware_concurrency() BOOST_NOEXCEPT
{
return thread::hardware_concurrency();
return Thread::hardware_concurrency();
}
#ifdef BOOST_THREAD_PROVIDES_PHYSICAL_CONCURRENCY
static unsigned physical_concurrency() BOOST_NOEXCEPT
{
return thread::physical_concurrency();
return Thread::physical_concurrency();
}
#endif
};
@@ -280,12 +281,13 @@ namespace boost
/**
* Effects: swaps the contents of two scoped threads.
*/
template <class Destroyer>
void swap(scoped_thread<Destroyer>& lhs, scoped_thread<Destroyer>& rhs)
template <class Destroyer, class Thread >
void swap(scoped_thread<Destroyer, Thread>& lhs, scoped_thread<Destroyer, Thread>& rhs)
BOOST_NOEXCEPT {
return lhs.swap(rhs);
}
typedef scoped_thread<> joining_thread;
}
#include <boost/config/abi_suffix.hpp>

View File

@@ -21,15 +21,29 @@ namespace boost
struct detach
{
void operator()(thread& t)
template <class Thread>
void operator()(Thread& t)
{
t.detach();
}
};
struct detach_if_joinable
{
template <class Thread>
void operator()(Thread& t)
{
if (t.joinable())
{
t.detach();
}
}
};
struct join_if_joinable
{
void operator()(thread& t)
template <class Thread>
void operator()(Thread& t)
{
if (t.joinable())
{
@@ -41,7 +55,8 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
struct interrupt_and_join_if_joinable
{
void operator()(thread& t)
template <class Thread>
void operator()(Thread& t)
{
if (t.joinable())
{

View File

@@ -21,14 +21,14 @@ namespace boost
/**
* Non-copyable RAII scoped thread guard joiner which join the thread if joinable when destroyed.
*/
template <class CallableThread = join_if_joinable>
template <class CallableThread = join_if_joinable, class Thread=::boost::thread>
class thread_guard
{
thread& t_;
Thread& t_;
public:
BOOST_THREAD_NO_COPYABLE( thread_guard)
explicit thread_guard(thread& t) :
explicit thread_guard(Thread& t) :
t_(t)
{
}

View File

@@ -142,32 +142,38 @@ namespace boost
struct relocker
{
BOOST_THREAD_NO_COPYABLE(relocker)
lock_type& lock;
bool unlocked;
lock_type& _lock;
bool _unlocked;
relocker(lock_type& lock_):
lock(lock_),unlocked(false)
_lock(lock_), _unlocked(false)
{}
void unlock()
{
lock.unlock();
unlocked=true;
if ( ! _unlocked )
{
_lock.unlock();
_unlocked=true;
}
}
~relocker()
void lock()
{
if(unlocked)
{
lock.lock();
}
if ( _unlocked )
{
_lock.lock();
_unlocked=false;
}
}
~relocker() BOOST_NOEXCEPT_IF(false)
{
lock();
}
};
entry_ptr get_wait_entry()
{
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
boost::lock_guard<boost::mutex> lk(internal_mutex);
if(!wake_sem)
{
wake_sem=detail::win32::create_anonymous_semaphore(0,LONG_MAX);
@@ -190,18 +196,32 @@ namespace boost
struct entry_manager
{
entry_ptr const entry;
entry_ptr entry;
boost::mutex& internal_mutex;
BOOST_THREAD_NO_COPYABLE(entry_manager)
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
entry_manager(entry_ptr&& entry_, boost::mutex& mutex_):
entry(static_cast< entry_ptr&& >(entry_)), internal_mutex(mutex_)
{}
#else
entry_manager(entry_ptr const& entry_, boost::mutex& mutex_):
entry(entry_), internal_mutex(mutex_)
{}
#endif
~entry_manager()
void remove_waiter_and_reset()
{
if (entry) {
boost::lock_guard<boost::mutex> internal_lock(internal_mutex);
entry->remove_waiter();
entry.reset();
}
}
~entry_manager() BOOST_NOEXCEPT_IF(false)
{
remove_waiter_and_reset();
}
list_entry* operator->()
@@ -215,23 +235,24 @@ namespace boost
template<typename lock_type>
bool do_wait(lock_type& lock,timeout abs_time)
{
relocker<lock_type> locker(lock);
relocker<lock_type> locker(lock);
entry_manager entry(get_wait_entry(), internal_mutex);
locker.unlock();
entry_manager entry(get_wait_entry(), internal_mutex);
bool woken=false;
while(!woken)
{
if(!entry->wait(abs_time))
{
return false;
}
locker.unlock();
bool woken=false;
while(!woken)
{
if(!entry->wait(abs_time))
{
return false;
}
woken=entry->woken();
}
return woken;
woken=entry->woken();
}
// do it here to avoid throwing on the destructor
entry.remove_waiter_and_reset();
locker.lock();
return woken;
}
template<typename lock_type,typename predicate_type>

View File

@@ -5,6 +5,7 @@
//
// (C) Copyright 2005-8 Anthony Williams
// (C) Copyright 2012 Vicente J. Botet Escriba
// (C) Copyright 2017 Andrey Semashev
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
@@ -15,36 +16,172 @@
#include <boost/config/abi_prefix.hpp>
#ifdef BOOST_MSVC
// Define compiler barriers
#if defined(__INTEL_COMPILER)
#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() __memory_barrier()
#elif defined(_MSC_VER) && !defined(_WIN32_WCE)
extern "C" void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#define BOOST_THREAD_DETAIL_COMPILER_BARRIER() _ReadWriteBarrier()
#endif
#ifndef BOOST_THREAD_DETAIL_COMPILER_BARRIER
#define BOOST_THREAD_DETAIL_COMPILER_BARRIER()
#endif
#if defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))
// Since VS2005 and until VS2012 volatile reads always acquire and volatile writes are always release.
// But VS2012 adds a compiler switch that can change behavior to the standard. On x86 though
// the compiler generates a single instruction for the load/store, which is enough synchronization
// as far as uarch is concerned. To prevent compiler reordering code around the load/store we add
// compiler barriers.
namespace boost
{
namespace detail
{
// Since VS2005 volatile reads always acquire
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
long const res=*x;
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
return res;
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
void* const res=*x;
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
return res;
}
// Since VS2005 volatile writes always release
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
*x=value;
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
*x=value;
}
}
}
#elif defined(_MSC_VER) && _MSC_VER >= 1700 && (defined(_M_ARM) || defined(_M_ARM64))
#include <intrin.h>
namespace boost
{
namespace detail
{
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
long const res=__iso_volatile_load32((const volatile __int32*)x);
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
__dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
return res;
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
void* const res=
#if defined(_M_ARM64)
__iso_volatile_load64((const volatile __int64*)x);
#else
__iso_volatile_load32((const volatile __int32*)x);
#endif
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
__dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
return res;
}
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
__dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
__iso_volatile_store32((volatile __int32*)x, (__int32)value);
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
__dmb(0xB); // _ARM_BARRIER_ISH, see armintr.h from MSVC 11 and later
BOOST_THREAD_DETAIL_COMPILER_BARRIER();
#if defined(_M_ARM64)
__iso_volatile_store64((volatile __int64*)x, (__int64)value);
#else
__iso_volatile_store32((volatile __int32*)x, (__int32)value);
#endif
}
}
}
#elif defined(__GNUC__) && (((__GNUC__ * 100 + __GNUC_MINOR__) >= 407) || (defined(__clang__) && (__clang_major__ * 100 + __clang_minor__) >= 302))
namespace boost
{
namespace detail
{
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
return __atomic_load_n((long*)x, __ATOMIC_ACQUIRE);
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
return __atomic_load_n((void**)x, __ATOMIC_ACQUIRE);
}
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
__atomic_store_n((long*)x, value, __ATOMIC_RELEASE);
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
__atomic_store_n((void**)x, value, __ATOMIC_RELEASE);
}
}
}
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
namespace boost
{
namespace detail
{
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
long res;
__asm__ __volatile__ ("movl %1, %0" : "=r" (res) : "m" (*x) : "memory");
return res;
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
void* res;
#if defined(__x86_64__)
__asm__ __volatile__ ("movq %1, %0" : "=r" (res) : "m" (*x) : "memory");
#else
__asm__ __volatile__ ("movl %1, %0" : "=r" (res) : "m" (*x) : "memory");
#endif
return res;
}
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
__asm__ __volatile__ ("movl %1, %0" : "=m" (*x) : "r" (value) : "memory");
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
#if defined(__x86_64__)
__asm__ __volatile__ ("movq %1, %0" : "=m" (*x) : "r" (value) : "memory");
#else
__asm__ __volatile__ ("movl %1, %0" : "=m" (*x) : "r" (value) : "memory");
#endif
}
}
}
#else
namespace boost
@@ -53,19 +190,19 @@ namespace boost
{
inline long interlocked_read_acquire(long volatile* x) BOOST_NOEXCEPT
{
return BOOST_INTERLOCKED_COMPARE_EXCHANGE(x,0,0);
return BOOST_INTERLOCKED_COMPARE_EXCHANGE((long*)x,0,0);
}
inline void* interlocked_read_acquire(void* volatile* x) BOOST_NOEXCEPT
{
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER(x,0,0);
return BOOST_INTERLOCKED_COMPARE_EXCHANGE_POINTER((void**)x,0,0);
}
inline void interlocked_write_release(long volatile* x,long value) BOOST_NOEXCEPT
{
BOOST_INTERLOCKED_EXCHANGE(x,value);
BOOST_INTERLOCKED_EXCHANGE((long*)x,value);
}
inline void interlocked_write_release(void* volatile* x,void* value) BOOST_NOEXCEPT
{
BOOST_INTERLOCKED_EXCHANGE_POINTER(x,value);
BOOST_INTERLOCKED_EXCHANGE_POINTER((void**)x,value);
}
}
}

View File

@@ -18,6 +18,7 @@
#include <boost/detail/interlocked.hpp>
#include <boost/detail/winapi/config.hpp>
//#include <boost/detail/winapi/synchronization.hpp>
#include <boost/thread/win32/interlocked_read.hpp>
#include <algorithm>
#if BOOST_PLAT_WINDOWS_RUNTIME
@@ -244,19 +245,19 @@ namespace boost
// Borrowed from https://stackoverflow.com/questions/8211820/userland-interrupt-timer-access-such-as-via-kequeryinterrupttime-or-similar
inline ticks_type __stdcall GetTickCount64emulation()
{
static volatile long count = 0xFFFFFFFF;
static long count = -1l;
unsigned long previous_count, current_tick32, previous_count_zone, current_tick32_zone;
ticks_type current_tick64;
previous_count = (unsigned long) _InterlockedCompareExchange(&count, 0, 0);
previous_count = (unsigned long) boost::detail::interlocked_read_acquire(&count);
current_tick32 = GetTickCount();
if(previous_count == 0xFFFFFFFF)
if(previous_count == (unsigned long)-1l)
{
// count has never been written
unsigned long initial_count;
initial_count = current_tick32 >> 28;
previous_count = (unsigned long) _InterlockedCompareExchange(&count, initial_count, 0xFFFFFFFF);
previous_count = (unsigned long) _InterlockedCompareExchange(&count, (long)initial_count, -1l);
current_tick64 = initial_count;
current_tick64 <<= 28;
@@ -279,8 +280,9 @@ namespace boost
if(current_tick32_zone == previous_count_zone + 1 || (current_tick32_zone == 0 && previous_count_zone == 15))
{
// The top four bits of the 32-bit tick count have been incremented since count was last written.
_InterlockedCompareExchange(&count, previous_count + 1, previous_count);
current_tick64 = previous_count + 1;
unsigned long new_count = previous_count + 1;
_InterlockedCompareExchange(&count, (long)new_count, (long)previous_count);
current_tick64 = new_count;
current_tick64 <<= 28;
current_tick64 += current_tick32 & 0x0FFFFFFF;
return current_tick64;

View File

@@ -459,7 +459,7 @@ namespace boost
void BOOST_THREAD_DECL sleep_until(const timespec& ts)
{
timespec now = boost::detail::timespec_now();
timespec now = boost::detail::timespec_now_realtime();
if (boost::detail::timespec_gt(ts, now))
{
for (int foo=0; foo < 5; ++foo)
@@ -479,7 +479,7 @@ namespace boost
condition_variable cond;
cond.do_wait_until(lock, ts);
# endif
timespec now2 = boost::detail::timespec_now();
timespec now2 = boost::detail::timespec_now_realtime();
if (boost::detail::timespec_ge(now2, ts))
{
return;

View File

@@ -10,7 +10,7 @@
#include <boost/detail/winapi/config.hpp>
#include <boost/thread/detail/config.hpp>
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB)
#if (defined(__MINGW32__) && !defined(_WIN64)) || defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR)
@@ -39,7 +39,7 @@ namespace {
}
}
#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32_MAJOR_VERSION >3) || \
#if defined(__MINGW64__) || (__MINGW64_VERSION_MAJOR) || (__MINGW32__) || (__MINGW32_MAJOR_VERSION >3) || \
((__MINGW32_MAJOR_VERSION==3) && (__MINGW32_MINOR_VERSION>=18))
extern "C"
{
@@ -112,15 +112,9 @@ extern BOOL (WINAPI * const _pDefaultRawDllMainOrig)(HANDLE, DWORD, LPVOID) = NU
//Definitions required by implementation
#if (_MSC_VER < 1300) || (_MSC_VER > 1900) // 1300 == VC++ 7.0, 1900 == VC++ 14.0
typedef void (__cdecl *_PVFV)();
#define INIRETSUCCESS
#define PVAPI void __cdecl
#else
typedef int (__cdecl *_PVFV)();
#define INIRETSUCCESS 0
#define PVAPI int __cdecl
#endif
typedef int (__cdecl *_PVFV)();
#define INIRETSUCCESS 0
#define PVAPI int __cdecl
typedef void (NTAPI* _TLSCB)(HINSTANCE, DWORD, PVOID);

View File

@@ -798,7 +798,9 @@ rule thread-compile ( sources : reqs * : name )
[ thread-run2-noit ../example/synchronized_value.cpp : ex_synchronized_value ]
[ thread-run2-noit ../example/synchronized_person.cpp : ex_synchronized_person ]
[ thread-run2-noit ../example/thread_guard.cpp : ex_thread_guard ]
[ thread-run2-noit ../example/std_thread_guard.cpp : ex_std_thread_guard ]
[ thread-run2-noit ../example/scoped_thread.cpp : ex_scoped_thread ]
[ thread-run2-noit ../example/std_scoped_thread.cpp : ex_std_scoped_thread ]
[ thread-run2-noit ../example/strict_lock.cpp : ex_strict_lock ]
[ thread-run2-noit ../example/ba_externallly_locked.cpp : ex_ba_externallly_locked ]
[ thread-run2 ../example/producer_consumer_bounded.cpp : ex_producer_consumer_bounded ]
@@ -965,7 +967,8 @@ rule thread-compile ( sources : reqs * : name )
#[ thread-run test_11611.cpp ]
#[ thread-run test_11818.cpp ]
#[ thread-run test_11796.cpp ]
[ thread-run test_12293.cpp ]
#[ thread-run test_12293.cpp ]
[ thread-run test_12949.cpp ]
;

View File

@@ -22,6 +22,7 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#if defined BOOST_THREAD_USES_CHRONO
@@ -35,33 +36,39 @@ int runs = 0;
void f()
{
typedef boost::chrono::steady_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
boost::unique_lock<boost::mutex> lk(mut);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
int count=0;
while (test2 == 0 && cv.wait_for(lk, milliseconds(250)) == boost::cv_status::no_timeout)
count++;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < milliseconds(250));
BOOST_TEST(test2 != 0);
try {
typedef boost::chrono::steady_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
boost::unique_lock<boost::mutex> lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
int count=0;
while (test2 == 0 && cv.wait_for(lk, milliseconds(250)) == boost::cv_status::no_timeout)
count++;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
assert(t1 - t0 < milliseconds(250));
assert(test2 != 0);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
assert(t1 - t0 - milliseconds(250) < milliseconds(count*250+5+1000));
assert(test2 == 0);
}
++runs;
} catch(...) {
std::cout << "ERROR exception" << __LINE__ << std::endl;
assert(false);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
BOOST_TEST(t1 - t0 - milliseconds(250) < milliseconds(count*250+5+1000));
BOOST_TEST(test2 == 0);
}
++runs;
}
int main()
{
try
{
boost::unique_lock<boost::mutex> lk(mut);
boost::thread t(f);
@@ -73,9 +80,13 @@ int main()
lk.unlock();
cv.notify_one();
t.join();
} catch(...) {
std::cout << "ERROR exception" << __LINE__ << std::endl;
BOOST_TEST(false);
}
test1 = 0;
test2 = 0;
try
{
boost::unique_lock<boost::mutex> lk(mut);
boost::thread t(f);
@@ -85,8 +96,10 @@ int main()
BOOST_TEST(test1 != 0);
lk.unlock();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
return boost::report_errors();
}
#else

View File

@@ -21,6 +21,8 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#include <iostream>
#if defined BOOST_THREAD_USES_CHRONO
@@ -49,34 +51,40 @@ int runs = 0;
void f()
{
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
boost::unique_lock < boost::mutex > lk(mut);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
int count=0;
//bool r =
(void)cv.wait_for(lk, milliseconds(250), Pred(test2));
count++;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
// This test is spurious as it depends on the time the thread system switches the threads
BOOST_TEST(t1 - t0 < milliseconds(250+1000));
BOOST_TEST(test2 != 0);
try {
typedef boost::chrono::system_clock Clock;
typedef boost::chrono::milliseconds milliseconds;
boost::unique_lock < boost::mutex > lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
int count=0;
//bool r =
(void)cv.wait_for(lk, milliseconds(250), Pred(test2));
count++;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
// This test is spurious as it depends on the time the thread system switches the threads
assert(t1 - t0 < milliseconds(250+1000));
assert(test2 != 0);
}
else
{
assert(t1 - t0 - milliseconds(250) < milliseconds(count*250+2));
assert(test2 == 0);
}
++runs;
} catch(...) {
std::cout << "ERROR exception" << __LINE__ << std::endl;
assert(false);
}
else
{
BOOST_TEST(t1 - t0 - milliseconds(250) < milliseconds(count*250+2));
BOOST_TEST(test2 == 0);
}
++runs;
}
int main()
{
try
{
boost::unique_lock < boost::mutex > lk(mut);
boost::thread t(f);
@@ -88,9 +96,13 @@ int main()
lk.unlock();
cv.notify_one();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
test1 = 0;
test2 = 0;
try
{
boost::unique_lock < boost::mutex > lk(mut);
boost::thread t(f);
@@ -100,6 +112,9 @@ int main()
BOOST_TEST(test1 != 0);
lk.unlock();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
return boost::report_errors();

View File

@@ -17,11 +17,13 @@
// void wait(unique_lock<mutex>& lock);
#include <iostream>
#include <boost/thread/condition_variable.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#include <iostream>
#if defined BOOST_THREAD_USES_CHRONO
@@ -35,31 +37,40 @@ int runs = 0;
void f()
{
boost::unique_lock<boost::mutex> lk(mut);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
while (test2 == 0) {
cv.wait(lk);
try {
boost::unique_lock<boost::mutex> lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
while (test2 == 0) {
cv.wait(lk);
}
assert(test2 != 0);
} catch(...) {
std::cout << "ERROR exception" << __LINE__ << std::endl;
assert(false);
}
BOOST_TEST(test2 != 0);
}
int main()
{
boost::unique_lock<boost::mutex>lk(mut);
boost::thread t(f);
BOOST_TEST(test1 == 0);
while (test1 == 0)
{
cv.wait(lk);
try {
boost::unique_lock<boost::mutex>lk(mut);
boost::thread t(f);
BOOST_TEST(test1 == 0);
while (test1 == 0)
{
cv.wait(lk);
}
BOOST_TEST(test1 != 0);
test2 = 1;
lk.unlock();
cv.notify_one();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
BOOST_TEST(test1 != 0);
test2 = 1;
lk.unlock();
cv.notify_one();
t.join();
return boost::report_errors();
}
#else

View File

@@ -21,6 +21,8 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <iostream>
#include <cassert>
#if defined BOOST_THREAD_USES_CHRONO
@@ -49,32 +51,38 @@ int runs = 0;
void f()
{
boost::unique_lock < boost::mutex > lk(mut);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
int count=0;
while (test2 == 0 && cv.wait_until(lk, t) == boost::cv_status::no_timeout)
count++;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < Clock::duration(250));
BOOST_TEST(test2 != 0);
try {
boost::unique_lock < boost::mutex > lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
int count=0;
while (test2 == 0 && cv.wait_until(lk, t) == boost::cv_status::no_timeout)
count++;
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
assert(t1 - t0 < Clock::duration(250));
assert(test2 != 0);
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
assert(t1 - t0 - Clock::duration(250) < Clock::duration(count*250+5+1000));
assert(test2 == 0);
}
++runs;
} catch(...) {
assert(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
else
{
// This test is spurious as it depends on the time the thread system switches the threads
BOOST_TEST(t1 - t0 - Clock::duration(250) < Clock::duration(count*250+5+1000));
BOOST_TEST(test2 == 0);
}
++runs;
}
int main()
{
try
{
boost::unique_lock < boost::mutex > lk(mut);
boost::thread t(f);
@@ -86,9 +94,14 @@ int main()
lk.unlock();
cv.notify_one();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
test1 = 0;
test2 = 0;
try
{
boost::unique_lock < boost::mutex > lk(mut);
boost::thread t(f);
@@ -98,6 +111,9 @@ int main()
BOOST_TEST(test1 != 0);
lk.unlock();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
return boost::report_errors();

View File

@@ -21,6 +21,8 @@
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <cassert>
#include <iostream>
#if defined BOOST_THREAD_USES_CHRONO
@@ -64,31 +66,37 @@ int runs = 0;
void f()
{
boost::unique_lock<boost::mutex> lk(mut);
BOOST_TEST(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
bool r = cv.wait_until(lk, t, Pred(test2));
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
BOOST_TEST(t1 - t0 < Clock::duration(250));
BOOST_TEST(test2 != 0);
BOOST_TEST(r);
try {
boost::unique_lock<boost::mutex> lk(mut);
assert(test2 == 0);
test1 = 1;
cv.notify_one();
Clock::time_point t0 = Clock::now();
Clock::time_point t = t0 + Clock::duration(250);
bool r = cv.wait_until(lk, t, Pred(test2));
Clock::time_point t1 = Clock::now();
if (runs == 0)
{
assert(t1 - t0 < Clock::duration(250));
assert(test2 != 0);
assert(r);
}
else
{
assert(t1 - t0 - Clock::duration(250) < Clock::duration(250+2));
assert(test2 == 0);
assert(!r);
}
++runs;
} catch(...) {
std::cout << "ERROR exception" << __LINE__ << std::endl;
assert(false);
}
else
{
BOOST_TEST(t1 - t0 - Clock::duration(250) < Clock::duration(250+2));
BOOST_TEST(test2 == 0);
BOOST_TEST(!r);
}
++runs;
}
int main()
{
try
{
boost::unique_lock<boost::mutex> lk(mut);
boost::thread t(f);
@@ -100,9 +108,13 @@ int main()
lk.unlock();
cv.notify_one();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
test1 = 0;
test2 = 0;
try
{
boost::unique_lock<boost::mutex> lk(mut);
boost::thread t(f);
@@ -112,6 +124,9 @@ int main()
BOOST_TEST(test1 != 0);
lk.unlock();
t.join();
} catch(...) {
BOOST_TEST(false);
std::cout << "ERROR exception" << __LINE__ << std::endl;
}
return boost::report_errors();

View File

@@ -89,12 +89,15 @@ int main()
}
{
// empty queue push rvalue succeeds
boost::sync_bounded_queue<int> q(2);
boost::sync_bounded_queue<int> q(3);
q.push(1);
BOOST_TEST_EQ(q.size(), 1u);
q.push(2);
BOOST_TEST_EQ(q.size(), 2u);
q.push(2);
BOOST_TEST_EQ(q.size(), 3u);
BOOST_TEST(! q.empty());
BOOST_TEST( q.full());
BOOST_TEST_EQ(q.size(), 2u);
BOOST_TEST(! q.closed());
}
{
@@ -317,12 +320,15 @@ int main()
}
{
// empty queue push rvalue succeeds
boost::sync_bounded_queue<int> q(2);
boost::sync_bounded_queue<int> q(3);
q.push_back(1);
BOOST_TEST_EQ(q.size(), 1u);
q.push_back(2);
BOOST_TEST_EQ(q.size(), 2u);
q.push_back(3);
BOOST_TEST_EQ(q.size(), 3u);
BOOST_TEST(! q.empty());
BOOST_TEST( q.full());
BOOST_TEST_EQ(q.size(), 2u);
BOOST_TEST(! q.closed());
}
{

View File

@@ -3,46 +3,64 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_VERSION 4
#include <iostream>
//#include <thread>
#define BOOST_THREAD_PROVIDES_FUTURE
#define BOOST_THREAD_PROVIDES_EXECUTORS
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#if __cplusplus >= 201103L
#include <boost/thread/executors/loop_executor.hpp>
#include <boost/thread/executors/serial_executor_cont.hpp>
#include <boost/thread/executors/serial_executor.hpp>
#endif
#include <boost/thread/thread.hpp>
#include <boost/atomic.hpp>
using namespace std;
int main()
{
#if __cplusplus >= 201103L
static std::size_t const nWorks = 100000;
boost::atomic<unsigned> execCount(0u);
boost::loop_executor ex;
//thread t([&ex]()
boost::thread t([&ex]()
{
ex.loop();
});
{
//boost::serial_executor_cont serial(ex);
boost::serial_executor serial(ex);
for (size_t i = 0; i < 100000; i++)
serial.submit([i] {
for (size_t i = 0; i < nWorks; i++)
serial.submit([i, &execCount] {
//std::cout << i << ".";
++execCount;
});
serial.close();
}
unsigned const cnt = execCount.load();
if (cnt != nWorks) {
// Since the serial_executor is closed, all work should have been done,
// even though the loop_executor ex is not.
std::cerr << "Only " << cnt << " of " << nWorks << " works executed!\n";
return 1;
}
if (ex.try_executing_one()) {
std::cerr
<< "loop_executor::try_executing_one suceeded on closed executor!\n";
return 1;
}
ex.close();
t.join();
std::cout << "end" << std::endl;
std::cout << "end\n" << std::endl;
#endif
return 0;
}

View File

@@ -20,6 +20,8 @@
int main()
{
#if __cplusplus >= 201103L
int value = 0;
int tmpValue = 0;
boost::promise<void> promise1;
@@ -56,6 +58,7 @@ int main()
waitFuture.wait();
std::cout << "value = " << value << std::endl; // should print 1 but prints 0
#endif
return 0;
}

21
test/test_12949.cpp Normal file
View File

@@ -0,0 +1,21 @@
// Copyright (C) 2017 Vicente Botet
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_THREAD_VERSION 4
//#define BOOST_THREAD_HAS_CONDATTR_SET_CLOCK_MONOTONIC
//#include <boost/thread/thread.hpp>
#include <boost/thread/condition_variable.hpp>
void f()
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(10)); // **
}
int main()
{
return 0;
}

View File

@@ -11,6 +11,7 @@
#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/once.hpp>
#include <iostream>
#define LOG \
if (false) {} else std::cout << std::endl << __FILE__ << "[" << __LINE__ << "]"

View File

@@ -12,6 +12,7 @@
#include <boost/thread/xtime.hpp>
#include "./util.inl"
#include "./shared_mutex_locking_thread.hpp"
#include <iostream>
#define CHECK_LOCKED_VALUE_EQUAL(mutex_name,value,expected_value) \
{ \

View File

@@ -26,9 +26,11 @@
unsigned throw_one = 0xFFFF;
#if defined _GLIBCXX_THROW
inline void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
#elif defined BOOST_MSVC
inline void* operator new(std::size_t s)
void* operator new(std::size_t s)
#elif __cplusplus > 201402L
void* operator new(std::size_t s)
#else
void* operator new(std::size_t s) throw (std::bad_alloc)
#endif
@@ -40,9 +42,9 @@ void* operator new(std::size_t s) throw (std::bad_alloc)
}
#if defined BOOST_MSVC
inline void operator delete(void* p)
void operator delete(void* p)
#else
inline void operator delete(void* p) throw ()
void operator delete(void* p) BOOST_NOEXCEPT_OR_NOTHROW
#endif
{
//std::cout << __FILE__ << ":" << __LINE__ << std::endl;

View File

@@ -29,6 +29,8 @@ unsigned throw_one = 0xFFFF;
void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
#elif defined BOOST_MSVC
void* operator new(std::size_t s)
#elif __cplusplus > 201402L
void* operator new(std::size_t s)
#else
void* operator new(std::size_t s) throw (std::bad_alloc)
#endif
@@ -42,7 +44,7 @@ void* operator new(std::size_t s) throw (std::bad_alloc)
#if defined BOOST_MSVC
void operator delete(void* p)
#else
void operator delete(void* p) throw ()
void operator delete(void* p) BOOST_NOEXCEPT_OR_NOTHROW
#endif
{
//std::cout << __FILE__ << ":" << __LINE__ << std::endl;

View File

@@ -28,9 +28,11 @@
unsigned throw_one = 0xFFFF;
#if defined _GLIBCXX_THROW
inline void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
void* operator new(std::size_t s) _GLIBCXX_THROW (std::bad_alloc)
#elif defined BOOST_MSVC
inline void* operator new(std::size_t s)
void* operator new(std::size_t s)
#elif __cplusplus > 201402L
void* operator new(std::size_t s)
#else
void* operator new(std::size_t s) throw (std::bad_alloc)
#endif
@@ -41,9 +43,9 @@ void* operator new(std::size_t s) throw (std::bad_alloc)
}
#if defined BOOST_MSVC
inline void operator delete(void* p)
void operator delete(void* p)
#else
inline void operator delete(void* p) throw ()
void operator delete(void* p) BOOST_NOEXCEPT_OR_NOTHROW
#endif
{
std::free(p);