blob: 02d7b1dacba7039a7d2ce047c8b071043c86bd22 [file] [log] [blame]
#ifndef BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
#define BOOST_THREAD_EXPERIMENTAL_PARALLEL_V2_TASK_REGION_HPP
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Vicente J. Botet Escriba 2014-2015. 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)
//
// See http://www.boost.org/libs/thread for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#include <exception>
#include <boost/throw_exception.hpp>
#include <boost/thread/detail/config.hpp>
#include <boost/thread/future.hpp>
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
#include <boost/thread/executors/basic_thread_pool.hpp>
#endif
#include <boost/thread/experimental/exception_list.hpp>
#include <boost/thread/experimental/parallel/v2/inline_namespace.hpp>
#include <boost/thread/csbl/vector.hpp>
#include <boost/thread/detail/move.hpp>
#include <boost/config/abi_prefix.hpp>
#define BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
namespace boost
{
namespace experimental
{
namespace parallel
{
BOOST_THREAD_INLINE_NAMESPACE(v2)
{
class BOOST_SYMBOL_VISIBLE task_canceled_exception: public std::exception
{
public:
//task_canceled_exception() BOOST_NOEXCEPT {}
//task_canceled_exception(const task_canceled_exception&) BOOST_NOEXCEPT {}
//task_canceled_exception& operator=(const task_canceled_exception&) BOOST_NOEXCEPT {}
virtual const char* what() const BOOST_NOEXCEPT_OR_NOTHROW
{ return "task_canceled_exception";}
};
template <class Executor>
class task_region_handle_gen;
namespace detail
{
void handle_task_region_exceptions(exception_list& errors)
{
try {
throw;
}
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
catch (task_canceled_exception&)
{
}
#endif
catch (exception_list const& el)
{
for (exception_list::const_iterator it = el.begin(); it != el.end(); ++it)
{
boost::exception_ptr const& e = *it;
try {
rethrow_exception(e);
}
catch (...)
{
handle_task_region_exceptions(errors);
}
}
}
catch (...)
{
errors.add(boost::current_exception());
}
}
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
template <class TRH, class F>
struct wrapped
{
TRH& tr;
F f;
wrapped(TRH& tr, BOOST_THREAD_RV_REF(F) f) : tr(tr), f(move(f))
{}
void operator()()
{
try
{
f();
}
catch (...)
{
lock_guard<mutex> lk(tr.mtx);
tr.canceled = true;
throw;
}
}
};
#endif
}
template <class Executor>
class task_region_handle_gen
{
private:
// Private members and friends
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
template <class TRH, class F>
friend struct detail::wrapped;
#endif
template <typename F>
friend void task_region(BOOST_THREAD_FWD_REF(F) f);
template<typename F>
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
template <class Ex, typename F>
friend void task_region(Ex&, BOOST_THREAD_FWD_REF(F) f);
template<class Ex, typename F>
friend void task_region_final(Ex&, BOOST_THREAD_FWD_REF(F) f);
void wait_all()
{
wait_for_all(group.begin(), group.end());
for (group_type::iterator it = group.begin(); it != group.end(); ++it)
{
BOOST_THREAD_FUTURE<void>& f = *it;
if (f.has_exception())
{
try
{
boost::rethrow_exception(f.get_exception_ptr());
}
catch (...)
{
detail::handle_task_region_exceptions(exs);
}
}
}
if (exs.size() != 0)
{
boost::throw_exception(exs);
}
}
protected:
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
{}
#endif
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
: canceled(false)
, ex(0)
{}
task_region_handle_gen(Executor& ex)
: canceled(false)
, ex(&ex)
{}
#endif
#if ! defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
: ex(0)
{}
task_region_handle_gen(Executor& ex)
: ex(&ex)
{}
#endif
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED && ! defined BOOST_THREAD_PROVIDES_EXECUTORS
task_region_handle_gen()
: canceled(false)
{
}
#endif
~task_region_handle_gen()
{
//wait_all();
}
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
mutable mutex mtx;
bool canceled;
#endif
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
Executor* ex;
#endif
exception_list exs;
typedef csbl::vector<BOOST_THREAD_FUTURE<void> > group_type;
group_type group;
public:
BOOST_DELETED_FUNCTION(task_region_handle_gen(const task_region_handle_gen&))
BOOST_DELETED_FUNCTION(task_region_handle_gen& operator=(const task_region_handle_gen&))
BOOST_DELETED_FUNCTION(task_region_handle_gen* operator&() const)
public:
template<typename F>
void run(BOOST_THREAD_FWD_REF(F) f)
{
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
{
lock_guard<mutex> lk(mtx);
if (canceled) {
boost::throw_exception(task_canceled_exception());
}
}
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
group.push_back(async(*ex, detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
#else
group.push_back(async(detail::wrapped<task_region_handle_gen<Executor>, F>(*this, forward<F>(f))));
#endif
#else
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
group.push_back(async(*ex, forward<F>(f)));
#else
group.push_back(async(forward<F>(f)));
#endif
#endif
}
void wait()
{
#if defined BOOST_THREAD_TASK_REGION_HAS_SHARED_CANCELED
{
lock_guard<mutex> lk(mtx);
if (canceled) {
boost::throw_exception(task_canceled_exception());
}
}
#endif
wait_all();
}
};
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
typedef basic_thread_pool default_executor;
#else
typedef int default_executor;
#endif
class task_region_handle :
public task_region_handle_gen<default_executor>
{
default_executor tp;
template <typename F>
friend void task_region(BOOST_THREAD_FWD_REF(F) f);
template<typename F>
friend void task_region_final(BOOST_THREAD_FWD_REF(F) f);
protected:
task_region_handle() : task_region_handle_gen<default_executor>()
{
#if defined BOOST_THREAD_PROVIDES_EXECUTORS
ex = &tp;
#endif
}
BOOST_DELETED_FUNCTION(task_region_handle(const task_region_handle&))
BOOST_DELETED_FUNCTION(task_region_handle& operator=(const task_region_handle&))
BOOST_DELETED_FUNCTION(task_region_handle* operator&() const)
};
template <typename Executor, typename F>
void task_region_final(Executor& ex, BOOST_THREAD_FWD_REF(F) f)
{
task_region_handle_gen<Executor> tr(ex);
try
{
f(tr);
}
catch (...)
{
detail::handle_task_region_exceptions(tr.exs);
}
tr.wait_all();
}
template <typename Executor, typename F>
void task_region(Executor& ex, BOOST_THREAD_FWD_REF(F) f)
{
task_region_final(ex, forward<F>(f));
}
template <typename F>
void task_region_final(BOOST_THREAD_FWD_REF(F) f)
{
task_region_handle tr;
try
{
f(tr);
}
catch (...)
{
detail::handle_task_region_exceptions(tr.exs);
}
tr.wait_all();
}
template <typename F>
void task_region(BOOST_THREAD_FWD_REF(F) f)
{
task_region_final(forward<F>(f));
}
} // v2
} // parallel
} // experimental
} // boost
#include <boost/config/abi_suffix.hpp>
#endif // header