Commit 790db332 authored by Lisa Avila's avatar Lisa Avila
Browse files

Added Multi Threading

parent d8affbdb
......@@ -67,6 +67,7 @@ vtkLogLookupTable \
vtkLookupTable \
vtkMath \
vtkMatrix4x4 \
vtkMultiThreader \
vtkObject \
vtkPixel \
vtkPixmap \
......
#include "vtkMultiThreader.h"
// These are the includes necessary for multithreaded rendering on an SGI
// using the sproc() call
#ifdef USE_SPROC
#include <sys/resource.h>
#include <sys/prctl.h>
#include <wait.h>
#endif
#ifdef USE_PTHREADS
#include <pthread.h>
#endif
// Description:
// Constructor. Default all the methods to NULL. Since the
// ThreadInfoArray is static, the ThreadIDs can be initialized here
// and will not change.
vtkMultiThreader::vtkMultiThreader()
{
int i;
for ( i = 0; i < VTK_MAX_THREADS; i++ )
{
this->ThreadInfoArray[i].ThreadID = i;
this->MultipleMethod[i] = NULL;
}
this->SingleMethod = NULL;
#ifdef USE_SPROC
// Default the number of threads to be the number of available
// processors if we are using sproc()
this->ThreadCount = prctl( PR_MAXPPROCS );
#endif
#ifdef USE_PTHREADS
// Default the number of threads to be the number of available
// processors if we are using pthreads()
this->ThreadCount = sysconf( _SC_NPROCESSORS_ONLN );
#endif
#ifndef USE_SPROC
#ifndef USE_PTHREADS
// If we are not multithreading, the number of threads should
// always be 1
this->ThreadCount = 1;
#endif
#endif
}
// Description:
// Destructor. Nothing allocated so nothing needs to be done here.
vtkMultiThreader::~vtkMultiThreader()
{
}
// Description:
// Set the user defined method that will be run on ThreadCount threads
// when SingleMethodExecute is called.
void vtkMultiThreader::SetSingleMethod( vtkThreadFunctionType (*f)(void *),
void *data )
{
this->SingleMethod = f;
this->SingleData = data;
}
// Description:
// Set one of the user defined methods that will be run on ThreadCount
// threads when MultipleMethodExecute is called. This method should be
// called with index = 0, 1, .., ThreadCount-1 to set up all the
// required user defined methods
void vtkMultiThreader::SetMultipleMethod( int index,
vtkThreadFunctionType (*f)(void *),
void *data )
{
// You can only set the method for 0 through ThreadCount-1
if ( index >= this->ThreadCount )
vtkErrorMacro( << "Can't set method " << index <<
" with a thread count of " << this->ThreadCount );
else
{
this->MultipleMethod[index] = f;
this->MultipleData[index] = data;
}
}
// Description:
// Execute the method set as the SingleMethod on ThreadCount threads.
void vtkMultiThreader::SingleMethodExecute()
{
#ifdef USE_SPROC
int thread_loop;
siginfo_t info_ptr;
int process_id[VTK_MAX_THREADS];
#endif
#ifdef USE_PTHREADS
int thread_loop;
pthread_t process_id[VTK_MAX_THREADS];
#endif
if ( !this->SingleMethod )
{
vtkErrorMacro( << "No single method set!" );
return;
}
// We are using sproc (on SGIs), pthreads(on Suns), or a single thread
// (the default)
#ifdef USE_SPROC
// Using sproc() on an SGI
//
// We want to use sproc to start this->ThreadCount - 1 additional
// threads which will be used to call this->SingleMethod(). The
// parent thread will also call this routine. When it is done,
// it will wait for all the children to finish.
//
// First, start up the this->ThreadCount-1 processes. Keep track
// of their process ids for use later in the waitid call
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
this->ThreadInfoArray[thread_loop].UserData = this->SingleData;
this->ThreadInfoArray[thread_loop].ThreadCount = this->ThreadCount;
process_id[thread_loop] =
sproc( this->SingleMethod, PR_SADDR,
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
}
// Now, the parent thread calls this->SingleMethod() itself
this->ThreadInfoArray[this->ThreadCount-1].UserData = this->SingleData;
this->ThreadInfoArray[this->ThreadCount-1].ThreadCount = this->ThreadCount;
this->SingleMethod(
(void *)(&this->ThreadInfoArray[this->ThreadCount-1]) );
// The parent thread has finished this->SingleMethod() - so now it
// waits for each of the other processes to exit
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED );
}
#endif
#ifdef USE_PTHREADS
// Using POSIX threads
//
// We want to use pthread_create to start this->ThreadCount - 1 additional
// threads which will be used to call this->SingleMethod(). The
// parent thread will also call this routine. When it is done,
// it will wait for all the children to finish.
//
// First, start up the this->ThreadCount-1 processes. Keep track
// of their process ids for use later in the pthread_join call
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM);
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
this->ThreadInfoArray[thread_loop].UserData = this->SingleData;
this->ThreadInfoArray[thread_loop].ThreadCount = this->ThreadCount;
pthread_create( &(process_id[thread_loop]),
&attr, this->SingleMethod,
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
}
// Now, the parent thread calls this->SingleMethod() itself
this->ThreadInfoArray[this->ThreadCount-1].UserData = this->SingleData;
this->ThreadInfoArray[this->ThreadCount-1].ThreadCount = this->ThreadCount;
this->SingleMethod(
(void *)(&this->ThreadInfoArray[this->ThreadCount - 1]) );
// The parent thread has finished this->SingleMethod() - so now it
// waits for each of the other processes to exit
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
pthread_join( process_id[thread_loop], NULL );
}
#endif
#ifndef USE_SPROC
#ifndef USE_PTHREADS
// There is no multi threading, so there is only one thread.
this->ThreadInfoArray[0].UserData = this->SingleData;
this->ThreadInfoArray[0].ThreadCount = this->ThreadCount;
this->SingleMethod( (void *)(&this->ThreadInfoArray[0]) );
#endif
#endif
}
void vtkMultiThreader::MultipleMethodExecute()
{
int thread_loop;
#ifdef USE_SPROC
siginfo_t info_ptr;
int process_id[VTK_MAX_THREADS];
#endif
#ifdef USE_PTHREADS
pthread_t process_id[VTK_MAX_THREADS];
#endif
for ( thread_loop = 0; thread_loop < this->ThreadCount; thread_loop++ )
if ( this->MultipleMethod[thread_loop] == (void *)NULL)
{
vtkErrorMacro( << "No multiple method set for: " << thread_loop );
return;
}
// We are using sproc (on SGIs), pthreads(on Suns), or a single thread
// (the default)
#ifdef USE_SPROC
// Using sproc() on an SGI
//
// We want to use sproc to start this->ThreadCount - 1 additional
// threads which will be used to call the ThreadCount-1 methods
// defined in this->MultipleMethods[](). The parent thread
// will call this->MultipleMethods[ThreadCount-1](). When it is done,
// it will wait for all the children to finish.
//
// First, start up the this->ThreadCount-1 processes. Keep track
// of their process ids for use later in the waitid call
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
this->ThreadInfoArray[thread_loop].UserData =
this->MultipleData[thread_loop];
this->ThreadInfoArray[thread_loop].ThreadCount = this->ThreadCount;
process_id[thread_loop] =
sproc( this->MultipleMethod[thread_loop], PR_SADDR,
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
}
// Now, the parent thread calls the last method itself
this->ThreadInfoArray[this->ThreadCount-1].UserData =
this->MultipleData[this->ThreadCount-1];
this->ThreadInfoArray[this->ThreadCount-1].ThreadCount = this->ThreadCount;
(this->MultipleMethod[this->ThreadCount-1])(
(void *)(&this->ThreadInfoArray[this->ThreadCount-1]) );
// The parent thread has finished its method - so now it
// waits for each of the other processes (created with sproc) to
// exit
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED );
}
#endif
#ifdef USE_PTHREADS
// Using POSIX threads
//
// We want to use pthread_create to start this->ThreadCount - 1 additional
// threads which will be used to call the ThreadCount-1 methods
// defined in this->MultipleMethods[](). The parent thread
// will call this->MultipleMethods[ThreadCount-1](). When it is done,
// it will wait for all the children to finish.
//
// First, start up the this->ThreadCount-1 processes. Keep track
// of their process ids for use later in the pthread_join call
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
this->ThreadInfoArray[thread_loop].UserData =
this->MultipleData[thread_loop];
this->ThreadInfoArray[thread_loop].ThreadCount = this->ThreadCount;
pthread_create( &(process_id[thread_loop]),
NULL, this->MultipleMethod[thread_loop],
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
}
// Now, the parent thread calls the last method itself
this->ThreadInfoArray[this->ThreadCount-1].UserData =
this->MultipleData[this->ThreadCount-1];
this->ThreadInfoArray[this->ThreadCount-1].ThreadCount = this->ThreadCount;
(this->MultipleMethod[this->ThreadCount-1])(
(void *)(&this->ThreadInfoArray[this->ThreadCount - 1]) );
// The parent thread has finished its method - so now it
// waits for each of the other processes to exit
for ( thread_loop = 0; thread_loop < this->ThreadCount-1; thread_loop++ )
{
pthread_join( process_id[thread_loop], NULL );
}
#endif
#ifndef USE_SPROC
#ifndef USE_PTHREADS
// There is no multi threading, so there is only one thread.
this->ThreadInfoArray[0].UserData = this->MultipleData[0];
this->ThreadInfoArray[0].ThreadCount = this->ThreadCount;
(this->MultipleMethod[0])( (void *)(&this->ThreadInfoArray[0]) );
#endif
#endif
}
// Description:
// Print method for the multithreader
void vtkMultiThreader::PrintSelf(ostream& os, vtkIndent indent)
{
os << indent << "Thread Count: " << this->ThreadCount << "\n";
}
// .NAME vtkMultiThreader.h - A class for performing multithreaded execution
// .SECTION Description
// vtkMultithreader is a class that provides support for multithreaded
// execution using sproc() on an SGI, or pthread_create on any platform
// supporting POSIX threads. This class can be used to execute a single
// method on multiple threads, or to specify a method per thread.
#ifndef __vtkMultiThreader_h
#define __vtkMultiThreader_h
#include "vtkObject.h"
#ifdef USE_SPROC
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef USE_PTHREADS
#include <sys/types.h>
#include <unistd.h>
#endif
// If USE_SPROC is defined, then sproc() will be used to create
// multiple threads on an SGI. If USE_PTHREADS is defined, then
// pthread_create() will be used to create multiple threads (on
// a sun, for example)
// The maximum number of threads allowed
#ifdef USE_SPROC
#define VTK_MAX_THREADS 32
#endif
#ifdef USE_PTHREADS
#define VTK_MAX_THREADS 32
#endif
#ifndef USE_SPROC
#ifndef USE_PTHREADS
#define VTK_MAX_THREADS 1
#endif
#endif
// If USE_SPROC is defined, then the multithreaded function is
// of type void. If USE_PTHREADS is defined, then the multithreaded
// function is of type void *, and returns NULL
// If neither are defined, the type is void.
#ifdef USE_SPROC
typedef void vtkThreadFunctionType;
#define VTK_THREAD_RETURN_TYPE
#endif
#ifdef USE_PTHREADS
typedef (void *) vtkThreadFunctionType;
#define VTK_THREAD_RETURN_TYPE NULL
#endif
#ifndef USE_SPROC
#ifndef USE_PTHREADS
typedef void vtkThreadFunctionType;
#define VTK_THREAD_RETURN_TYPE
#endif
#endif
// Description:
// This is the structure that is passed to the SingleMethod or
// MultipleMethod that is called during SingleMethodExecute or
// MultipleMethodExecute. It is passed in as a void *, and it is
// up to the method to cast correctly and extract the information.
// The ThreadID is a number between 0 and ThreadCount-1 that indicates
// the id of this thread. The ThreadCount is this->ThreadCount.
// The UserData is obtained from the SetSingleMethod or SetMultipleMethod
// call.
struct ThreadInfoStruct
{
int ThreadID;
int ThreadCount;
void *UserData;
};
class vtkMultiThreader : public vtkObject
{
public:
vtkMultiThreader();
~vtkMultiThreader();
char *GetClassName() {return "vtkMultiThreader";};
void PrintSelf(ostream& os, vtkIndent indent);
// Description:
// Get/Set the number of threads to create
// It will be clamped to the range 1 - VTK_MAX_THREADS, so the
// caller of this method should check that the requested number
// of threads was accepted.
vtkSetClampMacro( ThreadCount, int, 1, VTK_MAX_THREADS );
vtkGetMacro( ThreadCount, int );
// These methods are excluded from Tcl wrapping 1) because the
// wrapper barfs on them and 2) because they really shouldn't be
// called from a tcl script anyway.
//BTX
// Description:
// Execute the SingleMethod (as define by SetSingleMethod) using
// this->ThreadCount threads.
void SingleMethodExecute();
// Description:
// Execute the MultipleMethods (as define by calling SetMultipleMethod
// for each of the required this->ThreadCount methods) using
// this->ThreadCount threads.
void MultipleMethodExecute();
// Description:
// Set the SingleMethod to f() and the UserData field of the
// ThreadInfoStruct that is passed to it will be data.
// This method (and all the methods passed to SetMultipleMethod)
// must be of type vtkThreadFunctionType and must take a single argument of
// type void *.
void SetSingleMethod( vtkThreadFunctionType (*f)(void *), void *data );
// Description:
// Set the MultipleMethod at the given index to f() and the UserData
// field of the ThreadInfoStruct that is passed to it will be data.
void SetMultipleMethod( int index, vtkThreadFunctionType (*f)(void *),
void *data );
//ETX
protected:
// The number of threads to use
int ThreadCount;
// An array of thread info containing a thread id
// (0, 1, 2, .. VTK_MAX_THREADS-1), the thread count, and a pointer
// to void so that user data can be passed to each thread
ThreadInfoStruct ThreadInfoArray[VTK_MAX_THREADS];
//BTX
// The methods
vtkThreadFunctionType (*SingleMethod)( void *);
vtkThreadFunctionType (*MultipleMethod[VTK_MAX_THREADS])( void *);
//ETX
// Internal storage of the data
void *SingleData;
void *MultipleData[VTK_MAX_THREADS];
};
#endif
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment