From bb69e5557fecf6e27d0242437d972c33e737732b Mon Sep 17 00:00:00 2001 From: bangerth Date: Fri, 9 Jan 2009 19:40:43 +0000 Subject: [PATCH] First attempt at getting things to work in non-MT mode without TBB. git-svn-id: https://svn.dealii.org/trunk@18159 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/base/include/base/thread_management.h | 301 +++++++++++------- 1 file changed, 179 insertions(+), 122 deletions(-) diff --git a/deal.II/base/include/base/thread_management.h b/deal.II/base/include/base/thread_management.h index f3a2044edf..662c061293 100644 --- a/deal.II/base/include/base/thread_management.h +++ b/deal.II/base/include/base/thread_management.h @@ -1455,7 +1455,7 @@ namespace Threads boost::shared_ptr > thread_descriptor; #if !defined(DEAL_II_NAMESP_TEMPL_FRIEND_BUG2) && !defined(DEAL_II_NAMESP_TEMPL_FRIEND_BUG) - template friend struct internal::fun_wrapper; + template friend struct internal::ThreadStarter; #endif }; @@ -1475,29 +1475,9 @@ namespace Threads * @author Wolfgang Bangerth, 2003 */ template - struct fun_wrapper + struct ThreadStarter { - /** - * Constructor. Store the - * necessary information - * about the function to be - * called and with which - * arguments. - * - * Pass down the address of - * this class's thread entry - * point function. This way, - * we can ensure that object - * and thread entry point - * function always are in - * synch with respect to - * their knowledge of the - * types involved. - */ - fun_wrapper (const boost::function &function) - : function (function) {} - - + public: /** * Start a new thread, wait * until it has copied the @@ -1508,54 +1488,75 @@ namespace Threads * In the non-multithreaded case, * simply call the function. */ - Thread fire_up () + static + Thread start_thread (const boost::function &function) { - thread_descriptor = - DescriptionPointer(new internal::thread_description()); + ThreadStarter wrapper (function); + wrapper.thread_descriptor = + boost::shared_ptr > + (new internal::thread_description()); #if (DEAL_II_USE_MT == 1) - ThreadMutex::ScopedLock lock (mutex); - thread_descriptor->create (&entry_point, (void *)this); - condition.wait (mutex); + ThreadMutex::ScopedLock lock (wrapper.mutex); + wrapper.thread_descriptor->create (&ThreadStarter::entry_point, + (void *)&wrapper); + + // wait for the newly created + // thread to indicate that it has + // copied the function + // descriptor. note that the + // POSIX description of + // pthread_cond_wait says that + // the function can return + // spuriously and may have to be + // called again; we guard against + // this using the + // data_has_been_copied variable + // that indicates whether the + // condition has actually been + // met + do + { + wrapper.condition.wait (wrapper.mutex); + } + while (wrapper.data_has_been_copied == false); #else - call (function, thread_descriptor->ret_val); + call (function, wrapper.thread_descriptor->ret_val); #endif - return thread_descriptor; + return wrapper.thread_descriptor; } private: /** - * Default constructor. Made - * private and not - * implemented to prevent - * calling. - */ - fun_wrapper (); - - /** - * Copy constructor. Made - * private and not - * implemented to prevent - * calling. - */ - fun_wrapper (const fun_wrapper &); - - /** - * Typedef for shared - * pointers to the objects - * describing threads on the - * OS level. + * Constructor. Store the + * necessary information + * about the function to be + * called and with which + * arguments. + * + * Pass down the address of + * this class's thread entry + * point function. This way, + * we can ensure that object + * and thread entry point + * function always are in + * synch with respect to + * their knowledge of the + * types involved. */ - typedef - boost::shared_ptr > - DescriptionPointer; + ThreadStarter (const boost::function &function) + : + function (function), + data_has_been_copied (false) + {} /** * Shared pointer to the * unique object describing a * thread on the OS level. */ - DescriptionPointer thread_descriptor; + boost::shared_ptr > + thread_descriptor; /** * Mutex and condition @@ -1578,14 +1579,22 @@ namespace Threads */ const boost::function &function; + /** + * A variable that indicates whether + * the called thread has copied the + * function descriptor to its own + * stack. + */ + mutable bool data_has_been_copied; + /** * Entry point for the new * thread. */ static void * entry_point (void *arg) { - const fun_wrapper *wrapper - = reinterpret_cast*> (arg); + const ThreadStarter *wrapper + = reinterpret_cast*> (arg); // copy information from // the stack of the @@ -1599,11 +1608,50 @@ namespace Threads // we have copied all the // information that is // needed + // + // note that we indicate success + // of the operation not only + // through the condition variable + // but also through + // data_has_been_copied because + // pthread_cond_wait can return + // spuriously and we need to + // check there whether the return + // is spurious or not { + wrapper->data_has_been_copied = true; ThreadMutex::ScopedLock lock (wrapper->mutex); wrapper->condition.signal (); } + // 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; + // call the // function. since an // exception that is @@ -1633,15 +1681,6 @@ namespace Threads return 0; } - - - /** - * Make the base class a - * friend, so that it can - * access the thread entry - * point function. - */ - template friend class wrapper_base; }; } @@ -1718,7 +1757,7 @@ namespace Threads class fun_encapsulator; -// ----------- encapsulators for member functions not taking any parameters +// ----------- encapsulators for function objects /** * @internal @@ -1741,7 +1780,7 @@ namespace Threads Thread operator() () { - return fun_wrapper (function).fire_up (); + return ThreadStarter::start_thread (function); } private: @@ -1769,8 +1808,10 @@ namespace Threads Thread operator() (typename boost::tuples::element<0,ArgList>::type arg1) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1))); } private: @@ -1799,9 +1840,11 @@ namespace Threads operator() (typename boost::tuples::element<0,ArgList>::type arg1, typename boost::tuples::element<1,ArgList>::type arg2) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2))); } private: @@ -1831,10 +1874,12 @@ namespace Threads typename boost::tuples::element<1,ArgList>::type arg2, typename boost::tuples::element<2,ArgList>::type arg3) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3))); } private: @@ -1865,11 +1910,13 @@ namespace Threads typename boost::tuples::element<2,ArgList>::type arg3, typename boost::tuples::element<3,ArgList>::type arg4) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3), - internal::maybe_make_boost_ref::type>::act(arg4))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3), + internal::maybe_make_boost_ref::type>::act(arg4))); } private: @@ -1901,12 +1948,14 @@ namespace Threads typename boost::tuples::element<3,ArgList>::type arg4, typename boost::tuples::element<4,ArgList>::type arg5) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3), - internal::maybe_make_boost_ref::type>::act(arg4), - internal::maybe_make_boost_ref::type>::act(arg5))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3), + internal::maybe_make_boost_ref::type>::act(arg4), + internal::maybe_make_boost_ref::type>::act(arg5))); } private: @@ -1939,13 +1988,15 @@ namespace Threads typename boost::tuples::element<4,ArgList>::type arg5, typename boost::tuples::element<5,ArgList>::type arg6) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3), - internal::maybe_make_boost_ref::type>::act(arg4), - internal::maybe_make_boost_ref::type>::act(arg5), - internal::maybe_make_boost_ref::type>::act(arg6))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3), + internal::maybe_make_boost_ref::type>::act(arg4), + internal::maybe_make_boost_ref::type>::act(arg5), + internal::maybe_make_boost_ref::type>::act(arg6))); } private: @@ -1979,14 +2030,16 @@ namespace Threads typename boost::tuples::element<5,ArgList>::type arg6, typename boost::tuples::element<6,ArgList>::type arg7) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3), - internal::maybe_make_boost_ref::type>::act(arg4), - internal::maybe_make_boost_ref::type>::act(arg5), - internal::maybe_make_boost_ref::type>::act(arg6), - internal::maybe_make_boost_ref::type>::act(arg7))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3), + internal::maybe_make_boost_ref::type>::act(arg4), + internal::maybe_make_boost_ref::type>::act(arg5), + internal::maybe_make_boost_ref::type>::act(arg6), + internal::maybe_make_boost_ref::type>::act(arg7))); } private: @@ -2021,15 +2074,17 @@ namespace Threads typename boost::tuples::element<6,ArgList>::type arg7, typename boost::tuples::element<7,ArgList>::type arg8) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3), - internal::maybe_make_boost_ref::type>::act(arg4), - internal::maybe_make_boost_ref::type>::act(arg5), - internal::maybe_make_boost_ref::type>::act(arg6), - internal::maybe_make_boost_ref::type>::act(arg7), - internal::maybe_make_boost_ref::type>::act(arg8))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3), + internal::maybe_make_boost_ref::type>::act(arg4), + internal::maybe_make_boost_ref::type>::act(arg5), + internal::maybe_make_boost_ref::type>::act(arg6), + internal::maybe_make_boost_ref::type>::act(arg7), + internal::maybe_make_boost_ref::type>::act(arg8))); } private: @@ -2065,16 +2120,18 @@ namespace Threads typename boost::tuples::element<7,ArgList>::type arg8, typename boost::tuples::element<8,ArgList>::type arg9) { - return fun_wrapper (boost::bind (function, - internal::maybe_make_boost_ref::type>::act(arg1), - internal::maybe_make_boost_ref::type>::act(arg2), - internal::maybe_make_boost_ref::type>::act(arg3), - internal::maybe_make_boost_ref::type>::act(arg4), - internal::maybe_make_boost_ref::type>::act(arg5), - internal::maybe_make_boost_ref::type>::act(arg6), - internal::maybe_make_boost_ref::type>::act(arg7), - internal::maybe_make_boost_ref::type>::act(arg8), - internal::maybe_make_boost_ref::type>::act(arg9))).fire_up (); + return + ThreadStarter::start_thread + (boost::bind (function, + internal::maybe_make_boost_ref::type>::act(arg1), + internal::maybe_make_boost_ref::type>::act(arg2), + internal::maybe_make_boost_ref::type>::act(arg3), + internal::maybe_make_boost_ref::type>::act(arg4), + internal::maybe_make_boost_ref::type>::act(arg5), + internal::maybe_make_boost_ref::type>::act(arg6), + internal::maybe_make_boost_ref::type>::act(arg7), + internal::maybe_make_boost_ref::type>::act(arg8), + internal::maybe_make_boost_ref::type>::act(arg9))); } private: -- 2.39.5