16 #ifndef dealii_thread_management_h 17 # define dealii_thread_management_h 20 # include <deal.II/base/config.h> 22 # include <deal.II/base/exceptions.h> 23 # include <deal.II/base/multithread_info.h> 24 # include <deal.II/base/template_constraints.h> 26 # ifdef DEAL_II_WITH_THREADS 27 # include <condition_variable> 32 # include <functional> 41 # ifdef DEAL_II_WITH_THREADS 42 # ifdef DEAL_II_USE_MT_POSIX 45 # include <tbb/task.h> 46 # include <tbb/tbb_stddef.h> 51 DEAL_II_NAMESPACE_OPEN
210 const char * name =
nullptr,
211 void * arg =
nullptr);
239 ExcBarrierSizeNotUseful,
241 <<
"In single-thread mode, barrier sizes other than 1 are not " 242 <<
"useful. You gave " << arg1 <<
".");
248 # ifdef DEAL_II_WITH_THREADS 384 condition_variable.notify_one();
394 condition_variable.notify_all();
409 std::unique_lock<std::mutex> lock(mutex.
mutex, std::adopt_lock);
410 condition_variable.wait(lock);
443 const char * name =
nullptr,
444 void * arg =
nullptr);
465 # ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS 567 template <
typename ForwardIterator>
568 std::vector<std::pair<ForwardIterator, ForwardIterator>>
570 const ForwardIterator &end,
571 const unsigned int n_intervals);
581 std::vector<std::pair<unsigned int, unsigned int>>
583 const unsigned int end,
584 const unsigned int n_intervals);
615 handle_std_exception(
const std::exception &exc);
625 handle_unknown_exception();
658 template <
typename ForwardIterator>
659 std::vector<std::pair<ForwardIterator, ForwardIterator>>
661 const ForwardIterator &end,
662 const unsigned int n_intervals)
664 using IteratorPair = std::pair<ForwardIterator, ForwardIterator>;
670 if (n_intervals == 1)
671 return (std::vector<IteratorPair>(1, IteratorPair(begin, end)));
674 const unsigned int n_elements = std::distance(begin, end);
675 const unsigned int n_elements_per_interval = n_elements / n_intervals;
676 const unsigned int residual = n_elements % n_intervals;
678 std::vector<IteratorPair> return_values(n_intervals);
680 return_values[0].first = begin;
681 for (
unsigned int i = 0; i < n_intervals; ++i)
683 if (i != n_intervals - 1)
685 return_values[i].second = return_values[i].first;
690 std::advance(return_values[i].second,
691 static_cast<signed int>(n_elements_per_interval));
695 ++return_values[i].second;
697 return_values[i + 1].first = return_values[i].second;
700 return_values[i].second = end;
702 return return_values;
720 template <
typename RT>
727 using reference_type = RT &;
729 inline return_value()
733 inline reference_type
742 value = std::move(v);
756 template <
typename RT>
757 struct return_value<RT &>
763 using reference_type = RT &;
765 inline return_value()
769 inline reference_type
792 struct return_value<void>
794 using reference_type = void;
806 template <
typename RT>
808 call(
const std::function<RT()> &
function,
809 internal::return_value<RT> &ret_val)
811 ret_val.set(
function());
816 call(
const std::function<
void()> &
function, internal::return_value<void> &)
826 # ifdef DEAL_II_WITH_THREADS 838 template <
typename RT>
898 : thread_is_active(false)
903 if (!thread_is_active)
906 thread_is_active =
false;
914 start(
const std::function<RT()> &
function)
916 thread_is_active =
true;
917 ret_val = std::make_shared<return_value<RT>>();
918 thread = std::thread(thread_entry_point,
function, ret_val);
931 if (thread_is_active ==
false)
935 if (thread_is_active ==
true)
939 thread_is_active =
false;
949 std::shared_ptr<return_value<RT>> ret_val)
956 internal::register_thread();
959 call(
function, *ret_val);
961 catch (
const std::exception &exc)
963 internal::handle_std_exception(exc);
967 internal::handle_unknown_exception();
969 internal::deregister_thread();
982 template <
typename RT>
989 std::shared_ptr<return_value<RT>> ret_val;
996 start(
const std::function<RT()> &
function)
998 ret_val = std::make_shared<return_value<RT>>();
999 call(
function, *ret_val);
1036 template <
typename RT =
void>
1044 : thread_descriptor(new
internal::ThreadDescriptor<RT>())
1047 thread_descriptor->start(
function);
1061 : thread_descriptor(t.thread_descriptor)
1072 if (thread_descriptor)
1073 thread_descriptor->join();
1119 typename internal::return_value<RT>::reference_type
1123 return thread_descriptor->ret_val->get();
1133 return static_cast<bool>(thread_descriptor);
1167 template <
typename T>
1186 template <
typename T>
1189 static std::reference_wrapper<T>
1209 template <
typename RT>
1282 template <
typename FunctionObjectType>
1287 using return_type = decltype(function_object());
1299 template <
typename RT,
typename... Args>
1301 new_thread(RT (*fun_ptr)(Args...),
typename identity<Args>::type... args)
1314 template <
typename RT,
typename C,
typename... Args>
1317 typename identity<C>::type &c,
1318 typename identity<Args>::type... args)
1320 return new_thread(std::function<RT()>(std::bind(
1324 # ifndef DEAL_II_CONST_MEMBER_DEDUCTION_BUG 1330 template <
typename RT,
typename C,
typename... Args>
1333 typename identity<const C>::type &c,
1334 typename identity<Args>::type... args)
1336 return new_thread(std::function<RT()>(std::bind(
1351 template <
typename RT =
void>
1361 threads.push_back(t);
1374 for (
typename std::list<
Thread<RT>>::const_iterator t = threads.begin();
1394 # ifdef DEAL_II_WITH_THREADS 1397 struct TaskDescriptor;
1402 template <
typename RT>
1406 : task_descriptor(task_descriptor)
1416 call(task_descriptor.function, task_descriptor.ret_val);
1418 catch (
const std::exception &exc)
1420 internal::handle_std_exception(exc);
1424 internal::handle_unknown_exception();
1456 template <
typename RT>
1457 struct TaskDescriptor
1463 std::function<RT()>
function;
1478 return_value<RT> ret_val;
1489 TaskDescriptor(
const std::function<RT()> &
function);
1502 TaskDescriptor(
const TaskDescriptor &);
1514 operator=(
const TaskDescriptor &);
1536 friend class ::Threads::Task<RT>;
1541 template <
typename RT>
1542 inline TaskDescriptor<RT>::TaskDescriptor(
1543 const std::function<RT()> &
function)
1544 :
function(
function)
1546 , task_is_done(
false)
1550 template <
typename RT>
1552 TaskDescriptor<RT>::queue_task()
1556 task =
new (tbb::task::allocate_root()) tbb::empty_task;
1557 task->set_ref_count(2);
1567 # if TBB_VERSION_MAJOR >= 4 1568 tbb::task::spawn(*worker);
1570 task->spawn(*worker);
1576 template <
typename RT>
1577 TaskDescriptor<RT>::TaskDescriptor()
1578 : task_is_done(
false)
1585 template <
typename RT>
1586 TaskDescriptor<RT>::TaskDescriptor(
const TaskDescriptor &)
1587 : task_is_done(
false)
1596 template <
typename RT>
1597 inline TaskDescriptor<RT>::~TaskDescriptor()
1614 task->destroy(*task);
1618 template <
typename RT>
1619 TaskDescriptor<RT> &
1620 TaskDescriptor<RT>::operator=(
const TaskDescriptor &)
1629 template <
typename RT>
1631 TaskDescriptor<RT>::join()
1642 if (task_is_done ==
true)
1646 task_is_done =
true;
1647 task->wait_for_all();
1652 # else // no threading enabled 1658 template <
typename RT>
1659 struct TaskDescriptor
1664 return_value<RT> ret_val;
1670 TaskDescriptor(
const std::function<RT()> &
function)
1672 call(
function, ret_val);
1708 template <
typename RT =
void>
1719 Task(
const std::function<RT()> &function_object)
1724 std::make_shared<internal::TaskDescriptor<RT>>(function_object);
1725 task_descriptor->queue_task();
1736 : task_descriptor(t.task_descriptor)
1765 task_descriptor->join();
1783 return (task_descriptor !=
1784 std::shared_ptr<internal::TaskDescriptor<RT>>());
1831 typename internal::return_value<RT>::reference_type
1835 return task_descriptor->ret_val.get();
1860 "The current object is not associated with a task that " 1861 "can be joined. It may have been detached, or you " 1862 "may have already joined it in the past.");
1882 template <
typename RT>
1955 template <
typename FunctionObjectType>
1960 using return_type = decltype(function_object());
1973 template <
typename RT,
typename... Args>
1975 new_task(RT (*fun_ptr)(Args...),
typename identity<Args>::type... args)
1977 return new_task(std::function<RT()>(
1988 template <
typename RT,
typename C,
typename... Args>
1991 typename identity<C>::type &c,
1992 typename identity<Args>::type... args)
1994 return new_task(std::function<RT()>(std::bind(
1998 # ifndef DEAL_II_CONST_MEMBER_DEDUCTION_BUG 2004 template <
typename RT,
typename C,
typename... Args>
2007 typename identity<const C>::type &c,
2008 typename identity<Args>::type... args)
2010 return new_task(std::function<RT()>(std::bind(
2031 template <
typename RT =
void>
2054 for (
typename std::list<
Task<RT>>::const_iterator t = tasks.begin();
2075 DEAL_II_NAMESPACE_CLOSE
std::shared_ptr< internal::ThreadDescriptor< RT > > thread_descriptor
#define AssertNothrow(cond, exc)
unsigned int this_thread_id()
Task< RT > new_task(const std::function< RT()> &function)
Thread(const Thread< RT > &t)
TaskDescriptor< RT > & task_descriptor
std::list< Task< RT > > tasks
internal::return_value< RT >::reference_type return_value()
ScopedLock(DummyThreadMutex &)
std::shared_ptr< return_value< RT > > ret_val
#define AssertThrow(cond, exc)
std::vector< std::pair< unsigned int, unsigned int > > split_interval(const unsigned int begin, const unsigned int end, const unsigned int n_intervals)
Task(const std::function< RT()> &function_object)
Mutex & operator=(const Mutex &)
void wait(DummyThreadMutex &) const
#define DeclException1(Exception1, type1, outsequence)
std::condition_variable condition_variable
#define Assert(cond, exc)
static void initialize_multithreading()
std::shared_ptr< internal::TaskDescriptor< RT > > task_descriptor
#define DeclExceptionMsg(Exception, defaulttext)
unsigned int n_existing_threads()
Thread(const std::function< RT()> &function)
internal::return_value< RT >::reference_type return_value()
bool operator==(const Task &t) const
TaskGroup & operator+=(const Task< RT > &t)
void start(const std::function< RT()> &function)
ThreadGroup & operator+=(const Thread< RT > &t)
Task(const Task< RT > &t)
Thread< RT > new_thread(const std::function< RT()> &function)
static void thread_entry_point(const std::function< RT()> &function, std::shared_ptr< return_value< RT >> ret_val)
Mutex thread_is_active_mutex
pthread_barrier_t barrier
bool operator==(const Thread &t) const
std::vector< std::pair< ForwardIterator, ForwardIterator > > split_range(const ForwardIterator &begin, const ForwardIterator &end, const unsigned int n_intervals)
std::list< Thread< RT > > threads
static::ExceptionBase & ExcInternalError()