Simbody  3.7
SimTK::ParallelExecutor Class Reference

This class is used for performing multithreaded computations. More...

+ Inheritance diagram for SimTK::ParallelExecutor:

Classes

class  Task
 Concrete subclasses of this abstract class represent tasks that can be executed by a ParallelExecutor. More...
 

Public Member Functions

 ParallelExecutor ()
 Construct a ParallelExecutor. More...
 
 ParallelExecutor (int maxThreads)
 Construct a ParallelExecutor. More...
 
ParallelExecutorclone () const
 Clone the ParallelExecutor. More...
 
void execute (Task &task, int times)
 Execute a parallel task. More...
 
int getMaxThreads () const
 Get the maximum number of thread contexts that the ParallelExecutor is currently allowed to use. More...
 
- Public Member Functions inherited from SimTK::PIMPLHandle< ParallelExecutor, ParallelExecutorImpl >
bool isEmptyHandle () const
 Returns true if this handle is empty, that is, does not refer to any implementation object. More...
 
bool isOwnerHandle () const
 Returns true if this handle is the owner of the implementation object to which it refers. More...
 
bool isSameHandle (const ParallelExecutor &other) const
 Determine whether the supplied handle is the same object as "this" PIMPLHandle. More...
 
void disown (ParallelExecutor &newOwner)
 Give up ownership of the implementation to an empty handle. More...
 
PIMPLHandlereferenceAssign (const ParallelExecutor &source)
 "Copy" assignment but with shallow (pointer) semantics. More...
 
PIMPLHandlecopyAssign (const ParallelExecutor &source)
 This is real copy assignment, with ordinary C++ object ("value") semantics. More...
 
void clearHandle ()
 Make this an empty handle, deleting the implementation object if this handle is the owner of it. More...
 
const ParallelExecutorImpl & getImpl () const
 Get a const reference to the implementation associated with this Handle. More...
 
ParallelExecutorImpl & updImpl ()
 Get a writable reference to the implementation associated with this Handle. More...
 
int getImplHandleCount () const
 Return the number of handles the implementation believes are referencing it. More...
 

Static Public Member Functions

static int getNumProcessors ()
 Get the total number of available processor cores (physical cores and hyperthreads on Intel architecture). More...
 
static bool isWorkerThread ()
 Determine whether the thread invoking this method is a worker thread created by ParallelExecutor. More...
 

Additional Inherited Members

- Public Types inherited from SimTK::PIMPLHandle< ParallelExecutor, ParallelExecutorImpl >
typedef PIMPLHandle< ParallelExecutor, ParallelExecutorImpl, false > HandleBase
 
typedef HandleBase ParentHandle
 
- Protected Member Functions inherited from SimTK::PIMPLHandle< ParallelExecutor, ParallelExecutorImpl >
 PIMPLHandle ()
 The default constructor makes this an empty handle. More...
 
 PIMPLHandle (ParallelExecutorImpl *p)
 This provides consruction of a handle referencing an existing implementation object. More...
 
 PIMPLHandle (const PIMPLHandle &source)
 The copy constructor makes either a deep (value) or shallow (reference) copy of the supplied source PIMPL object, based on whether this is a "pointer semantics" (PTR=true) or "object (value) semantics" (PTR=false, default) class. More...
 
 ~PIMPLHandle ()
 Note that the destructor is non-virtual. More...
 
PIMPLHandleoperator= (const PIMPLHandle &source)
 Copy assignment makes the current handle either a deep (value) or shallow (reference) copy of the supplied source PIMPL object, based on whether this is a "pointer sematics" (PTR=true) or "object (value) semantics" (PTR=false, default) class. More...
 
void setImpl (ParallelExecutorImpl *p)
 Set the implementation for this empty handle. More...
 
bool hasSameImplementation (const ParallelExecutor &other) const
 Determine whether the supplied handle is a reference to the same implementation object as is referenced by "this" PIMPLHandle. More...
 

Detailed Description

This class is used for performing multithreaded computations.

To use it, define a subclass of ParallelExecutor::Task that performs some computation. Then create a ParallelExecutor object and ask it to execute the task:

ParallelExecutor executor;
executor.execute(myTask, times);

The Task's execute() method will be called the specified number of times, with each invocation being given a different index value from 0 to times-1. The invocations are done in parallel on multiple threads, so you cannot make any assumptions about what order they will occur in or which ones will happen at the same time.

The threads are created in the ParallelExecutor's constructor and remain active until it is deleted. This means that creating a ParallelExecutor is a somewhat expensive operation, but it may then be used repeatedly for executing various calculations. By default, the number of threads is chosen to be equal to the number of available processor cores. You can optionally specify a different number of threads to create. For example, using more threads than processors can sometimes lead to better processor utilitization. Alternatively, if the Task will only be executed four times, you might specify min(4, ParallelExecutor::getNumProcessors()) to avoid creating extra threads that will never have any work to do.

You may find it useful to use "thread local" variables with your parallel tasks. A thread local variable may have a different value on each thread Thread-local storage is useful in many situations when writing multithreaded code. For example, it can be used as temporary workspace for calculations. If a single workspace object were created, all access to it would need to be synchronized to prevent threads from overwriting each other's values. Making a variable thread_local T means that a separate workspace object of type T will automatically be created for each thread. That object will have "thread scope" meaning it will be destructed only on thread termination.

One way to use thread local variables is to declare a static thread local member variable in your ParallelExecutor::Task:

class MyTask : public ParallelExecutor::Task {
...
public:
void execute(int index) override {
workspace += 1.0; // incremented separately on each thread.
}
private:
static thread_local double workspace;
};
// Initialize the static variable out-of-line.
thread_local double workspace = 0;

Constructor & Destructor Documentation

◆ ParallelExecutor() [1/2]

SimTK::ParallelExecutor::ParallelExecutor ( )
explicit

Construct a ParallelExecutor.

By default, constructs a ParallelExecutor with the number of threads equal to the number of total processors on the computer (including hyperthreads).

◆ ParallelExecutor() [2/2]

SimTK::ParallelExecutor::ParallelExecutor ( int  maxThreads)
explicit

Construct a ParallelExecutor.

Parameters
maxThreadsthe maximum number of threads that the ParallelExecutor is allowed to launch

Member Function Documentation

◆ clone()

ParallelExecutor* SimTK::ParallelExecutor::clone ( ) const

Clone the ParallelExecutor.

Returns
Returns a ParallelExecutor with the same number of maxThreads

◆ execute()

void SimTK::ParallelExecutor::execute ( Task task,
int  times 
)

Execute a parallel task.

Parameters
taskthe Task to execute
timesthe number of times the Task should be executed

◆ getNumProcessors()

static int SimTK::ParallelExecutor::getNumProcessors ( )
static

Get the total number of available processor cores (physical cores and hyperthreads on Intel architecture).

If the number of threads is not computable or well defined, the function returns 0.

◆ isWorkerThread()

static bool SimTK::ParallelExecutor::isWorkerThread ( )
static

Determine whether the thread invoking this method is a worker thread created by ParallelExecutor.

◆ getMaxThreads()

int SimTK::ParallelExecutor::getMaxThreads ( ) const

Get the maximum number of thread contexts that the ParallelExecutor is currently allowed to use.


The documentation for this class was generated from the following file: