# include <pthread.h>
# endif
# include <tbb/task.h>
-# include <tbb/task_scheduler_init.h>
#endif
*
* @ingroup threads
*/
-namespace Threads
+namespace Threads
{
/**
* This class is used instead of a true lock class when not using
*/
~ScopedLock () {}
};
-
+
/**
* Simulate acquisition of the
* mutex. As this class does
};
-
+
/**
* This class is used instead of a true barrier class when not using
* multithreading. It allows to write programs such that they use the
/** @addtogroup Exceptions
* @{ */
-
+
/**
* Exception.
*/
//@}
};
-
-
+
+
#if DEAL_II_USE_MT == 1
/**
*
* @author Wolfgang Bangerth, 2002, 2003, 2009
*/
- class Mutex
+ class Mutex
{
public:
/**
* of course does nothing.
*/
~ScopedLock () { mutex.release (); }
-
+
private:
/**
* Store the address of the
:
mutex()
{}
-
-
+
+
/**
* Acquire a mutex.
*/
*
* @author Wolfgang Bangerth, 2002
*/
- class PosixThreadBarrier
+ class PosixThreadBarrier
{
public:
/**
* Destructor. Release all
* resources.
*/
- ~PosixThreadBarrier ();
+ ~PosixThreadBarrier ();
/**
* Wait for all threads to
*
* @deprecated
*/
- typedef ConditionVariable ThreadCondition;
+ typedef ConditionVariable ThreadCondition;
/**
* If using POSIX functions, then
*/
typedef DummyBarrier Barrier;
#endif
-
+
}
* locks and mutexes, or may be
* sleeping until they are
* delivered with data to work on.
- *
+ *
* Upon program start, this number
* is one. It is increased each
* time a thread is created using
* @ingroup threads
*/
unsigned int this_thread_id ();
-
+
/**
* Split the range <tt>[begin,end)</tt>
* into <tt>n_intervals</tt> subintervals
* iterators, now values are taken
* that define the whole interval.
*
- * @ingroup threads
+ * @ingroup threads
*/
std::vector<std::pair<unsigned int,unsigned int> >
split_interval (const unsigned int begin,
/**
* @cond internal
*/
-
+
/**
* A namespace in which helper
* functions and the like for the
* implemented. The members of this
* namespace are not meant for
* public use.
- *
+ *
* @author Wolfgang Bangerth, 2003
*/
namespace internal
* functions below.
*/
void register_thread ();
-
+
/**
* @internal
* The following function is used
/**
* @endcond
*/
-
+
} // end declarations of namespace Threads
/* ----------- implementation of functions in namespace Threads ---------- */
#ifndef DOXYGEN
-namespace Threads
-{
+namespace Threads
+{
template <typename ForwardIterator>
std::vector<std::pair<ForwardIterator,ForwardIterator> >
split_range (const ForwardIterator &begin,
// n_intervals==1, so have a
// shortcut here to handle that
// case efficiently
-
+
if (n_intervals==1)
return (std::vector<IteratorPair>
(1, IteratorPair(begin, end)));
-
+
// if more than one interval
// requested, do the full work
const unsigned int n_elements = std::distance (begin, end);
const unsigned int n_elements_per_interval = n_elements / n_intervals;
const unsigned int residual = n_elements % n_intervals;
-
+
std::vector<IteratorPair> return_values (n_intervals);
return_values[0].first = begin;
for (unsigned int i=0; i<n_intervals; ++i)
{
- if (i != n_intervals-1)
+ if (i != n_intervals-1)
{
return_values[i].second = return_values[i].first;
// note: the cast is
// subintervals
if (i < residual)
++return_values[i].second;
-
+
return_values[i+1].first = return_values[i].second;
}
else
return_values[i].second = end;
}
return return_values;
- }
+ }
}
#endif // DOXYGEN
namespace Threads
{
- namespace internal
+ namespace internal
{
/**
* @internal
RT value;
public:
inline return_value () : value() {}
-
+
inline RT get () const { return value; }
inline void set (RT v) { value = v; }
};
-
+
/**
* @internal
* Given an arbitrary type RT,
inline void set (RT & v) { value = &v; }
};
-
+
/**
* @internal
* Given an arbitrary type RT,
};
}
-
+
namespace internal
{
internal::return_value<RT> &ret_val)
{
ret_val.set (function());
- }
+ }
inline void call (const std_cxx1x::function<void ()> &function,
internal::return_value<void> &)
{
function();
- }
+ }
}
template <typename RT, typename ArgList,
int length = std_cxx1x::tuple_size<ArgList>::value>
struct fun_ptr_helper;
-
+
/**
* @internal
typename std_cxx1x::tuple_element<9,ArgList>::type);
};
-
+
/**
* @internal
- namespace internal
+ namespace internal
{
#if (DEAL_II_USE_MT == 1)
{
thread.join ();
}
-
+
private:
/**
void thread_entry_point (const std_cxx1x::function<RT ()> function,
ThreadDescriptor<RT> *descriptor)
{
- // create a new scheduler object
- // so that we can start tasks on
- // the new thread. the scheduler
- // will go out of scope at the
- // end of the function, which
- // also coincides with the end of
- // the thread
- //
- // one may think that the
- // creation of a scheduler is
- // expensive, but just creating
- // one and then destroying it
- // again costs about 92
- // nanoseconds on my laptop
- // (early 2009), whereas thread
- // creation takes about 12000
- // nanoseconds, more than 100
- // times longer. there is
- // therefore no need to only
- // create the scheduler when this
- // is actually necessary because
- // we are spawning tasks on this
- // particular thread; rather, we
- // make our life simpler by
- // always having a scheduler
- // around
- tbb::task_scheduler_init scheduler;
-
- // now call the function
+ // call the function
// in question. since an
// exception that is
// thrown from one of the
// the operating system's
// thread library
internal::register_thread ();
- try
+ try
{
call (function, descriptor->ret_val);
}
* this descriptor.
*/
template <typename RT>
- struct ThreadDescriptor
+ struct ThreadDescriptor
{
/**
* An object that will hold the value
void join ()
{}
};
-
+
#endif
}
-
+
/**
* An object that represents a
* calling on a new thread has no
* return value, you can omit the
* template argument.
- *
+ *
* @author Wolfgang Bangerth, 2003, 2009
* @ingroup threads
* @ingroup threads
/** @addtogroup Exceptions
* @{ */
-
+
/**
* Exception
*/
std_cxx1x::shared_ptr<internal::ThreadDescriptor<RT> > thread_descriptor;
};
-
+
namespace internal
{
/**
return t;
}
};
-
+
/**
}
};
}
-
-
+
+
namespace internal
{
{
return Thread<RT> (function);
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
(std_cxx1x::bind (function,
internal::maybe_make_ref<typename std_cxx1x::tuple_element<0,ArgList>::type>::act(arg1)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
internal::maybe_make_ref<typename std_cxx1x::tuple_element<0,ArgList>::type>::act(arg1),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<1,ArgList>::type>::act(arg2)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
internal::maybe_make_ref<typename std_cxx1x::tuple_element<1,ArgList>::type>::act(arg2),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<2,ArgList>::type>::act(arg3)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
internal::maybe_make_ref<typename std_cxx1x::tuple_element<2,ArgList>::type>::act(arg3),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<3,ArgList>::type>::act(arg4)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
internal::maybe_make_ref<typename std_cxx1x::tuple_element<3,ArgList>::type>::act(arg4),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<4,ArgList>::type>::act(arg5)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
internal::maybe_make_ref<typename std_cxx1x::tuple_element<4,ArgList>::type>::act(arg5),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<5,ArgList>::type>::act(arg6)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
internal::maybe_make_ref<typename std_cxx1x::tuple_element<5,ArgList>::type>::act(arg6),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<6,ArgList>::type>::act(arg7)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
internal::maybe_make_ref<typename std_cxx1x::tuple_element<6,ArgList>::type>::act(arg7),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<7,ArgList>::type>::act(arg8)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
-
+
/**
* @internal
* Encapsulator class for
internal::maybe_make_ref<typename std_cxx1x::tuple_element<7,ArgList>::type>::act(arg8),
internal::maybe_make_ref<typename std_cxx1x::tuple_element<8,ArgList>::type>::act(arg9)));
}
-
+
private:
std_cxx1x::function<typename internal::fun_ptr<RT,ArgList>::type> function;
};
return fun_ptr;
}
-
+
/**
* Overload of the non-const spawn
* function for member functions with
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c)));
}
-
+
return
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<Arg1,Arg2> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c), _1, _2));
- }
+ }
// ----------- encapsulators for ternary functions
return
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<Arg1,Arg2,Arg3> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c), _1, _2, _3));
- }
+ }
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<Arg1, Arg2, Arg3, Arg4, Arg5> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c), _1, _2, _3, _4, _5));
}
-
+
// ----------- encapsulators for functions with 6 arguments
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<Arg1, Arg2, Arg3, Arg4, Arg5, Arg6> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c), _1, _2, _3, _4, _5, _6));
}
-
+
// ----------- encapsulators for functions with 7 arguments
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c), _1, _2, _3, _4, _5, _6, _7));
}
-
+
// ----------- encapsulators for functions with 8 arguments
std_cxx1x::function<typename internal::fun_ptr<RT,std_cxx1x::tuple<Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8> >::type>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c), _1, _2, _3, _4, _5, _6, _7, _8));
}
-
+
// ----------- encapsulators for functions with 9 arguments
{
return Thread<RT>(fun_ptr);
}
-
+
/**
* Overload of the non-const new_thread
Thread<RT>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c)));
}
-#endif
+#endif
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c),
internal::maybe_make_ref<Arg1>::act(arg1),
internal::maybe_make_ref<Arg2>::act(arg2)));
- }
+ }
#endif
// ----------- thread starters for ternary functions
internal::maybe_make_ref<Arg1>::act(arg1),
internal::maybe_make_ref<Arg2>::act(arg2),
internal::maybe_make_ref<Arg3>::act(arg3)));
- }
+ }
#endif
internal::maybe_make_ref<Arg4>::act(arg4),
internal::maybe_make_ref<Arg5>::act(arg5)));
}
-#endif
+#endif
// ----------- thread starters for functions with 6 arguments
internal::maybe_make_ref<Arg5>::act(arg5),
internal::maybe_make_ref<Arg6>::act(arg6)));
}
-#endif
+#endif
// ----------- thread starters for functions with 7 arguments
internal::maybe_make_ref<Arg6>::act(arg6),
internal::maybe_make_ref<Arg7>::act(arg7)));
}
-#endif
+#endif
// ----------- thread starters for functions with 8 arguments
internal::maybe_make_ref<Arg7>::act(arg7),
internal::maybe_make_ref<Arg8>::act(arg8)));
}
-#endif
+#endif
// ----------- thread starters for functions with 9 arguments
internal::maybe_make_ref<Arg7>::act(arg7),
internal::maybe_make_ref<Arg8>::act(arg8),
internal::maybe_make_ref<Arg9>::act(arg9)));
- }
+ }
#endif
-
-// ------------------------ ThreadGroup -------------------------------------
+
+// ------------------------ ThreadGroup -------------------------------------
/**
* A container for thread
* @ingroup threads
*/
template <typename RT = void>
- class ThreadGroup
+ class ThreadGroup
{
public:
/**
t=threads.begin(); t!=threads.end(); ++t)
t->join ();
}
-
+
private:
/**
* List of thread objects.
*/
std::list<Thread<RT> > threads;
};
-
+
template <typename> class Task;
-
- namespace internal
+
+ namespace internal
{
#if (DEAL_II_USE_MT == 1)
template <typename> class TaskDescriptor;
-
+
/**
* The task class for TBB that is
* used by the TaskDescriptor
// TaskDescriptor::join().
task_descriptor.task_is_done = true;
task_descriptor.completion_mutex.release ();
-
+
return 0;
}
* object of this task.
*/
TaskDescriptor<RT> &task_descriptor;
- };
-
+ };
+
/**
* @internal
* Base class describing a
* that are to be run on the task.
*/
std_cxx1x::function<RT ()> function;
-
+
/**
* Variable holding the data the TBB
* needs to work with a task. Set by
* deposit its return value.
*/
return_value<RT> ret_val;
-
+
/**
* A flag indicating whether the task
* has terminated.
* task.
*/
TaskDescriptor ();
-
+
/**
* Copy constructor. Throws
* an exception since we want
* task.
*/
TaskDescriptor (const TaskDescriptor &);
-
+
/**
* Destructor.
*/
* already.
*/
void queue_task ();
-
+
/**
* Join a task, i.e. wait
* for it to finish. This
TaskDescriptor<RT>::TaskDescriptor (const std_cxx1x::function<RT ()> &function)
:
function (function),
- task_is_done (false)
+ task_is_done (false)
{}
// become unlocked when the
// task is done
completion_mutex.acquire ();
-
+
// use the pattern described in
// the TBB book on pages
// 230/231 ("Start a large task
{
Assert (false, ExcInternalError());
}
-
+
template <typename RT>
task->destroy (*task);
}
-
+
template <typename RT>
inline
void
*/
static void queue_task () {}
};
-
+
#endif
-
+
}
-
+
template <typename RT = void>
class Task
{
/** @addtogroup Exceptions
* @{ */
-
+
/**
* Exception
*/
{
return new_task<RT>(std_cxx1x::function<RT ()>(fun_ptr));
}
-
-
+
+
/**
* Overload of the non-const new_task
* function for member functions with
new_task<RT>
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c)));
}
-#endif
+#endif
(std_cxx1x::bind(fun_ptr, std_cxx1x::cref(c),
internal::maybe_make_ref<Arg1>::act(arg1),
internal::maybe_make_ref<Arg2>::act(arg2)));
- }
+ }
#endif
// ----------- thread starters for ternary functions
internal::maybe_make_ref<Arg1>::act(arg1),
internal::maybe_make_ref<Arg2>::act(arg2),
internal::maybe_make_ref<Arg3>::act(arg3)));
- }
+ }
#endif
internal::maybe_make_ref<Arg4>::act(arg4),
internal::maybe_make_ref<Arg5>::act(arg5)));
}
-#endif
+#endif
// ----------- thread starters for functions with 6 arguments
internal::maybe_make_ref<Arg5>::act(arg5),
internal::maybe_make_ref<Arg6>::act(arg6)));
}
-#endif
+#endif
// ----------- thread starters for functions with 7 arguments
internal::maybe_make_ref<Arg6>::act(arg6),
internal::maybe_make_ref<Arg7>::act(arg7)));
}
-#endif
+#endif
// ----------- thread starters for functions with 8 arguments
internal::maybe_make_ref<Arg7>::act(arg7),
internal::maybe_make_ref<Arg8>::act(arg8)));
}
-#endif
+#endif
// ----------- thread starters for functions with 9 arguments
internal::maybe_make_ref<Arg7>::act(arg7),
internal::maybe_make_ref<Arg8>::act(arg8),
internal::maybe_make_ref<Arg9>::act(arg9)));
- }
+ }
#endif
-// ------------------------ TaskGroup -------------------------------------
+// ------------------------ TaskGroup -------------------------------------
/**
* A container for task
* @ingroup tasks
*/
template <typename RT = void>
- class TaskGroup
+ class TaskGroup
{
public:
/**
t=tasks.begin(); t!=tasks.end(); ++t)
t->join ();
}
-
+
private:
/**
* List of task objects.
*/
std::list<Task<RT> > tasks;
};
-
+
} // end of implementation of namespace Threads
/**