13#ifndef dealii_thread_management_h
14#define dealii_thread_management_h
25#ifdef DEAL_II_WITH_TASKFLOW
26# include <taskflow/taskflow.hpp>
39#ifdef DEAL_II_HAVE_CXX20
44#ifdef DEAL_II_WITH_TBB
45# include <tbb/task_group.h>
78 template <
typename ForwardIterator>
79 std::vector<std::pair<ForwardIterator, ForwardIterator>>
81 const ForwardIterator &
end,
82 const unsigned int n_intervals);
92 std::vector<std::pair<unsigned int, unsigned int>>
94 const unsigned int end,
95 const unsigned int n_intervals);
147 template <
typename ForwardIterator>
148 std::vector<std::pair<ForwardIterator, ForwardIterator>>
150 const ForwardIterator &
end,
151 const unsigned int n_intervals)
153 using IteratorPair = std::pair<ForwardIterator, ForwardIterator>;
159 if (n_intervals == 1)
160 return (std::vector<IteratorPair>(1, IteratorPair(
begin,
end)));
163 const unsigned int n_elements = std::distance(
begin,
end);
164 const unsigned int n_elements_per_interval = n_elements / n_intervals;
165 const unsigned int residual = n_elements % n_intervals;
167 std::vector<IteratorPair> return_values(n_intervals);
169 return_values[0].first =
begin;
170 for (
unsigned int i = 0; i < n_intervals; ++i)
172 if (i != n_intervals - 1)
174 return_values[i].second = return_values[i].first;
179 std::advance(return_values[i].
second,
180 static_cast<signed int>(n_elements_per_interval));
184 ++return_values[i].second;
186 return_values[i + 1].first = return_values[i].second;
189 return_values[i].second =
end;
191 return return_values;
219 template <
typename RT>
240 "You cannot read the return value of a thread or task "
241 "if that value has not been set. This happens, for example, if "
242 "a task or thread threw an exception."));
249 value = std::move(v);
264 value = std::move(v.get());
289 template <
typename RT>
301 , value_is_initialized(false)
304 inline reference_type
308 value_is_initialized,
310 "You cannot read the return value of a thread or task "
311 "if that value has not been set. This happens, for example, if "
312 "a task or thread threw an exception."));
335 value_is_initialized =
true;
391 template <
typename T>
410 template <
typename T>
413 static std::reference_wrapper<T>
428 template <
typename RT,
typename Function>
430 (std::invocable<Function> &&
431 std::convertible_to<std::invoke_result_t<Function>, RT>))
434 promise.set_value(function());
447 template <
typename Function>
450 std::promise<
void> &promise)
486 template <
typename RT =
void>
501 Task(
const std::function<RT()> &function_object)
505#ifdef DEAL_II_WITH_TASKFLOW
528#elif defined(DEAL_II_WITH_TBB)
533 std::unique_ptr<std::promise<RT>> promise =
534 std::make_unique<std::promise<RT>>();
536 std::make_shared<TaskData>(std::move(promise->get_future()));
576 std::shared_ptr<std::promise<RT>>(std::move(promise))]() {
586 promise->set_exception(std::current_exception());
616 std::async(std::launch::async | std::launch::deferred,
632 std::promise<RT> promise;
633 task_data = std::make_shared<TaskData>(promise.get_future());
643 promise.set_exception(std::current_exception());
855 "The current object is not associated with a task that "
856 "can be joined. It may have been detached, or you "
857 "may have already joined it in the past.");
878#ifdef DEAL_II_WITH_TBB
879 ,
task_group(std::make_unique<tbb::task_group>())
965 std::scoped_lock lock(
mutex);
970#ifdef DEAL_II_WITH_TASKFLOW
982 return (
future.wait_for(std::chrono::seconds(0)) ==
983 std::future_status::ready);
1005#elif defined(DEAL_II_WITH_TBB)
1129#ifdef DEAL_II_WITH_TBB
1139 friend class Task<RT>;
1171 template <
typename RT>
1257 template <
typename FunctionObjectType>
1259 inline auto
new_task(FunctionObjectType function_object)
1260 ->
Task<decltype(function_object())>
1262 using return_type =
decltype(function_object());
1264 return new_task(std::function<return_type()>(function_object));
1275 template <
typename RT,
typename... Args>
1281 [dummy, fun_ptr]() -> RT {
return std::apply(fun_ptr, dummy); });
1327 typename FunctionObject,
1329 typename = std::enable_if_t<std::is_invocable_v<FunctionObject, Args...>>,
1330 typename = std::enable_if_t<std::is_function_v<FunctionObject> ==
false>,
1332 std::enable_if_t<std::is_member_pointer_v<FunctionObject> ==
false>,
1333 typename = std::enable_if_t<std::is_pointer_v<FunctionObject> ==
false>>
1334 inline Task<std::invoke_result_t<FunctionObject, Args...>>
1337 using RT = std::invoke_result_t<FunctionObject, Args...>;
1338 auto dummy = std::make_tuple(std::forward<Args>(args)...);
1339 return new_task([dummy, fun]() -> RT {
return std::apply(fun, dummy); });
1350 template <
typename RT,
typename C,
typename... Args>
1354 std_cxx20::type_identity_t<Args>... args)
1357 return new_task(std::function<RT()>(std::bind(
1367 template <
typename RT,
typename C,
typename... Args>
1371 std_cxx20::type_identity_t<Args>... args)
1374 return new_task(std::function<RT()>(std::bind(
1391 template <
typename RT =
void>
1416 return tasks.size();
1436 std::vector<RT> results;
1437 results.reserve(
size());
1438 for (
auto &t :
tasks)
1439 results.emplace_back(std::move(t.return_value()));
1453 for (
const auto &t :
tasks)
static void initialize_multithreading()
static unsigned int n_threads()
static tf::Executor & get_taskflow_executor()
TaskGroup & operator+=(const Task< RT > &t)
std::vector< RT > return_values()
std::list< Task< RT > > tasks
TaskData(std::future< RT > &&future) noexcept
TaskData(const TaskData &)=delete
TaskData & operator=(const TaskData &)=delete
std::atomic< bool > task_has_finished
internal::return_value< RT > returned_object
std::unique_ptr< tbb::task_group > task_group
TaskData & operator=(TaskData &&)=delete
TaskData(TaskData &&)=delete
internal::return_value< RT >::reference_type get()
Task(Task &&other) noexcept=default
std::shared_ptr< TaskData > task_data
internal::return_value< RT >::reference_type return_value()
Task & operator=(Task &&other) noexcept=default
Task(const Task &other)=default
Task(const std::function< RT()> &function_object)
Task & operator=(const Task &other)=default
#define DEAL_II_NAMESPACE_OPEN
#define DEAL_II_CXX20_REQUIRES(condition)
#define DEAL_II_NAMESPACE_CLOSE
static ::ExceptionBase & ExcNoTask()
#define Assert(cond, exc)
#define DeclExceptionMsg(Exception, defaulttext)
static ::ExceptionBase & ExcMessage(std::string arg1)
#define AssertThrow(cond, exc)
std::vector< std::pair< ForwardIterator, ForwardIterator > > split_range(const ForwardIterator &begin, const ForwardIterator &end, const unsigned int n_intervals)
Task< RT > new_task(const std::function< RT()> &function)
std::vector< std::pair< unsigned int, unsigned int > > split_interval(const unsigned int begin, const unsigned int end, const unsigned int n_intervals)
void handle_unknown_exception()
void evaluate_and_set_promise(Function &function, std::promise< RT > &promise)
void handle_std_exception(const std::exception &exc)
typename type_identity< T >::type type_identity_t
static std::reference_wrapper< T > act(T &t)
reference_type get() const
bool value_is_initialized
void set_from(std::future< RT & > &v)
void set_from(std::future< void > &)
bool value_is_initialized
void set_from(std::future< RT > &v)