Skip to content

Commit

Permalink
Thread: Added BOOST_THREAD_DONT_PROVIDE_THREAD_EQ, BOOST_THREAD_DONT_…
Browse files Browse the repository at this point in the history
…USE_DATETIME and forbid their use when defined + Added BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION and future<>::then + Go towards don't throwing from the cpp files (refactor start_thread, join + Added #define BOOST_THREAD_VERSION 2 for the tests that runs only with version 2

[SVN r81023]
  • Loading branch information
viboes committed Oct 20, 2012
1 parent bd69c93 commit a3098b5
Show file tree
Hide file tree
Showing 25 changed files with 507 additions and 133 deletions.
13 changes: 10 additions & 3 deletions doc/changes.qbk
Expand Up @@ -73,11 +73,12 @@ Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/2797 #2797] Two problems with thread_specific_ptr.
* [@http://svn.boost.org/trac/boost/ticket/5274 #5274] failed to compile future.hpp with stlport 5.1.5 under msvc8.1, because of undefined class.
* [@http://svn.boost.org/trac/boost/ticket/5431 #5431] compile error in Windows CE 6.0(interlocked).
* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms.
[/* [@http://svn.boost.org/trac/boost/ticket/5696 #5696] win32 detail::set_tss_data does nothing when tss_cleanup_function is NULL].
[/* [@http://svn.boost.org/trac/boost/ticket/5752 #5752] boost::call_once() is unreliable on some platforms.]
* [@http://svn.boost.org/trac/boost/ticket/5696 #5696] win32 detail::set_tss_data does nothing when tss_cleanup_function is NULL.
* [@http://svn.boost.org/trac/boost/ticket/6931 #6931] mutex waits forwever with Intel C++ Compiler XE 12.1.5.344 Build 20120612
* [@http://svn.boost.org/trac/boost/ticket/7045 #7045] Thread library does not automatically compile date_time.
* [@http://svn.boost.org/trac/boost/ticket/7173 #7173] wrong function name interrupt_point().
* [@http://svn.boost.org/trac/boost/ticket/7200 #7200] Unable to build boost.thread modularized.
* [@http://svn.boost.org/trac/boost/ticket/7200 #7200] Unable to build boost.thread modularized.
* [@http://svn.boost.org/trac/boost/ticket/7220 #7220] gcc 4.6.2 warns about inline+dllimport functions.
* [@http://svn.boost.org/trac/boost/ticket/7238 #7238] this_thread::sleep_for() does not respond to interrupt().
* [@http://svn.boost.org/trac/boost/ticket/7245 #7245] Minor typos on documentation related to version 3.
Expand All @@ -87,6 +88,12 @@ Fixed Bugs:
* [@http://svn.boost.org/trac/boost/ticket/7336 #7336] BOOST_THREAD_DONT_USE_SYSTEM doesn't work.
* [@http://svn.boost.org/trac/boost/ticket/7329 #7349] packaged_task holds reference to temporary.
* [@http://svn.boost.org/trac/boost/ticket/7350 #7350] allocator_destructor does not destroy object
* [@http://svn.boost.org/trac/boost/ticket/7360 #7360] Memory leak in pthread implementation of boost::thread_specific_ptr
* [@http://svn.boost.org/trac/boost/ticket/7370 #7370] Boost.Thread documentation
* [@http://svn.boost.org/trac/boost/ticket/7438 #7438] Segmentation fault in test_once regression test in group.join_all();
* [@http://svn.boost.org/trac/boost/ticket/7461 #7461] detail::win32::ReleaseSemaphore may be called with count_to_release equal to 0
* [@http://svn.boost.org/trac/boost/ticket/7499 #7499] call_once doesn't call even once


[heading Version 3.0.1 - boost 1.51]

Expand Down
65 changes: 64 additions & 1 deletion doc/future_ref.qbk
Expand Up @@ -261,7 +261,16 @@ The object's `name` virtual function returns a pointer to the string "future".]]
__unique_future__(__unique_future__ && other) noexcept;
__unique_future__& operator=(__unique_future__ && other) noexcept;
shared_future<R> share();

template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(S& scheduler, F&& func); // EXTENSION NOT_YET_IMPLEMENTED
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(launch policy, F&& func); // EXTENSION NOT_YET_IMPLEMENTED

void swap(__unique_future__& other) noexcept; // EXTENSION

// retrieving the value
Expand Down Expand Up @@ -628,6 +637,60 @@ associated with `*this` is ready for retrieval, __waiting__ otherwise.]]

[endsect]

[section:then Member function `then()`]

template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(F&& func); // EXTENSION
template<typename S, typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(S& scheduler, F&& func); // EXTENSION
template<typename F>
__unique_future__<typename boost::result_of<F(__unique_future__&)>::type>
then(launch policy, F&& func); // EXTENSION

[variablelist

[[Notes:] [The three functions differ only by input parameters. The first only takes a callable object which accepts a
future object as a parameter. The second function takes a scheduler as the first parameter and a callable object as
the second parameter. The third function takes a launch policy as the first parameter and a callable object as the
second parameter.]]

[[Effects:] [

- The continuation is called when the object's shared state is ready (has a value or exception stored).

- The continuation launches according to the specified policy or scheduler.

- When the scheduler or launch policy is not provided the continuation inherits the
parent's launch policy or scheduler.

- If the parent was created with std::promise or with a packaged_task (has no associated launch policy), the
continuation behaves the same as the third overload with a policy argument of launch::async | launch::deferred and
the same argument for func.

- If the parent has a policy of launch::deferred and the continuation does not have a specified launch policy or
scheduler, then the parent is filled by immediately calling .wait(), and the policy of the antecedent is
launch::deferred

]]

[[Returns:] [An object of type future<decltype(func(*this))> that refers to the shared state created by the continuation.]]

[[Postconditions:] [

- The future object is moved to the parameter of the continuation function .

- valid() == false on original future object immediately after it returns.

]]

]

[endsect]




[endsect]

Expand Down
59 changes: 59 additions & 0 deletions doc/futures.qbk
Expand Up @@ -220,6 +220,65 @@ make_shared_future has the same functionality as make_future, except has a retur

[endsect]

[section:then Associating future continuations]

In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second
operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future.
With .then, instead of waiting for the result, a continuation is "attached" to the asynchronous operation, which is
invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits
or wasting threads on polling, greatly improving the responsiveness and scalability of an application.

future.then provides the ability to sequentially compose two futures by declaring one to be the continuation of another.
With .then the antecedent future is ready (has a value or exception stored in the shared state) before the continuation
starts as instructed by the lambda function.

In the example below the future<int> f2 is registered to be a continuation of future<int> f1 using the .then member
function. This operation takes a lambda function which describes how f2 should proceed after f1 is ready.


#include <boost/thread/future.hpp>
using namespace boost;
int main()
{
future<int> f1 = async([]() { return 123; });
future<string> f2 = f1.then([](future<int> f) { return f.get().to_string(); // here .get() won't block });
}

One key feature of this function is the ability to chain multiple asynchronous operations. In asynchronous programming,
it's common to define a sequence of operations, in which each continuation executes only when the previous one completes.
In some cases, the antecedent future produces a value that the continuation accepts as input. By using future.then,
creating a chain of continuations becomes straightforward and intuitive:

myFuture.then(...).then(...).then(...).

Some points to note are:

* Each continuation will not begin until the preceding has completed.
* If an exception is thrown, the following continuation can handle it in a try-catch block


Input Parameters:

* Lambda function2: One option which was considered was to follow JavaScript's approach and take two functions, one for
success and one for error handling. However this option is not viable in C++ as there is no single base type for
exceptions as there is in JavaScript. 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.
* Scheduler: Providing an overload to .then, to take a scheduler 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 scheduler must outlive the continuation.
* Launch policy: if the additional flexibility that the scheduler provides is not required.


Return values: The decision to return a future was based primarily on the ability to chain multiple continuations using
.then. This benefit of composability gives the programmer incredible control and flexibility over their code. Returning
a future object rather than a shared_future is also a much cheaper operation thereby improving performance. A
shared_future object is not necessary to take advantage of the chaining feature. It is also easy to go from a future
to a shared_future when needed using future::share().


[endsect]


[include future_ref.qbk]

[endsect]
37 changes: 37 additions & 0 deletions example/future_then.cpp
@@ -0,0 +1,37 @@
// Copyright (C) 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)

#define BOOST_THREAD_VERSION 4
#define BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET

#include <boost/thread/future.hpp>
#include <iostream>
#include <string>
#if defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION

int p1()
{
return 123;
}

int p2(boost::future<int>& f)
{
return 2 * f.get();
}

int main()
{
boost::future<int> f1 = boost::async(p1);
boost::future<int> f2 = f1.then(p2);
std::cout << f2.get() << std::endl;
return 0;
}
#else

int main()
{
return 0;
}
#endif
49 changes: 36 additions & 13 deletions include/boost/thread/detail/config.hpp
Expand Up @@ -16,12 +16,15 @@
#include <boost/config.hpp>
#include <boost/detail/workaround.hpp>
#include <boost/thread/detail/platform.hpp>
#include <boost/detail/no_exceptions_support.hpp>

#if ! defined BOOST_THREAD_NOEXCEPT_OR_THROW
#ifdef BOOST_NO_NOEXCEPT
# define BOOST_THREAD_NOEXCEPT_OR_THROW throw()
#else
# define BOOST_THREAD_NOEXCEPT_OR_THROW noexcept
#endif
#endif

// This compiler doesn't support Boost.Chrono
#if defined __IBMCPP__ && (__IBMCPP__ < 1100) && ! defined BOOST_THREAD_DONT_USE_CHRONO
Expand Down Expand Up @@ -69,12 +72,21 @@


#if BOOST_THREAD_VERSION==2
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY && ! defined BOOST_THREAD_PROMISE_LAZY
#if ! defined BOOST_THREAD_DONT_PROVIDE_PROMISE_LAZY \
&& ! defined BOOST_THREAD_PROMISE_LAZY
#define BOOST_THREAD_PROMISE_LAZY
#endif
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0

#if ! defined BOOST_THREAD_DONT_PROVIDE_THREAD_EQ \
&& ! defined BOOST_THREAD_PROVIDES_THREAD_EQ
#define BOOST_THREAD_PROVIDES_THREAD_EQ
#endif

#if ! defined BOOST_THREAD_DONT_USE_DATETIME \
&& ! defined BOOST_THREAD_USES_DATETIME
#define BOOST_THREAD_USES_DATETIME
#endif

#endif

#if BOOST_THREAD_VERSION>=3
Expand Down Expand Up @@ -110,10 +122,6 @@
&& ! defined BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#define BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN
#endif
#if ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 \
&& ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_
#define BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0
#endif
#if ! defined BOOST_THREAD_DONT_USE_MOVE \
&& ! defined BOOST_THREAD_USES_MOVE
#define BOOST_THREAD_USES_MOVE
Expand All @@ -136,19 +144,27 @@
! defined(BOOST_NO_CXX11_DECLTYPE) && \
! defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
! defined(BOOST_NO_CXX11_HDR_TUPLE)
#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD
#endif
#endif

#if ! defined BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_CONTINUATION

#define BOOST_THREAD_PROVIDES_VARIADIC_THREAD
#if ! defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
#define BOOST_THREAD_PROVIDES_FUTURE_CONTINUATION
#endif
#endif

#if ! defined BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET \
&& ! defined BOOST_THREAD_DONT_PROVIDE_FUTURE_INVALID_AFTER_GET
#define BOOST_THREAD_PROVIDES_FUTURE_INVALID_AFTER_GET
#endif

#endif // BOOST_THREAD_VERSION>=4

#endif
#endif

// CORRELATIONS

// BOOST_THREAD_PROVIDES_GENERIC_SHARED_MUTEX_ON_WIN is defined if BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS
#if defined BOOST_THREAD_PROVIDES_SHARED_MUTEX_UPWARDS_CONVERSIONS \
Expand All @@ -158,9 +174,16 @@

// BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.52
// BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 defined by default up to Boost 1.55
#if ! defined BOOST_THREAD_DONT_PROVIDE_DEPRECATED_FEATURES_SINCE_V3_0_0 \
&& ! defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
#define BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0
#if defined BOOST_THREAD_PROVIDES_DEPRECATED_FEATURES_SINCE_V3_0_0

#if ! defined BOOST_THREAD_PROVIDES_THREAD_EQ
#define BOOST_THREAD_PROVIDES_THREAD_EQ
#endif

#if ! defined BOOST_THREAD_USES_DATETIME
#define defined BOOST_THREAD_USES_DATETIME
#endif

#endif

#if BOOST_WORKAROUND(__BORLANDC__, < 0x600)
Expand Down

0 comments on commit a3098b5

Please sign in to comment.