Skip to content

Commit e11216a

Browse files
committed
do not launch taskflow tasks from inside tasks
This works around the deadlocks reported in dealii#17669
1 parent 9bd70d8 commit e11216a

File tree

1 file changed

+41
-34
lines changed

1 file changed

+41
-34
lines changed

include/deal.II/base/thread_management.h

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -504,8 +504,14 @@ namespace Threads
504504
if (MultithreadInfo::n_threads() > 1)
505505
{
506506
#ifdef DEAL_II_WITH_TASKFLOW
507-
task_data = std::make_shared<TaskData>(
508-
MultithreadInfo::get_taskflow_executor().async(function_object));
507+
508+
if (MultithreadInfo::get_taskflow_executor().this_worker_id() < 0)
509+
{
510+
task_data = std::make_shared<TaskData>(
511+
MultithreadInfo::get_taskflow_executor().async(
512+
function_object));
513+
return;
514+
}
509515
#elif defined(DEAL_II_WITH_TBB)
510516
// Create a promise object and from it extract a future that
511517
// we can use to refer to the outcome of the task. For reasons
@@ -573,6 +579,7 @@ namespace Threads
573579
}
574580
}
575581
});
582+
return;
576583

577584
#else
578585
// If no threading library is supported, just fall back onto C++11
@@ -595,40 +602,40 @@ namespace Threads
595602
task_data = std::make_shared<TaskData>(
596603
std::async(std::launch::async | std::launch::deferred,
597604
function_object));
605+
return;
598606
#endif
599607
}
600-
else
601-
{
602-
// Only one thread allowed. So let the task run to completion
603-
// and just emplace a 'ready' future.
604-
//
605-
// The design of std::promise/std::future is unclear, but it
606-
// seems that the intent is to obtain the std::future before
607-
// we set the std::promise. So create the TaskData object at
608-
// the top and then run the task and set the returned
609-
// value. Since everything here happens sequentially, it
610-
// really doesn't matter in which order all of this is
611-
// happening.
612-
std::promise<RT> promise;
613-
task_data = std::make_shared<TaskData>(promise.get_future());
614-
try
615-
{
616-
internal::evaluate_and_set_promise(function_object, promise);
617-
}
618-
catch (...)
619-
{
620-
try
621-
{
622-
// store anything thrown in the promise
623-
promise.set_exception(std::current_exception());
624-
}
625-
catch (...)
626-
{
627-
// set_exception() may throw too. But ignore this on
628-
// the task.
629-
}
630-
}
631-
}
608+
{
609+
// Only one thread allowed. So let the task run to completion
610+
// and just emplace a 'ready' future.
611+
//
612+
// The design of std::promise/std::future is unclear, but it
613+
// seems that the intent is to obtain the std::future before
614+
// we set the std::promise. So create the TaskData object at
615+
// the top and then run the task and set the returned
616+
// value. Since everything here happens sequentially, it
617+
// really doesn't matter in which order all of this is
618+
// happening.
619+
std::promise<RT> promise;
620+
task_data = std::make_shared<TaskData>(promise.get_future());
621+
try
622+
{
623+
internal::evaluate_and_set_promise(function_object, promise);
624+
}
625+
catch (...)
626+
{
627+
try
628+
{
629+
// store anything thrown in the promise
630+
promise.set_exception(std::current_exception());
631+
}
632+
catch (...)
633+
{
634+
// set_exception() may throw too. But ignore this on
635+
// the task.
636+
}
637+
}
638+
}
632639
}
633640

634641
/**

0 commit comments

Comments
 (0)