#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
};
+
+/**
+ * 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
#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
* 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;
};
- 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
/**
* 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
* still in use.
*/
mutable ThreadMutex lock;
+
+ /**
+ * A condition variable that is
+ * used for the same purpose.
+ */
+ mutable ThreadCondition condition;
private:
/**
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
// 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
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