The generic class template< class Interface> Mover
in the
namespace Multithread
is used to apply a function to
a collection of objects. It can use several threads to do this.
At the very beginning, the threads are created upon the first
call to the member function do_moves
.
The objects are placed on a queue and each thread keeps pulling objects
off the queue and executing the function until the queue is empty.
The threads then wait until the next time do_moves
is called.
This might be useful for
a wide variety of situations where one must
repeatedly run simulations
on several copies for a while,
stop to do something else like data gathering,
and resume the simulations. Upon destruction of the Mover
object, the threads are destroyed.
One big issue is what happens in case of an error.
In serial code, one can print a message and exit, or
throw an exception. It's more complicated in
multithreaded code, because you want to shut down
the other threads in a graceful manner; otherwise,
debugging can be a nightmare. This code assumes that
if an error occurs in the user-provided do_move
function, it will throw a C++ exception of the type provided
by the Interface
class. When this happens, the
thread in which the error occurs shuts down the other
threads, and rethrows the exception to be caught once more by
the user's code.
The code is used by including the header file multithread_mover.hh
,
which in turn pulls in other headers files in the same directory.
The code must also be linked to the compiled result of barrier.cc
.
Both of these files are in the src
directory.
The Interface
class, provided by the
user, must have the following members:
typename Objects_Ref
- reference to the container of objects.
Usually this will be a pointer.
typename Object
-
reference to an individual object; used in conjunction with Object_Ref. Often this will be a pointer, but one could also use an integer index, for example.
Exception
- exception type thrown by user code. This exception
type is caught by the mover code, which then shuts down the threads.
void do_move( Objects_Ref objects, unsigned int ithread, Object_Ref object)
-
this is the function executed on each object by the threads. Thread
number ithread
is the one doing the work. The threads are
numbered starting from 0.
template< class Func> void apply_to_object_refs( Func& f, Objects_Ref objects)
- this applies an arbitrary function object to all the objects
in objects
. The function object has the ()
operator overloaded
to take an argument of type Object_Ref
.
bool is_null( Objects_Ref objects)
- returns true
if
reference is to a "null" value.
void set_null( Objects_Ref& objects)
- sets reference to
a "null" value, which is used to denote an uninitialized reference.
The Mover
has the following member functions:
void set_objects( Objects_Ref)
- sets reference to object container.
void set_number_of_threads( unsigned int)
- set number of threads. If it
is not called, then only one thread is used. It's probably best not to use
more threads than number of processors.
void do_moves()
- apply the user-defined do_move
function
to all the objects.