From 00e837f34199efe02e31a51c86ac41a1085ba3ed Mon Sep 17 00:00:00 2001 From: wolf Date: Mon, 13 Jan 2003 19:46:01 +0000 Subject: [PATCH] Make thread startup rely less on non-POSIX features: we were acquiring a mutex on one thread, and releasing it on another one. While this is documented to work on Linux, it is not necessarily so on other systems, since POSIX does not standardize this behavior. So use a condition variable instead to avoid the problem. While at it, also remove support for ACE. git-svn-id: https://svn.dealii.org/trunk@6916 0785d39b-7218-0410-832d-ea1e28bc413d --- deal.II/aclocal.m4 | 84 +-- deal.II/base/include/base/thread_management.h | 489 ++++++++++++++++-- deal.II/base/source/thread_management.cc | 74 ++- deal.II/common/Make.global_options.in | 16 - deal.II/configure.in | 3 +- deal.II/doc/development/makefiles.1.html | 26 +- deal.II/doc/news/2002/c-3-4.html | 45 ++ deal.II/doc/readme.html | 69 +-- deal.II/doc/reports/multithreading/node1.html | 16 + 9 files changed, 589 insertions(+), 233 deletions(-) diff --git a/deal.II/aclocal.m4 b/deal.II/aclocal.m4 index f367a98c82..113708c750 100644 --- a/deal.II/aclocal.m4 +++ b/deal.II/aclocal.m4 @@ -921,8 +921,11 @@ AC_DEFUN(DEAL_II_SET_MULTITHREADING_FLAGS, dnl dnl ------------------------------------------------------------- dnl Test which library the MT code shall use to support threads. -dnl We support either POSIX or ACE. If requested, then set -dnl $withmultithreading to either POSIX or to the path to ACE. +dnl We used to support either POSIX or ACE, but support for ACE +dnl has now been deleted and we only use POSIX these days. However, +dnl the code to pass another name than "posix" remains here in +dnl case someone wants to hook in support for other thread +dnl implementations dnl dnl Usage: dnl DEAL_II_CHECK_USE_MT @@ -932,8 +935,7 @@ AC_DEFUN(DEAL_II_CHECK_USE_MT, dnl [ AC_ARG_WITH(multithreading, [ --with-multithreading=name If name==posix, or no name given, then use - POSIX threads, otherwise assume use of ACE - and use given argument as path to ACE], + POSIX threads], withmultithreading=$withval, withmultithreading=no) @@ -949,17 +951,7 @@ dnl Default (i.e. no arg) means POSIX [Defined if multi-threading is to be achieved by using the POSIX functions]) else - AC_MSG_CHECKING(for ACE) - if test -d "$withmultithreading" ; then - AC_MSG_RESULT(found) - else - AC_MSG_RESULT(not found) - AC_MSG_ERROR(Invalid ACE path) - fi - AC_DEFINE(DEAL_II_USE_MT_ACE, 1, - [Defined if multi-threading is to be achieved by using - the ACE library]) - DEAL_II_SET_ACE_FLAGS + AC_MSG_ERROR(Invalid flag for --with-multithreading) fi DEAL_II_USE_MT_VAL=1 @@ -1076,32 +1068,6 @@ AC_DEFUN(DEAL_II_CHECK_POSIX_THREAD_FUNCTIONS, dnl -dnl ------------------------------------------------------------- -dnl If the MT code shall be used through ACE, we might have to -dnl adjust the compiler flags: Possibly remove -pedantic from -dnl compiler flags again, since ACE yields a lot of error messages -dnl with this flag. -dnl -dnl Usage: -dnl DEAL_II_SET_ACE_FLAGS -dnl -dnl ------------------------------------------------------------- -AC_DEFUN(DEAL_II_SET_ACE_FLAGS, dnl -[ - if test "$enablemultithreading" = yes ; then - if test "$GXX" = yes ; then - DEAL_II_CHECK_ACE_FORBIDDEN_FLAGS - if test "x$deal_II_ace_remove_pedantic" = "xyes" ; then - CXXFLAGSG="`echo $CXXFLAGSG | perl -pi -e 's/-pedantic//g;'`" - CXXFLAGSO="`echo $CXXFLAGSO | perl -pi -e 's/-pedantic//g;'`" - fi - fi - fi -]) - - - - dnl ------------------------------------------------------------- dnl Check whether some backward compatibility features are disabled dnl Usage: @@ -2472,42 +2438,6 @@ static preload_terminate_dummy dummy; -dnl ------------------------------------------------------------- -dnl When compiling with ACE thread support, there are many constructs -dnl that are not allowed in C++, or that yield warnings when compiling with -dnl -pedantic. Check this, and if that is the case, set the variables -dnl $deal_II_ace_remove_ansi and $deal_II_ace_remove_pedantic to "yes". -dnl -dnl Usage: DEAL_II_CHECK_ACE_FORBIDDEN_FLAGS -dnl -dnl ------------------------------------------------------------- -AC_DEFUN(DEAL_II_CHECK_ACE_FORBIDDEN_FLAGS, dnl -[ - AC_MSG_CHECKING(whether compilation with ACE disallows flags) - AC_LANG(C++) - CXXFLAGS="-pedantic -Werror -I$withmultithreading" - AC_TRY_COMPILE( - [ -# include -# include - ], - [], - [ - deal_II_ace_remove_pedantic="no" - ], - [ - deal_II_ace_remove_pedantic="yes" - ]) - - if test $deal_II_ace_remove_pedantic = "no" ; then - AC_MSG_RESULT(no) - else - AC_MSG_RESULT(-pedantic) - fi -]) - - - dnl ------------------------------------------------------------- dnl gcc versions up to 2.95.3 had a problem with the std::advance function, dnl when the number of steps forward was given by an unsigned number, since diff --git a/deal.II/base/include/base/thread_management.h b/deal.II/base/include/base/thread_management.h index d091a39105..59926954a1 100644 --- a/deal.II/base/include/base/thread_management.h +++ b/deal.II/base/include/base/thread_management.h @@ -22,10 +22,7 @@ #include #if DEAL_II_USE_MT == 1 -# if defined(DEAL_II_USE_MT_ACE) -# include -# include -# elif defined(DEAL_II_USE_MT_POSIX) +# if defined(DEAL_II_USE_MT_POSIX) # include # endif #endif @@ -74,6 +71,67 @@ namespace Threads }; + +/** + * This class is used in single threaded mode instead of a class + * implementing real condition variable semantics. It allows to write + * programs such that they start new threads and/or lock objects in + * multithreading mode, and use dummy thread management and + * synchronisation classes instead when running in single-thread + * mode. Specifically, the @p{spawn} functions only call the function + * but wait for it to return instead of running in on another thread, + * and the mutices do nothing really. The only reason to provide such + * a function is that the program can be compiled both in MT and + * non-MT mode without difference. + * + * In this particular case, just as with mutexes, the functions do + * nothing, and by this provide the same semantics of condition + * variables as in multi-threaded mode. + * + * @author Wolfgang Bangerth, 2003 + */ + class DummyThreadCondition + { + public: + /** + * Signal to a single listener + * that a condition has been + * met, i.e. that some data + * will now be available. Since + * in single threaded mode, + * this function of course does + * nothing. + */ + inline void signal () {}; + + /** + * Signal to multiple listener + * that a condition has been + * met, i.e. that some data + * will now be available. Since + * in single threaded mode, + * this function of course does + * nothing. + */ + inline void broadcast () {}; + + /** + * Wait for the condition to be + * signalled. Signal variables + * need to be guarded by a + * mutex which needs to be + * given to this function as an + * argument, see the man page + * of @p{posix_cond_wait} for a + * description of the + * mechanisms. Since in single + * threaded mode, this function + * of course does nothing, but + * returns immediately. + */ + inline void wait (DummyThreadMutex &) {}; + }; + /** * This class is used instead of a true thread manager class when not * using multithreading. It allows to write programs such that they @@ -183,20 +241,7 @@ namespace Threads #if DEAL_II_USE_MT == 1 -# if defined(DEAL_II_USE_MT_ACE) - /** - * In multithread mode with ACE - * enabled, we alias the mutex and - * thread management classes to the - * respective classes of the ACE - * library. Likewise for the - * barrier class. - */ - typedef ACE_Thread_Mutex ThreadMutex; - typedef ACE_Thread_Manager ThreadManager; - typedef ACE_Barrier Barrier; - -# elif defined(DEAL_II_USE_MT_POSIX) +# if defined(DEAL_II_USE_MT_POSIX) /** * Class implementing a Mutex with @@ -237,6 +282,82 @@ namespace Threads * call the POSIX functions. */ pthread_mutex_t mutex; + + /** + * Make the class implementing + * condition variables a + * friend, since it needs + * access to the + * @p{pthread_mutex_t} + * structure. + */ + friend class PosixThreadCondition; + }; + + + /** + * Class implementing a condition + * variable with the help of POSIX + * functions. The semantics of this + * class and its member functions + * are the same as those of the + * POSIX functions. + * + * @author Wolfgang Bangerth, 2003 + */ + class PosixThreadCondition + { + public: + /** + * Constructor. Initialize the + * underlying POSIX condition + * variable data structure. + */ + PosixThreadCondition (); + + /** + * Destructor. Release all + * resources. + */ + ~PosixThreadCondition (); + + /** + * Signal to a single listener + * that a condition has been + * met, i.e. that some data + * will now be available. + */ + inline void signal () { pthread_cond_signal(&cond); }; + + /** + * Signal to multiple listener + * that a condition has been + * met, i.e. that some data + * will now be available. + */ + inline void broadcast () { pthread_cond_broadcast(&cond); }; + + /** + * Wait for the condition to be + * signalled. Signal variables + * need to be guarded by a + * mutex which needs to be + * given to this function as an + * argument, see the man page + * of @p{posix_cond_wait} for a + * description of the + * mechanisms. + */ + inline void wait (PosixThreadMutex &mutex) + { pthread_cond_wait(&cond, &mutex.mutex); }; + + private: + /** + * Data object storing the + * POSIX data which we need to + * call the POSIX functions. + */ + pthread_cond_t cond; }; @@ -377,10 +498,13 @@ namespace Threads - typedef PosixThreadMutex ThreadMutex; - typedef PosixThreadManager ThreadManager; - typedef PosixThreadBarrier Barrier; - + typedef PosixThreadMutex ThreadMutex; + typedef PosixThreadCondition ThreadCondition; + typedef PosixThreadManager ThreadManager; + typedef PosixThreadBarrier Barrier; + +# else +# error Not Implemented # endif #else /** @@ -393,9 +517,10 @@ namespace Threads * threads. Likewise for the * barrier class. */ - typedef DummyThreadMutex ThreadMutex; - typedef DummyThreadManager ThreadManager; - typedef DummyBarrier Barrier; + typedef DummyThreadMutex ThreadMutex; + typedef DummyThreadCondition ThreadCondition; + typedef DummyThreadManager ThreadManager; + typedef DummyBarrier Barrier; #endif @@ -832,6 +957,12 @@ namespace Threads * still in use. */ mutable ThreadMutex lock; + + /** + * A condition variable that is + * used for the same purpose. + */ + mutable ThreadCondition condition; private: /** @@ -4832,7 +4963,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -4933,7 +5076,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5038,7 +5193,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5149,7 +5316,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5265,7 +5444,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5386,7 +5577,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5513,7 +5716,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5646,7 +5861,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5786,7 +6013,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -5930,7 +6169,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6082,7 +6333,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6198,7 +6461,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6313,7 +6588,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6432,7 +6719,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6559,7 +6858,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6693,7 +7004,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6832,7 +7155,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -6978,7 +7313,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -7132,7 +7479,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -7289,7 +7648,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -7452,7 +7823,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the @@ -7622,7 +8005,19 @@ namespace Threads // copying of parameters is done, // now we can release the lock on - // @p{fun_data} + // @p{fun_data}, by first making + // sure that the main thread is + // hanging in the condition + // variable's wait() function, + // and then signalling that the + // condition has been met, + // i.e. that the data has been + // copied. (note that there can + // be only one listener, so + // signal() is fine and we don't + // need broadcast()) + fun_data->lock.acquire (); + fun_data->condition.signal (); fun_data->lock.release (); // register new thread, call the diff --git a/deal.II/base/source/thread_management.cc b/deal.II/base/source/thread_management.cc index 242eca389b..494be8a660 100644 --- a/deal.II/base/source/thread_management.cc +++ b/deal.II/base/source/thread_management.cc @@ -131,14 +131,27 @@ namespace Threads PosixThreadMutex::PosixThreadMutex () { pthread_mutex_init (&mutex, 0); - }; + } PosixThreadMutex::~PosixThreadMutex () { pthread_mutex_destroy (&mutex); - }; + } + + + PosixThreadCondition::PosixThreadCondition () + { + pthread_cond_init (&cond, 0); + } + + + + PosixThreadCondition::~PosixThreadCondition () + { + pthread_cond_destroy (&cond); + } #ifndef DEAL_II_USE_MT_POSIX_NO_BARRIERS @@ -147,7 +160,7 @@ namespace Threads void *) { pthread_barrier_init (&barrier, 0, count); - }; + } #else @@ -167,7 +180,7 @@ namespace Threads "POSIX barriers. You will not be able to use\n" "this class, but the rest of the threading\n" "functionality is available.")); - }; + } #endif @@ -183,7 +196,7 @@ namespace Threads if (count != 1) std::abort (); #endif - }; + } @@ -205,14 +218,14 @@ namespace Threads return 1; }; #endif - }; + } PosixThreadManager::PosixThreadManager () : thread_id_list (new std::list()) - {}; + {} PosixThreadManager::~PosixThreadManager () @@ -221,7 +234,7 @@ namespace Threads // release memory wait (); delete reinterpret_cast*>(thread_id_list); - }; + } @@ -246,7 +259,7 @@ namespace Threads while (error == EAGAIN); Assert (error == 0, ExcInternalError()); - }; + } @@ -259,7 +272,7 @@ namespace Threads for (std::list::iterator i=tid_list.begin(); i != tid_list.end(); ++i) pthread_join (*i, 0); - }; + } # endif #endif @@ -320,12 +333,14 @@ namespace Threads FunEncapsulation::~FunEncapsulation () { - // wait until the data in - // fun_data_base has been copied - // and is no more needed - fun_data_base->lock.acquire(); - // now that we have got the lock, - // we can delete the data + // note that the spawn() function + // makes sure that we only get + // here if the data has already + // been copied by the spawned + // thread, so destruction is safe + // here. + // + // so do so. delete fun_data_base; fun_data_base = 0; @@ -394,16 +409,13 @@ namespace Threads fun_data.fun_data_base->lock.acquire (); // now start the new thread #if DEAL_II_USE_MT == 1 -# if defined(DEAL_II_USE_MT_ACE) - thread_manager.spawn (*fun_data.fun_data_base->thread_entry_point, - (void*)&fun_data, - THR_SCOPE_SYSTEM | THR_DETACHED); -# elif defined(DEAL_II_USE_MT_POSIX) +# if defined(DEAL_II_USE_MT_POSIX) thread_manager.spawn (*fun_data.fun_data_base->thread_entry_point, (void*)&fun_data, - 0); + 0); +# else +# error Not implemented # endif - #else // if not in MT mode, then simply // call the respective @@ -414,6 +426,22 @@ namespace Threads (void*)&fun_data, 0); #endif + + // unlock the mutex and wait for + // the condition that the data + // has been copied to be + // signalled. unlocking the mutex + // will allow the other thread to + // proceed to the signal() call, + // which we want to catch here + // + // the mutex will subsequently be + // locked again, but since we + // don't need it any more, we can + // go on unlocking it immediately + // again + fun_data.fun_data_base->condition.wait(fun_data.fun_data_base->lock); + fun_data.fun_data_base->lock.release (); } diff --git a/deal.II/common/Make.global_options.in b/deal.II/common/Make.global_options.in index 72cb31d69e..8636d7ba10 100644 --- a/deal.II/common/Make.global_options.in +++ b/deal.II/common/Make.global_options.in @@ -124,19 +124,3 @@ ifeq ($(enable-shared),yes) LDFLAGS += @LDFLAGSPIC@ endif - - -# if multithread support in the library is requested, then set the -# respective flags -ifneq ($(with-multithreading),no) - ifneq ($(with-multithreading),posix) - ACE_ROOT = $(with-multithreading) - INCLUDE += -I$(ACE_ROOT) - LIBPATH += -L$(ACE_ROOT)/ace - - lib-ACE = $(ACE_ROOT)/ace/libACE.so - LIBS += $(lib-ACE) - - vpath %.a $(ACE_ROOT) - endif -endif diff --git a/deal.II/configure.in b/deal.II/configure.in index d5c96a4bc4..640c864b79 100644 --- a/deal.II/configure.in +++ b/deal.II/configure.in @@ -140,8 +140,7 @@ DEAL_II_CHECK_MULTITHREADING DEAL_II_SET_MULTITHREADING_FLAGS AC_SUBST(enablemultithreading) -dnl Next also check whether the MT code shall be used through -dnl POSIX or ACE +dnl Next also check whether the MT code shall be used through POSIX DEAL_II_CHECK_USE_MT AC_SUBST(withmultithreading) diff --git a/deal.II/doc/development/makefiles.1.html b/deal.II/doc/development/makefiles.1.html index 081388bc2c..3843e9426d 100644 --- a/deal.II/doc/development/makefiles.1.html +++ b/deal.II/doc/development/makefiles.1.html @@ -208,8 +208,7 @@
LIBS

Additional libraries to be linked in, such as Fortran - support, the ACE library when multithreading is enabled, or - Tecplot libraries when binary output is available. + support, or Tecplot libraries when binary output is available.

@@ -371,32 +370,11 @@
  • Variables in multithreading mode

    -

    - If --with-multithreading was given to ./configure, $(INCLUDE) and - $(LIBPATH) are augmented by the ACE include and library paths, and - the following symbols are meaningful: -

    -
    ACE_ROOT
    -

    - Path to the ACE library as given to ./configure -

    -
    - - -
    lib-ACE
    -

    - Path and name of the ACE library -

    -
    - -
    with-multithreading

    This symbol is 'no' if the flag was not given - to ./configure and not 'no' (it actually equals - $(ACE_ROOT)) if -with-multithreading=... was - given + to ./configure and 'posix' otherwise

    diff --git a/deal.II/doc/news/2002/c-3-4.html b/deal.II/doc/news/2002/c-3-4.html index 6c3d7ef387..17fdaa6f58 100644 --- a/deal.II/doc/news/2002/c-3-4.html +++ b/deal.II/doc/news/2002/c-3-4.html @@ -33,6 +33,18 @@ contributor's names are abbreviated by WB (Wolfgang Bangerth), GK

    General

      +
    1. + Removed: Thread support now relies solely on the use of POSIX + functions. The use of the + ACE + (Adaptive Communications Environment) library for this is now no + longer supported. However, application programs can of course still use + ACE, but they will need to generate paths to this library in their + makefiles themselves. +
      + (WB 2003/01/11) +

      +
    2. New: Some changes have been made to support Mac OS X 10.2. Shared libraries are not supported on this architecture, but everything else @@ -222,6 +234,39 @@ contributor's names are abbreviated by WB (Wolfgang Bangerth), GK

      base

        +
      1. + Fixed: The Subscriptor uses a counter to + count how many SmartPointer objects subscribe + to the pointed-to object. This counter needs to be a volatile variable + in multithreaded mode, to avoid false compiler optimizations based on + the assumption that the variable cannot change between two subsequent + reads. +
        + (Michael Anderson, WB 2003/01/11) +

        + +
      2. + Fixed: In multithreaded mode, when a new thread is started, the + arguments to the function being called need to be copied from the stack + of the starting thread to that of the new thread. In order to + synchronise this, mutexes were used that were acquired from one thread + and released from another thread. On Linux this does not lead to + problems, but POSIX functions do not guarantee that this actually works, + and it also leads to problems when running programs under valgrind. This + is now fixed with the help of condition variables. +
        + (Michael Anderson, WB 2003/01/11) +

        + +
      3. + New: There are now classes ThreadCondition + that implement thread condition variable operations through POSIX + functions (in multithreaded mode) or doing nothing (in singlethreaded + mode). +
        + (WB 2003/01/11) +

        +
      4. New: Newer versions of gcc have a very nice feature: you can set a verbose terminate handler, that not only aborts a program diff --git a/deal.II/doc/readme.html b/deal.II/doc/readme.html index 5ab296004c..8c59af8948 100644 --- a/deal.II/doc/readme.html +++ b/deal.II/doc/readme.html @@ -38,11 +38,11 @@ developed and tested on Unix or Unix-like systems only. It can be used positively on

          -
        • Linux ELF on i386 with gcc 2.95, gcc 3.0, gcc 3.1, and Intel ICC 5.0 - and 6.0; +
        • Linux on i386 with gcc 2.95, gcc 3.0, gcc 3.1/3.2; and Intel ICC + 5.0, 6.0 and 7.0;
        • Sun Solaris 2.5, 2.6, 7, 8, and 9 on Sparc, with gcc 2.95, - gcc 3.0, and gcc 3.1; -
        • Sun Solaris 9 on Sparc in 64bit mode, with gcc 3.1.1; + gcc 3.0, and gcc 3.1/3.2; +
        • Sun Solaris 9 on Sparc in 64bit mode, with gcc 3.1.1/3.2;
        • Sun Solaris 8 on i386, with gcc 2.95;
        • FreeBSD 4.5 with gcc 2.95;
        • IBM AIX 4.2, with gcc 2.95 (with some restrictions on @@ -466,56 +466,50 @@ multi-threading. Basically, for this, different system include files have to be selected (gcc option -threads) and memory allocation has to be made thread-safe; the latter can be done - for the C++ standard containers by defining - -D__USE_MALLOC. Note that + for the C++ standard containers in gcc versions prior to 3.0 by + defining -D__USE_MALLOC. Note also that gcc's runtime library was not thread-safe prior to gcc 3.x unless you configured gcc with --enable-threads and recompiled it. Using a gcc that was not configured with this option may lead to errors in your threaded programs that are extremely hard to find. Newer - versions of gcc are thread-safe by default. + versions of gcc and their standard libraries are thread-safe by + default.

        • --with-multithreading=name: enabling multi-threading as shown above does not enable multi-threading - inside the library itself. However, there are many places in the + inside the library itself, it just sets the compiler flags to make + the generated code thread-safe. However, there are many places in the library and example programs where multi-threading can be used, and you can switch to multi-threading using this configure option.

          - To support multi-threading in a cross-platform way, two methods - are implemented that are selected by the argument given to - --with-multithreading=name: + We used to support two different ways to achieve multi-threading in a + cross-platform way, which were selected by the argument given to + --with-multithreading=name. Since after deal.II-- + 3.4 we dropped support for + the ACE (Adaptive Communications Environment) + library for cross-platform portability, there remains only one valid + value for this option:

            -
          • name=posix: in this case, POSIX functions - are used to start threads and to implement mutex and barrier +
          • name=posix: use POSIX functions to start threads and + to implement mutex, condition variable, and barrier data structures. Most systems today support POSIX, so this - should be fairly portable. If no argument is given to - --with-multithreading, then POSIX is assumed. - -
          • name=path-to-ACE: - In previous versions of - deal.II, we exclusively used the ACE (Adaptive Communications Environment) - library for cross-platform portability. This mode is still - supported for backward compatibility, although we prefer to - use POSIX. The ACE library needs to be installed separately, - and the path to its installation directory needs to be given - as argument to this option. + should be fairly portable.
          - As a rule, if the name of the argument is posix, - then POSIX threads are used. Otherwise, the configuration script - assumes that it is the path to the ACE library. + If no argument is given to --with-multithreading, then + POSIX is assumed.

          Note that the library tries to detect the number of processors - in your system in multit-thread mode, to determine a default + in your system in multi-threaded mode, to determine a default number of threads to start in some situations. We presently support this detection only on Linux, Solaris, OSF, and SGI systems. @@ -639,22 +633,9 @@ deal.II. Presently supported are the following:

            -
          • -

            The - ACE - (Adaptive Communications Environment) library: This library - can be used - to support multithreading in a cross-platform way if you say so - to the ./configure script. It also - enables programs to use interprocess communication and many - other related services using a platform independent - interface. On how to enable using this library, see the section on - Configuration Options above. -

            -
          • - It is also possible to use some subroutines from the + It is possible to use some subroutines from the Harwell Subroutine Library (HSL) to make use of some sparse direct solvers. For a description of how to diff --git a/deal.II/doc/reports/multithreading/node1.html b/deal.II/doc/reports/multithreading/node1.html index 6adecb4fb9..9d0c6456f9 100644 --- a/deal.II/doc/reports/multithreading/node1.html +++ b/deal.II/doc/reports/multithreading/node1.html @@ -98,6 +98,22 @@ directly to the applications in Section 4< [*]). + +

            +Note (2003-01-11): In this report we frequently make reference to the +ACE +(Adaptive Communications Environment) library. This library has been used +in previous versions of the library to start and control threads, and to +provide other multithreading features in a cross-platform way. We dropped +support for ACE after version 3.4 of the deal.II library +since we found that using POSIX functions instead is much simpler to +support. One of the main problems with ACE was the complicated installation, +while POSIX functions are provided by most modern system's C libraries. + +

            Since the features we used from ACE are limited to the features that POSIX +also provides for multithreading, the impact of this replacement on the +underlying foundations used in this report are minor, and can be ignored. +


            -- 2.39.5