]> https://gitweb.dealii.org/ - dealii-svn.git/commitdiff
Make thread startup rely less on non-POSIX features: we were acquiring a mutex on...
authorwolf <wolf@0785d39b-7218-0410-832d-ea1e28bc413d>
Mon, 13 Jan 2003 19:46:01 +0000 (19:46 +0000)
committerwolf <wolf@0785d39b-7218-0410-832d-ea1e28bc413d>
Mon, 13 Jan 2003 19:46:01 +0000 (19:46 +0000)
git-svn-id: https://svn.dealii.org/trunk@6916 0785d39b-7218-0410-832d-ea1e28bc413d

deal.II/aclocal.m4
deal.II/base/include/base/thread_management.h
deal.II/base/source/thread_management.cc
deal.II/common/Make.global_options.in
deal.II/configure.in
deal.II/doc/development/makefiles.1.html
deal.II/doc/news/2002/c-3-4.html
deal.II/doc/readme.html
deal.II/doc/reports/multithreading/node1.html

index f367a98c82e10e2060b01a5dc3664df6b76f80b9..113708c75026ff29223a3294b4c984c060cd0df5 100644 (file)
@@ -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 <ace/Thread_Manager.h>
-#  include <ace/Synch.h>
-    ],
-    [],
-    [
-      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
index d091a3910598661c194e655b80918cb16124b614..59926954a1effb91229e8572625eda4aa2ceebff 100644 (file)
 #include <iterator>
 
 #if DEAL_II_USE_MT == 1
-#  if defined(DEAL_II_USE_MT_ACE)
-#    include <ace/Thread_Manager.h>
-#    include <ace/Synch.h>
-#  elif defined(DEAL_II_USE_MT_POSIX)
+#  if defined(DEAL_II_USE_MT_POSIX)
 #    include <pthread.h>
 #  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
index 242eca389b93103c9716674f9775a749d07b3b1c..494be8a6600b520890631e26c0405d1566391aaa 100644 (file)
@@ -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<pthread_t>())
-  {};
+  {}
 
 
   PosixThreadManager::~PosixThreadManager ()
@@ -221,7 +234,7 @@ namespace Threads
                                     // release memory
     wait ();
     delete reinterpret_cast<std::list<pthread_t>*>(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<pthread_t>::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 ();
   }
 
 
index 72cb31d69eeb5ef2f8f5ec04ec9573db238742df..8636d7ba1037c8e273e5281b2a722638ab8333bf 100644 (file)
@@ -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
index d5c96a4bc4ffe7dd0bcd918056566bd00d8046f1..640c864b79c61b4b9a58158d3be05675d648bca3 100644 (file)
@@ -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)
 
index 081388bc2c7d5cfff6782ce51b42184cc675a34f..3843e9426d0c5654960129a4e296b30217ed182e 100644 (file)
       <dt> <code>LIBS</code> </dt>
       <dd> <p>
            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.
            </p>
       </dd>
 
 
     <li><h4>Variables in multithreading mode</h4>
  
-    <p>
-    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:
-
     <dl>
-      <dt> <code>ACE_ROOT</code> </dt>
-      <dd> <p>
-           Path to the ACE library as given to ./configure
-           </p>
-      </dd>
-
-
-      <dt> <code>lib-ACE</code> </dt>
-      <dd> <p>
-           Path and name of the ACE library
-           </p>
-      </dd>
-
-
       <dt> <code>with-multithreading</code> </dt>
       <dd> <p>
            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
            </p>
       </dd>
     </dl>
index 6c3d7ef38702fde66f7aa3712db7fc1e91ee1ec9..17fdaa6f58917b76703b5c44014fdf311824ab95 100644 (file)
@@ -33,6 +33,18 @@ contributor's names are abbreviated by WB (Wolfgang Bangerth), GK
 <h3>General</h3>
 
 <ol>
+  <li> <p> 
+       Removed: Thread support now relies solely on the use of POSIX
+       functions. The use of the
+       <a href="http://www.cs.wustl.edu/~schmidt/ACE.html" target="_top">ACE
+       (Adaptive Communications Environment)</a> 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.
+       <br>
+       (WB 2003/01/11)
+       </p>
+
   <li> <p> 
        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
 <h3>base</h3>
 
 <ol>
+  <li> <p> 
+       Fixed: The <code class="class">Subscriptor</code> uses a counter to
+       count how many <code class="class">SmartPointer</code> 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.
+       <br>
+       (Michael Anderson, WB 2003/01/11)
+       </p>
+
+  <li> <p> 
+       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.
+       <br>
+       (Michael Anderson, WB 2003/01/11)
+       </p>
+
+  <li> <p> 
+       New: There are now classes <code class="class">ThreadCondition</code>
+       that implement thread condition variable operations through POSIX
+       functions (in multithreaded mode) or doing nothing (in singlethreaded
+       mode).
+       <br>
+       (WB 2003/01/11)
+       </p>
+
   <li> <p> 
        New: Newer versions of gcc have a very nice feature: you can set
        a verbose terminate handler, that not only aborts a program
index 5ab296004c39c69ed0a0fa284062b3f5d7b411ce..8c59af89484ab41bca0ac37e74a249dc7696f56f 100644 (file)
     developed and tested on Unix or Unix-like systems only. It can be
     used positively on
     <ul>
-      <li>Linux ELF on i386 with gcc 2.95, gcc 3.0, gcc 3.1, and Intel ICC 5.0
-          and 6.0;
+      <li>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;
       <li>Sun Solaris 2.5, 2.6, 7, 8, and 9 on Sparc, with gcc 2.95,
-          gcc 3.0, and gcc 3.1; 
-      <li>Sun Solaris 9 on Sparc in 64bit mode, with gcc 3.1.1;
+          gcc 3.0, and gcc 3.1/3.2
+      <li>Sun Solaris 9 on Sparc in 64bit mode, with gcc 3.1.1/3.2;
       <li>Sun Solaris 8 on i386, with gcc 2.95;
       <li>FreeBSD 4.5 with gcc 2.95;
       <li>IBM AIX 4.2, with gcc 2.95 (with some restrictions on
       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
-      <code>-D__USE_MALLOC</code>. Note that 
+      for the C++ standard containers in gcc versions prior to 3.0 by
+      defining <code>-D__USE_MALLOC</code>. Note also that 
       gcc's runtime library was not thread-safe prior to gcc 3.x
       unless you configured gcc 
       with <code>--enable-threads</code> 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.
       </p>
 
     <li>
       <p>
       <code>--with-multithreading=name</code>: 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.
       </p>
 
       <p>
-      To support multi-threading in a cross-platform way, two methods
-      are implemented that are selected by the argument given to
-      <code>--with-multithreading=name</code>:
+      We used to support two different ways to achieve multi-threading in a
+      cross-platform way, which were selected by the argument given to
+      <code>--with-multithreading=name</code>. Since after <acronym>deal.II--
+      3.4</code> we dropped support for 
+      the <a href="http://www.cs.wustl.edu/~schmidt/ACE.html"
+      target="_top">ACE (Adaptive Communications Environment)</a>
+      library for cross-platform portability, there remains only one valid
+      value for this option:
       <ul>
-        <li> <code>name=posix</code>: in this case, POSIX functions
-        are used to start threads and to implement mutex and barrier
+        <li> <code>name=posix</code>: 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
-        <code>--with-multithreading</code>, then POSIX is assumed.
-
-       <li> <code>name=path-to-ACE</code>: 
-       In previous versions of
-       <acronym>deal.II</acronym>, we exclusively used the <a
-       href="http://www.cs.wustl.edu/~schmidt/ACE.html"
-       target="_top">ACE (Adaptive Communications Environment)</a>
-       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.
       </ul>
-      As a rule, if the name of the argument is <code>posix</code>,
-      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 <code>--with-multithreading</code>, then 
+      POSIX is assumed.
       </p>
 
       <p>
       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.
     <acronym>deal.II</acronym>. Presently supported are the following:
 
     <ul>
-      <li>
-      <p> The
-      <a href="http://www.cs.wustl.edu/~schmidt/ACE.html" target="_top">ACE
-      (Adaptive Communications Environment)</a> library: This library
-      can be used
-      to support multithreading in a cross-platform way if you say so
-      to the <code>./configure</code> 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
-      <a href="#configuration-options">Configuration Options</a> above.
-      </p>
-
       <li>
       <p>
-      It is also possible to use some subroutines from the
+      It is possible to use some subroutines from the
       <a href="http://www.cse.clrc.ac.uk/Activity/HSL"
       target="_top">Harwell Subroutine Library (HSL)</a> to make use
       of some sparse direct solvers. For a description of how to
index 6adecb4fb91ffea7a1561c928e12b8fb696af86e..9d0c6456f9c660ca4a0c63656e29c6e07e491eae 100644 (file)
@@ -98,6 +98,22 @@ directly to the applications in Section <A HREF="node8.html#sec:applications">4<
 <A HREF="node8.html#sec:applications"><IMG  ALIGN="BOTTOM" BORDER="1" ALT="[*]"
  SRC="../deal.II-paper/cross_ref_motif.gif"></A>). 
 
+
+<P>
+<B>Note (2003-01-11):</B> In this report we frequently make reference to the 
+<a href="http://www.cs.wustl.edu/~schmidt/ACE.html" target="_top">ACE
+(Adaptive Communications Environment)</a> 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 <acronym>deal.II</acronym> 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.
+
+<P>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.
+
 <P>
 <HR>
 <!--Navigation Panel-->

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.