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

Compare commits

..

2 Commits

15 changed files with 372 additions and 514 deletions

View File

@@ -58,15 +58,11 @@ Please take a look at [@http://www.boost.org/development/tests/master/developer/
* [@http://svn.boost.org/trac/boost/ticket/11377 #11377] Boost condition variable always waits for system clock deadline
* [@http://svn.boost.org/trac/boost/ticket/11435 #11435] gcc compiler warning in future.hpp
* [@http://svn.boost.org/trac/boost/ticket/11555 #11555] devector.hpp assumes allocator_traits_type is always present
* [@http://svn.boost.org/trac/boost/ticket/11562 #11562] (condition_variable_any::wait_until + recursive_mutex + steady_clock) timer expires after computer time is set forward on Ubuntu 64-bit
* [@http://svn.boost.org/trac/boost/ticket/11562 #11562] Timer (using steady_clock) expires after computer time is set forward on Ubuntu 64-bit
* [@http://svn.boost.org/trac/boost/ticket/11672 #11672] Thread: Should use unique_ptr, not auto_ptr
* [@http://svn.boost.org/trac/boost/ticket/11688 #11688] thread::try_join_until: Avoid busy wait if system clock changes
* [@http://svn.boost.org/trac/boost/ticket/11672 #11716] ::then(f) should inherit the parent Executor
* [@http://svn.boost.org/trac/boost/ticket/11795 #11795] Incorrect version specification for documentation of thread destructor
* [@http://svn.boost.org/trac/boost/ticket/11796 #11796] Thread move assignment operator, does not detach previous thread data
* [@http://svn.boost.org/trac/boost/ticket/11817 #11817] 'sync_queue_is_closed' was not declared in boost/thread/executors/thread_executor.hpp
* [@http://svn.boost.org/trac/boost/ticket/11818 #11818] future.then will be blocked if promise is set after the invocation of then
[heading Version 4.5.0 - boost 1.58]

View File

@@ -326,7 +326,7 @@ Using a `shared_future` solves the issue
[heading share()]
Naming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists.
Namming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists.
Here `share()` could be used to simplify the code
void better_second_use( type arg ) {
@@ -344,7 +344,7 @@ Here `share()` could be used to simplify the code
[heading Writing on get()]
The user can either read or write the future variable.
The user can either read or write the future avariable.
void write_to_get( type arg ) {
@@ -365,7 +365,7 @@ The user can either read or write the future variable.
This works because the `shared_future<>::get()` function returns a non-const reference to the appropriate storage.
Of course the access to this storage must be ensured by the user. The library doesn't ensure the access to the internal storage is thread safe.
There has been some work by the C++ standard committee on an `atomic_future` that behaves as an `atomic` variable, that is thread_safe,
There has been some work by the C++ standard committe on an `atomic_future` that behaves as an `atomic` variable, that is is thread_safe,
and a `shared_future` that can be shared between several threads, but there were not enough consensus and time to get it ready for C++11.
[endsect]
@@ -444,7 +444,7 @@ Input Parameters:
success and one for error handling. However this option has not been retained for the moment.
The lambda function takes a future as its input which carries the exception
through. This makes propagating exceptions straightforward. This approach also simplifies the chaining of continuations.
* Executor: Providing an overload to `.then`, to take an executor reference places great flexibility over the execution
* Executor: Providing an overload to `.then`, to take a executor reference places great flexibility over the execution
of the future in the programmer's hand. As described above, often taking a launch policy is not sufficient for powerful
asynchronous operations. The lifetime of the executor must outlive the continuation.
* Launch policy: if the additional flexibility that the executor provides is not required.

View File

@@ -110,10 +110,10 @@ where
* `q` denotes a value of type `Q`,
* `e` denotes a value of type Q::value_type,
* `u` denotes a value of type Q::size_type,
* `lve` denotes an lvalue reference of type Q::value_type,
* `rve` denotes an rvalue reference of type Q::value_type:
* `lve` denotes a lvalue referece of type Q::value_type,
* `rve` denotes a rvalue referece of type Q::value_type:
[/* `spe` denotes a shared_ptr<Q::value_type>]
* `qs` denotes a variable of of type `queue_op_status`,
* `qs` denotes a variable of of type `queus_op_status`,
[/////////////////////////////////////]
@@ -246,8 +246,8 @@ where
* `e` denotes a value of type `Q::value_type`,
* `s` denotes a value of type `queue_status`,
* `u` denotes a value of type `Q::size_type`,
* `lve` denotes an lvalue reference of type Q::value_type,
* `rve` denotes an rvalue reference of type Q::value_type:
* `lve` denotes a lvalue referece of type Q::value_type,
* `rve` denotes a rvalue referece of type Q::value_type:
[/* `spe` denotes a shared_ptr<Q::value_type>]
@@ -357,8 +357,8 @@ where
* `q` denotes a value of type `Q`,
* `e` denotes a value of type Q::value_type,
* `s` denotes a value of type `queue_status`,
* `lve` denotes an lvalue reference of type Q::value_type,
* `rve` denotes an rvalue reference of type Q::value_type:
* `lve` denotes a lvalue referece of type Q::value_type,
* `rve` denotes a rvalue referece of type Q::value_type:
[/* `spe` denotes a shared_ptr<Q::value_type>]
@@ -545,7 +545,7 @@ Closed queues add the following valid expressions
[[Return:] [
- If the queue is closed return `queue_op_status::closed`,
- If the queue is closed retun `queue_op_status::closed`,
- otherwise, return `queue_op_status::success` if no exception is thrown.

View File

@@ -255,7 +255,7 @@ does not complete when the specified time has elapsed or reached respectively.
[endsect]
[section:destructor1 Destructor V1-2]
[section:destructor1 Destructor V1]
When the __thread__ object that represents a thread of execution is destroyed the thread becomes ['detached]. Once a thread is
detached, it will continue executing until the invocation of the function or callable object supplied on construction has completed,
@@ -264,7 +264,7 @@ object. In this case, the __thread__ object ceases to represent the now-detached
[endsect]
[section:destructor2 Destructor V3-X]
[section:destructor2 Destructor V2]
When the __thread__ object that represents a thread of execution is destroyed the program terminates if the thread is __joinable__.
@@ -280,7 +280,7 @@ You can use a thread_joiner to ensure that the thread has been joined at the thr
{
boost::thread t(my_func);
boost::thread_joiner g(t);
// do something else
// do someting else
} // here the thread_joiner destructor will join the thread before it is destroyed.
[endsect]
@@ -410,7 +410,7 @@ Of course all the synchronization facilities provided by Boost.Thread are also a
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::interruption_point()` will be just ignored.
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` will return false for the native threads.
As the single way to interrupt a thread is through a __thread__ instance, `interruption_request()` wiil returns false for the native threads.
[heading `pthread_exit` POSIX limitation]
@@ -964,7 +964,7 @@ predefined __interruption_points__ with interruption enabled .]]
[section:hardware_concurrency Static member function `hardware_concurrency()`]
unsigned hardware_concurrency() noexcept;
unsigned hardware_concurrency() noexecpt;
[variablelist
@@ -979,7 +979,7 @@ or 0 if this information is not available.]]
[section:physical_concurrency Static member function `physical_concurrency()`]
unsigned physical_concurrency() noexcept;
unsigned physical_concurrency() noexecpt;
[variablelist
@@ -1290,7 +1290,7 @@ instances of __thread_id__ `a` and `b` is the same if `a==b`, and different if `
[variablelist
[[Effects:] [Constructs a thread attributes instance with its default values.]]
[[Effects:] [Constructs a thread atrributes instance with its default values.]]
[[Throws:] [Nothing]]
@@ -1532,7 +1532,7 @@ do not throw exceptions. __thread_interrupted__ if the current thread of executi
[variablelist
[[Effects:] [Suspends the current thread until the duration specified
[[Effects:] [Suspends the current thread until the duration specified by
by `rel_time` has elapsed.]]
[[Throws:] [Nothing if operations of chrono::duration<Rep, Period> do not throw exceptions. __thread_interrupted__ if the current thread of execution is interrupted.]]

View File

@@ -41,28 +41,10 @@ int main()
for (int i=0; i< number_of_tests; i++)
try
{
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
{
boost::future<int> inner_future = boost::async(boost::launch::async, &p2);
inner_future.wait();
int ii = inner_future.get();
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
}
#endif
{
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
boost::future<int> inner_future = outer_future.unwrap();
inner_future.wait();
int ii = inner_future.get();
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
}
{
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
boost::future<int> inner_future = outer_future.unwrap();
int ii = inner_future.get();
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
}
boost::future<boost::future<int> > outer_future = boost::async(boost::launch::async, &p2);
boost::future<int> inner_future = outer_future.unwrap();
int ii = inner_future.get();
BOOST_THREAD_LOG << "ii= "<< ii << "" << BOOST_THREAD_END_LOG;
}
catch (std::exception& ex)
{

View File

@@ -99,7 +99,7 @@ namespace boost
result_type
execute(tuple_indices<Indices...>)
{
return detail::invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
return invoke(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
}
};
@@ -136,7 +136,7 @@ namespace boost
result_type
execute(tuple_indices<Indices...>)
{
return detail::invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
return invoke<R>(boost::move(csbl::get<0>(f_)), boost::move(csbl::get<Indices>(f_))...);
}
};
//BOOST_THREAD_DCL_MOVABLE_BEG(X) invoker<Fp> BOOST_THREAD_DCL_MOVABLE_END
@@ -190,7 +190,7 @@ namespace boost
{} \
\
result_type operator()() { \
return detail::invoke(boost::move(fp_) \
return invoke(boost::move(fp_) \
BOOST_PP_REPEAT(n, BOOST_THREAD_MOVE_DCL, ~) \
); \
} \
@@ -315,7 +315,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -381,7 +381,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -442,7 +442,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -498,7 +498,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -549,7 +549,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -595,7 +595,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -636,7 +636,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
, boost::move(v2_)
@@ -672,7 +672,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
, boost::move(v1_)
);
@@ -703,7 +703,7 @@ namespace boost
result_type operator()()
{
return detail::invoke(boost::move(fp_)
return invoke(boost::move(fp_)
, boost::move(v0_)
);
}

View File

@@ -72,7 +72,7 @@ namespace boost
void run2(tuple_indices<Indices...>)
{
detail::invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
invoke(std::move(std::get<0>(fp)), std::move(std::get<Indices>(fp))...);
}
void run()
{
@@ -354,8 +354,6 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_THREAD_MOVE_ASSIGN_CALLS_TERMINATE_IF_JOINABLE
if (joinable()) std::terminate();
#else
detach();
#endif
thread_info=BOOST_THREAD_RV(other).thread_info;
BOOST_THREAD_RV(other).thread_info.reset();

View File

@@ -17,7 +17,6 @@
#include <boost/thread/thread_only.hpp>
#include <boost/thread/scoped_thread.hpp>
#include <boost/thread/csbl/vector.hpp>
#include <boost/thread/concurrent_queues/queue_op_status.hpp>
#include <boost/config/abi_prefix.hpp>

File diff suppressed because it is too large Load Diff

View File

@@ -23,7 +23,6 @@ namespace boost
executor = 4,
#endif
inherit = 8,
sync = 16,
any = async | deferred
}
BOOST_SCOPED_ENUM_DECLARE_END(launch)

View File

@@ -68,14 +68,17 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
pthread_mutex_t* the_mutex = &internal_mutex;
guard.activate(m);
do {
res = pthread_cond_wait(&cond,&internal_mutex);
} while (res == EINTR);
#else
//boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
pthread_mutex_t* the_mutex = m.mutex()->native_handle();
#endif
do {
res = pthread_cond_wait(&cond,the_mutex);
} while (res == EINTR);
#endif
}
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
this_thread::interruption_point();
@@ -96,17 +99,18 @@ namespace boost
boost::throw_exception(condition_error(EPERM, "boost::condition_variable::do_wait_until() failed precondition mutex not owned"));
}
#endif
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
int cond_res;
{
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
thread_cv_detail::lock_on_exit<unique_lock<mutex> > guard;
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,&internal_mutex,&timeout);
#else
//boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
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();
@@ -174,7 +178,7 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
#else
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
#endif
guard.activate(m);
res=pthread_cond_wait(&cond,&internal_mutex);
@@ -401,7 +405,7 @@ namespace boost
#if defined BOOST_THREAD_PROVIDES_INTERRUPTIONS
detail::interruption_checker check_for_interruption(&internal_mutex,&cond);
#else
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
boost::pthread::pthread_mutex_scoped_lock check_for_interruption(&internal_mutex);
#endif
guard.activate(m);
res=pthread_cond_timedwait(&cond,&internal_mutex,&timeout);
@@ -419,6 +423,8 @@ namespace boost
}
return true;
}
};
}

View File

@@ -80,8 +80,8 @@ namespace boost
{
static void tls_destructor(void* data)
{
//boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(data)->shared_from_this();
boost::detail::thread_data_base* thread_info=static_cast<boost::detail::thread_data_base*>(data);
//boost::detail::thread_data_ptr thread_info = static_cast<boost::detail::thread_data_base*>(data)->shared_from_this();
if(thread_info)
{
@@ -110,7 +110,10 @@ namespace boost
thread_info->tss_data.erase(current);
}
}
thread_info->self.reset();
if (thread_info) // fixme: should we test this?
{
thread_info->self.reset();
}
}
}
}

View File

@@ -963,8 +963,6 @@ rule thread-compile ( sources : reqs * : name )
#[ thread-run test_11256.cpp ]
#[ thread-run test_11499.cpp ]
#[ thread-run test_11611.cpp ]
#[ thread-run test_11818.cpp ]
[ thread-run test_11796.cpp ]
;

View File

@@ -1,33 +0,0 @@
// Copyright (C) 2015 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)
#include <boost/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
boost::thread th;
int main()
{
for (auto ti = 0; ti < 1000; ti++)
{
th = boost::thread([ti]()
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
std::cout << ti << std::endl;
});
}
std::string st;
std::cin >> st;
// for (int i = 0; i < 10; ++i) {
// std::cout << "." << i << std::endl;
// boost::this_thread::sleep_for(boost::chrono::milliseconds(100));
// }
th.join();
return 0;
}

View File

@@ -1,64 +0,0 @@
// Copyright (C) 2014 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
#include <boost/config.hpp>
#if ! defined BOOST_NO_CXX11_DECLTYPE
#define BOOST_RESULT_OF_USE_DECLTYPE
#endif
#include <boost/thread/future.hpp>
#include <boost/thread/thread.hpp>
#include <thread>
int main()
{
{
boost::promise<int> promise;
boost::future<int> future = promise.get_future();
boost::future<int> result =
future.then
(
boost::launch::deferred,
[](boost::future<int> && f)
{
std::cout << std::this_thread::get_id() << ": callback" << std::endl;
std::cout << "The value is: " << f.get() << std::endl;
return f.get();
}
);
// We could not reach here.
std::cout << std::this_thread::get_id() << ": function" << std::endl;
promise.set_value(0);
}
{
boost::promise<int> promise;
boost::shared_future<int> future = promise.get_future().share();
boost::future<int> result =
future.then
(
boost::launch::deferred,
[](boost::shared_future<int> && f)
{
std::cout << std::this_thread::get_id() << ": callback" << std::endl;
std::cout << "The value is: " << f.get() << std::endl;
return f.get();
}
);
// We could not reach here.
std::cout << std::this_thread::get_id() << ": function" << std::endl;
promise.set_value(0);
}
return 0;
}