Skip to content

Commit

Permalink
Fixed #795: Create timed make_ready_future, adding example demonstrat…
Browse files Browse the repository at this point in the history
…ing new facilities
  • Loading branch information
hkaiser committed Aug 5, 2013
1 parent f551a2e commit d5ba0ae
Show file tree
Hide file tree
Showing 5 changed files with 268 additions and 20 deletions.
2 changes: 2 additions & 0 deletions examples/quickstart/CMakeLists.txt
Expand Up @@ -25,6 +25,7 @@ set(example_programs
print_to_console
quicksort
simplest_hello_world
timed_futures
timed_wake
use_main_thread
wait_composition
Expand Down Expand Up @@ -69,6 +70,7 @@ set(simplest_hello_world_FLAGS DEPENDENCIES iostreams_component)
set(component_inheritance_FLAGS DEPENDENCIES iostreams_component)
set(component_inheritance_simple_FLAGS DEPENDENCIES iostreams_component)
set(interest_calculator_FLAGS DEPENDENCIES dataflow_component)
set(timed_futures_FLAGS DEPENDENCIES iostreams_component)

foreach(example_program ${example_programs})
set(sources
Expand Down
74 changes: 74 additions & 0 deletions examples/quickstart/timed_futures.cpp
@@ -0,0 +1,74 @@
// Copyright (c) 2013 Hartmut Kaiser
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// This example demonstrates the use of the utility function
// make_ready_future_after to orchestrate timed operations with 'normal'
// asynchronous work.

#include <hpx/hpx_init.hpp>
#include <hpx/include/iostreams.hpp>
#include <hpx/util/high_resolution_timer.hpp>

#include <boost/date_time/posix_time/posix_time.hpp>

///////////////////////////////////////////////////////////////////////////////
void wake_up_after_2_seconds()
{
hpx::cout << "waiting for 2 seconds\n";

hpx::util::high_resolution_timer t;

// Schedule a wakeup after 2 seconds.
using boost::posix_time::seconds;
hpx::future<void> f = hpx::make_ready_future_after(seconds(2));

// ... do other things while waiting for the future to get ready

// wait until the new future gets ready
f.wait();

hpx::cout << "woke up after " << t.elapsed()
<< " seconds\n" << hpx::flush;
}

int return_int_at_time()
{
hpx::cout << "generating an 'int' value 2 seconds from now\n";

hpx::util::high_resolution_timer t;

// Schedule a wakeup 2 seconds from now.
using namespace boost::posix_time;
int arg = 42;
hpx::future<int> f = hpx::make_ready_future_at(
microsec_clock::universal_time() + seconds(2), 42);

// ... do other things while waiting for the future to get ready

// wait until the new future gets ready (should return 42)
int retval = f.get();

hpx::cout << "woke up after " << t.elapsed()
<< " seconds, returned: " << retval << "\n"
<< hpx::flush;

return retval;
}

///////////////////////////////////////////////////////////////////////////////
int hpx_main()
{
wake_up_after_2_seconds();
return_int_at_time();
return hpx::finalize();
}

///////////////////////////////////////////////////////////////////////////////
int main(int argc, char* argv[])
{
// Initialize and run HPX.
return hpx::init(argc, argv);
}

8 changes: 0 additions & 8 deletions hpx/hpx_fwd.hpp
Expand Up @@ -606,13 +606,6 @@ namespace hpx
template <typename Result>
class future;

template <typename Result>
future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type> make_ready_future(BOOST_FWD_REF(Result));

future<void> make_ready_future();

template <typename ValueType>
struct object_semaphore;

Expand Down Expand Up @@ -686,7 +679,6 @@ namespace hpx
// Pulling important types into the main namespace
using naming::id_type;
using lcos::future;
using lcos::make_ready_future;
using lcos::promise;

/// \endcond
Expand Down
64 changes: 64 additions & 0 deletions hpx/lcos/detail/future_data.hpp
Expand Up @@ -530,6 +530,70 @@ namespace detail
completed_callback_type on_completed_;
};

///////////////////////////////////////////////////////////////////////////
template <typename Result>
struct timed_future_data : future_data<Result>
{
public:
typedef future_data<Result> base_type;
typedef typename base_type::result_type result_type;
typedef typename base_type::mutex_type mutex_type;
typedef typename base_type::error_type error_type;
typedef typename base_type::data_type data_type;

template <typename T>
friend class lcos::future;

private:
void set_data(result_type const& value)
{
this->base_type::set_data(value);
}

template <typename TimeSpec, typename Result_>
void at_time(TimeSpec const& tpoint, BOOST_FWD_REF(Result_) init)
{
boost::intrusive_ptr<timed_future_data> this_(this);

error_code ec;
threads::thread_id_type id = threads::register_thread_nullary(
HPX_STD_BIND(&timed_future_data::set_data, this_,
boost::forward<Result_>(init)),
"timed_future_data<Result>::timed_future_data",
threads::suspended, true, threads::thread_priority_normal,
std::size_t(-1), threads::thread_stacksize_default, ec);
if (ec) {
// thread creation failed, report error to the new future
this->base_type::set_exception(hpx::detail::access_exception(ec));
}

// start new thread at given point in time
threads::set_thread_state(id, tpoint, threads::pending,
threads::wait_timeout, threads::thread_priority_critical, ec);
if (ec) {
// thread scheduling failed, report error to the new future
this->base_type::set_exception(hpx::detail::access_exception(ec));
}
}

protected:
timed_future_data() {}

template <typename Result_>
timed_future_data(boost::posix_time::ptime const& at,
BOOST_FWD_REF(Result_) init)
{
at_time(at, boost::forward<Result_>(init));
}

template <typename Result_>
timed_future_data(boost::posix_time::time_duration const& d,
BOOST_RV_REF(Result_) init)
{
at_time(d, boost::forward<Result_>(init));
}
};

///////////////////////////////////////////////////////////////////////////
template <typename Result>
struct task_base : future_data<Result>
Expand Down
140 changes: 128 additions & 12 deletions hpx/lcos/future.hpp
@@ -1,4 +1,4 @@
// Copyright (c) 2007-2012 Hartmut Kaiser
// Copyright (c) 2007-2013 Hartmut Kaiser
//
// 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)
Expand Down Expand Up @@ -96,12 +96,10 @@ namespace hpx { namespace lcos
template <typename Result_>
friend detail::future_data_base<Result_> const*
detail::get_future_data(lcos::future<Result_> const&);


private:
BOOST_COPYABLE_AND_MOVABLE(future)


explicit future(future_data_type* p)
: future_data_(p)
{}
Expand Down Expand Up @@ -143,13 +141,6 @@ namespace hpx { namespace lcos
future_data_.swap(p);
}

// accept wrapped future
future(BOOST_RV_REF(future<future>) other)
{
future f = boost::move(other.unwrap());
(*this).swap(f);
}

explicit future(BOOST_RV_REF(Result) init)
{
typedef lcos::detail::future_data<Result> impl_type;
Expand All @@ -158,6 +149,32 @@ namespace hpx { namespace lcos
future_data_.swap(p);
}

// extension: accept wrapped future
future(BOOST_RV_REF(future<future>) other)
{
future f = boost::move(other.unwrap());
(*this).swap(f);
}

// extension: support timed future creation
future(boost::posix_time::ptime const& at, Result const& init)
: future_data_(new lcos::detail::timed_future_data<Result>(at, init))
{}

future(boost::posix_time::ptime const& at, BOOST_RV_REF(Result) init)
: future_data_(new lcos::detail::timed_future_data<Result>(
at, boost::move(init)))
{}

future(boost::posix_time::time_duration const& d, Result const& init)
: future_data_(new lcos::detail::timed_future_data<Result>(d, init))
{}

future(boost::posix_time::time_duration const& d, BOOST_RV_REF(Result) init)
: future_data_(new lcos::detail::timed_future_data<Result>(
d, boost::move(init)))
{}

// assignment
future& operator=(BOOST_COPY_ASSIGN_REF(future) other)
{
Expand Down Expand Up @@ -266,7 +283,7 @@ namespace hpx { namespace lcos

template <typename Clock, typename Duration>
BOOST_SCOPED_ENUM(future_status)
wait_until(boost::chrono::time_point<Clock, Duration> const& abs_time)
wait_until(boost::chrono::time_point<Clock, Duration> const& abs_time)
{
return wait_until(util::to_ptime(abs_time));
}
Expand Down Expand Up @@ -297,6 +314,7 @@ namespace hpx { namespace lcos
boost::intrusive_ptr<future_data_type> future_data_;
};

///////////////////////////////////////////////////////////////////////////
// extension: create a pre-initialized future object
template <typename Result>
future<typename boost::remove_const<
Expand All @@ -309,6 +327,56 @@ namespace hpx { namespace lcos
>::type>(boost::forward<Result>(init));
}

// extension: create a pre-initialized future object which gets ready at
// a given point in time
template <typename Result>
future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>
make_ready_future_at(boost::posix_time::ptime const& at,
BOOST_FWD_REF(Result) init)
{
return future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>(at, boost::forward<Result>(init));
}

template <typename Clock, typename Duration, typename Result>
future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>
make_ready_future_at(boost::chrono::time_point<Clock, Duration> const& at,
BOOST_FWD_REF(Result) init)
{
return future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>(util::to_ptime(at), boost::forward<Result>(init));
}

template <typename Result>
future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>
make_ready_future_after(boost::posix_time::time_duration const& d,
BOOST_FWD_REF(Result) init)
{
return future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>(d, boost::forward<Result>(init));
}

template <typename Rep, typename Period, typename Result>
future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>
make_ready_future_after(boost::chrono::duration<Rep, Period> const& d,
BOOST_FWD_REF(Result) init)
{
return future<typename boost::remove_const<
typename util::detail::remove_reference<Result>::type
>::type>(util::to_time_duration(d), boost::forward<Result>(init));
}

///////////////////////////////////////////////////////////////////////////
template <>
class future<void>
Expand Down Expand Up @@ -384,13 +452,24 @@ namespace hpx { namespace lcos
future_data_.swap(other.future_data_);
}

// accept wrapped future
// extension: accept wrapped future
future(BOOST_RV_REF(future<future>) other)
{
future f = boost::move(other.unwrap());
(*this).swap(f);
}

// extension: support timed future creation
explicit future(boost::posix_time::ptime const& at)
: future_data_(new lcos::detail::timed_future_data<void>(
at, util::unused))
{}

explicit future(boost::posix_time::time_duration const& d)
: future_data_(new lcos::detail::timed_future_data<void>(
d, util::unused))
{}

future& operator=(BOOST_COPY_ASSIGN_REF(future) other)
{
if (this != &other)
Expand Down Expand Up @@ -515,6 +594,34 @@ namespace hpx { namespace lcos
return future<void>(1); // dummy argument
}

// extension: create a pre-initialized future object which gets ready at
// a given point in time
inline future<void> make_ready_future_at(
boost::posix_time::ptime const& at)
{
return future<void>(at);
}

template <typename Clock, typename Duration>
inline future<void> make_ready_future_at(
boost::chrono::time_point<Clock, Duration> const& at)
{
return future<void>(util::to_ptime(at));
}

inline future<void> make_ready_future_after(
boost::posix_time::time_duration const& d)
{
return future<void>(d);
}

template <typename Rep, typename Period>
inline future<void> make_ready_future_at(
boost::chrono::duration<Rep, Period> const& d)
{
return future<void>(util::to_time_duration(d));
}

///////////////////////////////////////////////////////////////////////////
namespace detail
{
Expand Down Expand Up @@ -662,4 +769,13 @@ namespace hpx { namespace actions
};
}}

///////////////////////////////////////////////////////////////////////////////
// hoist names into main namespace
namespace hpx
{
using lcos::make_ready_future;
using lcos::make_ready_future_at;
using lcos::make_ready_future_after;
}

#endif

0 comments on commit d5ba0ae

Please sign in to comment.