You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
779 lines
24 KiB
779 lines
24 KiB
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: $RCSfile: vtkMultiThreader.cxx,v $
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
#include "vtkMultiThreader.h"
|
|
|
|
#include "vtkMutexLock.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkWindows.h"
|
|
|
|
vtkCxxRevisionMacro(vtkMultiThreader, "$Revision: 1.50 $");
|
|
vtkStandardNewMacro(vtkMultiThreader);
|
|
|
|
// These are the includes necessary for multithreaded rendering on an SGI
|
|
// using the sproc() call
|
|
#ifdef VTK_USE_SPROC
|
|
#include <sys/resource.h>
|
|
#include <sys/prctl.h>
|
|
#include <wait.h>
|
|
#include <errno.h>
|
|
#endif
|
|
|
|
// Need to define "vtkExternCThreadFunctionType" to avoid warning on some
|
|
// platforms about passing function pointer to an argument expecting an
|
|
// extern "C" function. Placing the typedef of the function pointer type
|
|
// inside an extern "C" block solves this problem.
|
|
#if defined(VTK_USE_PTHREADS) || defined(VTK_HP_PTHREADS)
|
|
#include <pthread.h>
|
|
extern "C" { typedef void *(*vtkExternCThreadFunctionType)(void *); }
|
|
#else
|
|
typedef vtkThreadFunctionType vtkExternCThreadFunctionType;
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
#include <Carbon/Carbon.h>
|
|
#endif
|
|
|
|
// Initialize static member that controls global maximum number of threads
|
|
static int vtkMultiThreaderGlobalMaximumNumberOfThreads = 0;
|
|
|
|
void vtkMultiThreader::SetGlobalMaximumNumberOfThreads(int val)
|
|
{
|
|
if (val == vtkMultiThreaderGlobalMaximumNumberOfThreads)
|
|
{
|
|
return;
|
|
}
|
|
vtkMultiThreaderGlobalMaximumNumberOfThreads = val;
|
|
}
|
|
|
|
int vtkMultiThreader::GetGlobalMaximumNumberOfThreads()
|
|
{
|
|
return vtkMultiThreaderGlobalMaximumNumberOfThreads;
|
|
}
|
|
|
|
// 0 => Not initialized.
|
|
static int vtkMultiThreaderGlobalDefaultNumberOfThreads = 0;
|
|
|
|
void vtkMultiThreader::SetGlobalDefaultNumberOfThreads(int val)
|
|
{
|
|
if (val == vtkMultiThreaderGlobalDefaultNumberOfThreads)
|
|
{
|
|
return;
|
|
}
|
|
vtkMultiThreaderGlobalDefaultNumberOfThreads = val;
|
|
}
|
|
|
|
int vtkMultiThreader::GetGlobalDefaultNumberOfThreads()
|
|
{
|
|
if (vtkMultiThreaderGlobalDefaultNumberOfThreads == 0)
|
|
{
|
|
int num = 1; // default is 1
|
|
#ifdef VTK_USE_SPROC
|
|
// Default the number of threads to be the number of available
|
|
// processors if we are using sproc()
|
|
num = prctl( PR_MAXPPROCS );
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
// Default the number of threads to be the number of available
|
|
// processors if we are using pthreads()
|
|
#ifdef _SC_NPROCESSORS_ONLN
|
|
num = sysconf( _SC_NPROCESSORS_ONLN );
|
|
#elif defined(_SC_NPROC_ONLN)
|
|
num = sysconf( _SC_NPROC_ONLN );
|
|
#endif
|
|
#if defined(__SVR4) && defined(sun) && defined(PTHREAD_MUTEX_NORMAL)
|
|
pthread_setconcurrency(num);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef __APPLE__
|
|
// MPProcessors returns the physical number of processors present
|
|
// MPProcessorsScheduled returns number of active processors
|
|
num = MPProcessors();
|
|
#endif
|
|
|
|
#ifdef _WIN32
|
|
{
|
|
SYSTEM_INFO sysInfo;
|
|
GetSystemInfo(&sysInfo);
|
|
num = sysInfo.dwNumberOfProcessors;
|
|
}
|
|
#endif
|
|
|
|
#ifndef VTK_USE_WIN32_THREADS
|
|
#ifndef VTK_USE_SPROC
|
|
#ifndef VTK_USE_PTHREADS
|
|
// If we are not multithreading, the number of threads should
|
|
// always be 1
|
|
num = 1;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
// Lets limit the number of threads to VTK_MAX_THREADS
|
|
if (num > VTK_MAX_THREADS)
|
|
{
|
|
num = VTK_MAX_THREADS;
|
|
}
|
|
|
|
vtkMultiThreaderGlobalDefaultNumberOfThreads = num;
|
|
}
|
|
|
|
|
|
return vtkMultiThreaderGlobalDefaultNumberOfThreads;
|
|
}
|
|
|
|
// 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->ThreadInfoArray[i].ActiveFlag = NULL;
|
|
this->ThreadInfoArray[i].ActiveFlagLock = NULL;
|
|
this->MultipleMethod[i] = NULL;
|
|
this->SpawnedThreadActiveFlag[i] = 0;
|
|
this->SpawnedThreadActiveFlagLock[i] = NULL;
|
|
this->SpawnedThreadInfoArray[i].ThreadID = i;
|
|
}
|
|
|
|
this->SingleMethod = NULL;
|
|
this->NumberOfThreads =
|
|
vtkMultiThreader::GetGlobalDefaultNumberOfThreads();
|
|
|
|
}
|
|
|
|
// Destructor. Nothing allocated so nothing needs to be done here.
|
|
vtkMultiThreader::~vtkMultiThreader()
|
|
{
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMultiThreader::GetNumberOfThreads()
|
|
{
|
|
int num = this->NumberOfThreads;
|
|
if(vtkMultiThreaderGlobalMaximumNumberOfThreads > 0 &&
|
|
num > vtkMultiThreaderGlobalMaximumNumberOfThreads)
|
|
{
|
|
num = vtkMultiThreaderGlobalMaximumNumberOfThreads;
|
|
}
|
|
return num;
|
|
}
|
|
|
|
// Set the user defined method that will be run on NumberOfThreads threads
|
|
// when SingleMethodExecute is called.
|
|
void vtkMultiThreader::SetSingleMethod( vtkThreadFunctionType f,
|
|
void *data )
|
|
{
|
|
this->SingleMethod = f;
|
|
this->SingleData = data;
|
|
}
|
|
|
|
// Set one of the user defined methods that will be run on NumberOfThreads
|
|
// threads when MultipleMethodExecute is called. This method should be
|
|
// called with index = 0, 1, .., NumberOfThreads-1 to set up all the
|
|
// required user defined methods
|
|
void vtkMultiThreader::SetMultipleMethod( int index,
|
|
vtkThreadFunctionType f, void *data )
|
|
{
|
|
// You can only set the method for 0 through NumberOfThreads-1
|
|
if ( index >= this->NumberOfThreads )
|
|
{
|
|
vtkErrorMacro( << "Can't set method " << index <<
|
|
" with a thread count of " << this->NumberOfThreads );
|
|
}
|
|
else
|
|
{
|
|
this->MultipleMethod[index] = f;
|
|
this->MultipleData[index] = data;
|
|
}
|
|
}
|
|
|
|
// Execute the method set as the SingleMethod on NumberOfThreads threads.
|
|
void vtkMultiThreader::SingleMethodExecute()
|
|
{
|
|
int thread_loop = 0;
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
DWORD threadId;
|
|
HANDLE process_id[VTK_MAX_THREADS];
|
|
#endif
|
|
|
|
#ifdef VTK_USE_SPROC
|
|
siginfo_t info_ptr;
|
|
int process_id[VTK_MAX_THREADS];
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
pthread_t process_id[VTK_MAX_THREADS];
|
|
#endif
|
|
|
|
if ( !this->SingleMethod )
|
|
{
|
|
vtkErrorMacro( << "No single method set!" );
|
|
return;
|
|
}
|
|
|
|
// obey the global maximum number of threads limit
|
|
if (vtkMultiThreaderGlobalMaximumNumberOfThreads &&
|
|
this->NumberOfThreads > vtkMultiThreaderGlobalMaximumNumberOfThreads)
|
|
{
|
|
this->NumberOfThreads = vtkMultiThreaderGlobalMaximumNumberOfThreads;
|
|
}
|
|
|
|
|
|
// We are using sproc (on SGIs), pthreads(on Suns), or a single thread
|
|
// (the default)
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
// Using CreateThread on a PC
|
|
//
|
|
// We want to use CreateThread to start this->NumberOfThreads - 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->NumberOfThreads-1 processes. Keep track
|
|
// of their process ids for use later in the waitid call
|
|
for (thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
this->ThreadInfoArray[thread_loop].UserData = this->SingleData;
|
|
this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
|
|
process_id[thread_loop] =
|
|
CreateThread(NULL, 0, this->SingleMethod,
|
|
((void *)(&this->ThreadInfoArray[thread_loop])), 0, &threadId);
|
|
if (process_id[thread_loop] == NULL)
|
|
{
|
|
vtkErrorMacro("Error in thread creation !!!");
|
|
}
|
|
}
|
|
|
|
// Now, the parent thread calls this->SingleMethod() itself
|
|
this->ThreadInfoArray[0].UserData = this->SingleData;
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
this->SingleMethod((void *)(&this->ThreadInfoArray[0]));
|
|
|
|
// The parent thread has finished this->SingleMethod() - so now it
|
|
// waits for each of the other processes to exit
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
WaitForSingleObject(process_id[thread_loop], INFINITE);
|
|
}
|
|
|
|
// close the threads
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
CloseHandle(process_id[thread_loop]);
|
|
}
|
|
#endif
|
|
|
|
#ifdef VTK_USE_SPROC
|
|
// Using sproc() on an SGI
|
|
//
|
|
// We want to use sproc to start this->NumberOfThreads - 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->NumberOfThreads-1 processes. Keep track
|
|
// of their process ids for use later in the waitid call
|
|
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
this->ThreadInfoArray[thread_loop].UserData = this->SingleData;
|
|
this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
|
|
process_id[thread_loop] =
|
|
sproc( this->SingleMethod, PR_SADDR,
|
|
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
|
|
if ( process_id[thread_loop] == -1)
|
|
{
|
|
vtkErrorMacro("sproc call failed. Code: " << errno << endl);
|
|
}
|
|
}
|
|
|
|
// Now, the parent thread calls this->SingleMethod() itself
|
|
this->ThreadInfoArray[0].UserData = this->SingleData;
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
this->SingleMethod((void *)(&this->ThreadInfoArray[0]) );
|
|
|
|
// The parent thread has finished this->SingleMethod() - so now it
|
|
// waits for each of the other processes to exit
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED );
|
|
}
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
// Using POSIX threads
|
|
//
|
|
// We want to use pthread_create to start this->NumberOfThreads-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->NumberOfThreads-1 processes. Keep track
|
|
// of their process ids for use later in the pthread_join call
|
|
|
|
pthread_attr_t attr;
|
|
|
|
#ifdef VTK_HP_PTHREADS
|
|
pthread_attr_create( &attr );
|
|
#else
|
|
pthread_attr_init(&attr);
|
|
#if !defined(__CYGWIN__)
|
|
pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
|
|
#endif
|
|
#endif
|
|
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
this->ThreadInfoArray[thread_loop].UserData = this->SingleData;
|
|
this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
|
|
|
|
#ifdef VTK_HP_PTHREADS
|
|
pthread_create( &(process_id[thread_loop]),
|
|
attr, this->SingleMethod,
|
|
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
|
|
#else
|
|
int threadError;
|
|
threadError =
|
|
pthread_create( &(process_id[thread_loop]), &attr,
|
|
reinterpret_cast<vtkExternCThreadFunctionType>(
|
|
this->SingleMethod),
|
|
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
|
|
if (threadError != 0)
|
|
{
|
|
vtkErrorMacro(<< "Unable to create a thread. pthread_create() returned "
|
|
<< threadError);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// Now, the parent thread calls this->SingleMethod() itself
|
|
this->ThreadInfoArray[0].UserData = this->SingleData;
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
this->SingleMethod((void *)(&this->ThreadInfoArray[0]) );
|
|
|
|
// The parent thread has finished this->SingleMethod() - so now it
|
|
// waits for each of the other processes to exit
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
pthread_join( process_id[thread_loop], NULL );
|
|
}
|
|
#endif
|
|
|
|
#ifndef VTK_USE_WIN32_THREADS
|
|
#ifndef VTK_USE_SPROC
|
|
#ifndef VTK_USE_PTHREADS
|
|
// There is no multi threading, so there is only one thread.
|
|
this->ThreadInfoArray[0].UserData = this->SingleData;
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
this->SingleMethod( (void *)(&this->ThreadInfoArray[0]) );
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
void vtkMultiThreader::MultipleMethodExecute()
|
|
{
|
|
int thread_loop;
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
DWORD threadId;
|
|
HANDLE process_id[VTK_MAX_THREADS];
|
|
#endif
|
|
|
|
#ifdef VTK_USE_SPROC
|
|
siginfo_t info_ptr;
|
|
int process_id[VTK_MAX_THREADS];
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
pthread_t process_id[VTK_MAX_THREADS];
|
|
#endif
|
|
|
|
|
|
// obey the global maximum number of threads limit
|
|
if (vtkMultiThreaderGlobalMaximumNumberOfThreads &&
|
|
this->NumberOfThreads > vtkMultiThreaderGlobalMaximumNumberOfThreads)
|
|
{
|
|
this->NumberOfThreads = vtkMultiThreaderGlobalMaximumNumberOfThreads;
|
|
}
|
|
|
|
for ( thread_loop = 0; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
if ( this->MultipleMethod[thread_loop] == (vtkThreadFunctionType)NULL)
|
|
{
|
|
vtkErrorMacro( << "No multiple method set for: " << thread_loop );
|
|
return;
|
|
}
|
|
}
|
|
|
|
// We are using sproc (on SGIs), pthreads(on Suns), CreateThread
|
|
// on a PC or a single thread (the default)
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
// Using CreateThread on a PC
|
|
//
|
|
// We want to use CreateThread to start this->NumberOfThreads - 1
|
|
// additional threads which will be used to call the NumberOfThreads-1
|
|
// methods defined in this->MultipleMethods[](). The parent thread
|
|
// will call this->MultipleMethods[NumberOfThreads-1](). When it is done,
|
|
// it will wait for all the children to finish.
|
|
//
|
|
// First, start up the this->NumberOfThreads-1 processes. Keep track
|
|
// of their process ids for use later in the waitid call
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
this->ThreadInfoArray[thread_loop].UserData =
|
|
this->MultipleData[thread_loop];
|
|
this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
|
|
process_id[thread_loop] =
|
|
CreateThread(NULL, 0, this->MultipleMethod[thread_loop],
|
|
((void *)(&this->ThreadInfoArray[thread_loop])), 0, &threadId);
|
|
if (process_id[thread_loop] == NULL)
|
|
{
|
|
vtkErrorMacro("Error in thread creation !!!");
|
|
}
|
|
}
|
|
|
|
// Now, the parent thread calls the last method itself
|
|
this->ThreadInfoArray[0].UserData = this->MultipleData[0];
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
(this->MultipleMethod[0])((void *)(&this->ThreadInfoArray[0]) );
|
|
|
|
// 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 = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
WaitForSingleObject(process_id[thread_loop], INFINITE);
|
|
}
|
|
|
|
// close the threads
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
CloseHandle(process_id[thread_loop]);
|
|
}
|
|
#endif
|
|
|
|
#ifdef VTK_USE_SPROC
|
|
// Using sproc() on an SGI
|
|
//
|
|
// We want to use sproc to start this->NumberOfThreads - 1 additional
|
|
// threads which will be used to call the NumberOfThreads-1 methods
|
|
// defined in this->MultipleMethods[](). The parent thread
|
|
// will call this->MultipleMethods[NumberOfThreads-1](). When it is done,
|
|
// it will wait for all the children to finish.
|
|
//
|
|
// First, start up the this->NumberOfThreads-1 processes. Keep track
|
|
// of their process ids for use later in the waitid call
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
this->ThreadInfoArray[thread_loop].UserData =
|
|
this->MultipleData[thread_loop];
|
|
this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
|
|
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[0].UserData = this->MultipleData[0];
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
(this->MultipleMethod[0])((void *)(&this->ThreadInfoArray[0]) );
|
|
|
|
// 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 = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
waitid( P_PID, (id_t) process_id[thread_loop], &info_ptr, WEXITED );
|
|
}
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
// Using POSIX threads
|
|
//
|
|
// We want to use pthread_create to start this->NumberOfThreads - 1
|
|
// additional
|
|
// threads which will be used to call the NumberOfThreads-1 methods
|
|
// defined in this->MultipleMethods[](). The parent thread
|
|
// will call this->MultipleMethods[NumberOfThreads-1](). When it is done,
|
|
// it will wait for all the children to finish.
|
|
//
|
|
// First, start up the this->NumberOfThreads-1 processes. Keep track
|
|
// of their process ids for use later in the pthread_join call
|
|
|
|
pthread_attr_t attr;
|
|
|
|
#ifdef VTK_HP_PTHREADS
|
|
pthread_attr_create( &attr );
|
|
#else
|
|
pthread_attr_init(&attr);
|
|
#ifndef __CYGWIN__
|
|
pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
|
|
#endif
|
|
#endif
|
|
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
this->ThreadInfoArray[thread_loop].UserData =
|
|
this->MultipleData[thread_loop];
|
|
this->ThreadInfoArray[thread_loop].NumberOfThreads = this->NumberOfThreads;
|
|
#ifdef VTK_HP_PTHREADS
|
|
pthread_create( &(process_id[thread_loop]),
|
|
attr, this->MultipleMethod[thread_loop],
|
|
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
|
|
#else
|
|
pthread_create( &(process_id[thread_loop]),
|
|
&attr,
|
|
reinterpret_cast<vtkExternCThreadFunctionType>(
|
|
this->MultipleMethod[thread_loop]),
|
|
( (void *)(&this->ThreadInfoArray[thread_loop]) ) );
|
|
#endif
|
|
}
|
|
|
|
// Now, the parent thread calls the last method itself
|
|
this->ThreadInfoArray[0].UserData = this->MultipleData[0];
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
(this->MultipleMethod[0])((void *)(&this->ThreadInfoArray[0]) );
|
|
|
|
// The parent thread has finished its method - so now it
|
|
// waits for each of the other processes to exit
|
|
for ( thread_loop = 1; thread_loop < this->NumberOfThreads; thread_loop++ )
|
|
{
|
|
pthread_join( process_id[thread_loop], NULL );
|
|
}
|
|
#endif
|
|
|
|
#ifndef VTK_USE_WIN32_THREADS
|
|
#ifndef VTK_USE_SPROC
|
|
#ifndef VTK_USE_PTHREADS
|
|
// There is no multi threading, so there is only one thread.
|
|
this->ThreadInfoArray[0].UserData = this->MultipleData[0];
|
|
this->ThreadInfoArray[0].NumberOfThreads = this->NumberOfThreads;
|
|
(this->MultipleMethod[0])( (void *)(&this->ThreadInfoArray[0]) );
|
|
#endif
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
int vtkMultiThreader::SpawnThread( vtkThreadFunctionType f, void *userdata )
|
|
{
|
|
int id;
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
DWORD threadId;
|
|
#endif
|
|
|
|
for ( id = 0; id < VTK_MAX_THREADS; id++ )
|
|
{
|
|
if ( this->SpawnedThreadActiveFlagLock[id] == NULL )
|
|
{
|
|
this->SpawnedThreadActiveFlagLock[id] = vtkMutexLock::New();
|
|
}
|
|
this->SpawnedThreadActiveFlagLock[id]->Lock();
|
|
if (this->SpawnedThreadActiveFlag[id] == 0)
|
|
{
|
|
// We've got a useable thread id, so grab it
|
|
this->SpawnedThreadActiveFlag[id] = 1;
|
|
this->SpawnedThreadActiveFlagLock[id]->Unlock();
|
|
break;
|
|
}
|
|
this->SpawnedThreadActiveFlagLock[id]->Unlock();
|
|
}
|
|
|
|
if ( id >= VTK_MAX_THREADS )
|
|
{
|
|
vtkErrorMacro( << "You have too many active threads!" );
|
|
return -1;
|
|
}
|
|
|
|
this->SpawnedThreadInfoArray[id].UserData = userdata;
|
|
this->SpawnedThreadInfoArray[id].NumberOfThreads = 1;
|
|
this->SpawnedThreadInfoArray[id].ActiveFlag =
|
|
&this->SpawnedThreadActiveFlag[id];
|
|
this->SpawnedThreadInfoArray[id].ActiveFlagLock =
|
|
this->SpawnedThreadActiveFlagLock[id];
|
|
|
|
// We are using sproc (on SGIs), pthreads(on Suns or HPs),
|
|
// CreateThread (on win32), or generating an error
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
// Using CreateThread on a PC
|
|
//
|
|
this->SpawnedThreadProcessID[id] =
|
|
CreateThread(NULL, 0, f,
|
|
((void *)(&this->SpawnedThreadInfoArray[id])), 0, &threadId);
|
|
if (this->SpawnedThreadProcessID[id] == NULL)
|
|
{
|
|
vtkErrorMacro("Error in thread creation !!!");
|
|
}
|
|
#endif
|
|
|
|
#ifdef VTK_USE_SPROC
|
|
// Using sproc() on an SGI
|
|
//
|
|
this->SpawnedThreadProcessID[id] =
|
|
sproc( f, PR_SADDR, ( (void *)(&this->SpawnedThreadInfoArray[id]) ) );
|
|
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
// Using POSIX threads
|
|
//
|
|
pthread_attr_t attr;
|
|
|
|
#ifdef VTK_HP_PTHREADS
|
|
pthread_attr_create( &attr );
|
|
#else
|
|
pthread_attr_init(&attr);
|
|
#ifndef __CYGWIN__
|
|
pthread_attr_setscope(&attr, PTHREAD_SCOPE_PROCESS);
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef VTK_HP_PTHREADS
|
|
pthread_create( &(this->SpawnedThreadProcessID[id]),
|
|
attr, f,
|
|
( (void *)(&this->SpawnedThreadInfoArray[id]) ) );
|
|
#else
|
|
pthread_create( &(this->SpawnedThreadProcessID[id]),
|
|
&attr,
|
|
reinterpret_cast<vtkExternCThreadFunctionType>(f),
|
|
( (void *)(&this->SpawnedThreadInfoArray[id]) ) );
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#ifndef VTK_USE_WIN32_THREADS
|
|
#ifndef VTK_USE_SPROC
|
|
#ifndef VTK_USE_PTHREADS
|
|
// There is no multi threading, so there is only one thread.
|
|
// This won't work - so give an error message.
|
|
vtkErrorMacro( << "Cannot spawn thread in a single threaded environment!" );
|
|
this->SpawnedThreadActiveFlagLock[id]->Delete();
|
|
id = -1;
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
return id;
|
|
}
|
|
|
|
void vtkMultiThreader::TerminateThread( int threadID )
|
|
{
|
|
|
|
if ( !this->SpawnedThreadActiveFlag[threadID] )
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->SpawnedThreadActiveFlagLock[threadID]->Lock();
|
|
this->SpawnedThreadActiveFlag[threadID] = 0;
|
|
this->SpawnedThreadActiveFlagLock[threadID]->Unlock();
|
|
|
|
#ifdef VTK_USE_WIN32_THREADS
|
|
WaitForSingleObject(this->SpawnedThreadProcessID[threadID], INFINITE);
|
|
CloseHandle(this->SpawnedThreadProcessID[threadID]);
|
|
#endif
|
|
|
|
#ifdef VTK_USE_SPROC
|
|
siginfo_t info_ptr;
|
|
|
|
waitid( P_PID, (id_t) this->SpawnedThreadProcessID[threadID],
|
|
&info_ptr, WEXITED );
|
|
#endif
|
|
|
|
#ifdef VTK_USE_PTHREADS
|
|
pthread_join( this->SpawnedThreadProcessID[threadID], NULL );
|
|
#endif
|
|
|
|
#ifndef VTK_USE_WIN32_THREADS
|
|
#ifndef VTK_USE_SPROC
|
|
#ifndef VTK_USE_PTHREADS
|
|
// There is no multi threading, so there is only one thread.
|
|
// This won't work - so give an error message.
|
|
vtkErrorMacro(<< "Cannot terminate thread in single threaded environment!");
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
this->SpawnedThreadActiveFlagLock[threadID]->Delete();
|
|
this->SpawnedThreadActiveFlagLock[threadID] = NULL;
|
|
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkMultiThreaderIDType vtkMultiThreader::GetCurrentThreadID()
|
|
{
|
|
#if defined(VTK_USE_PTHREADS)
|
|
return pthread_self();
|
|
#elif defined(VTK_USE_WIN32_THREADS)
|
|
return GetCurrentThreadId();
|
|
#elif defined(VTK_USE_SPROC)
|
|
return getpid();
|
|
#else
|
|
// No threading implementation. Assume all callers are in the same
|
|
// thread.
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
int vtkMultiThreader::ThreadsEqual(vtkMultiThreaderIDType t1,
|
|
vtkMultiThreaderIDType t2)
|
|
{
|
|
#if defined(VTK_USE_PTHREADS)
|
|
return pthread_equal(t1, t2) != 0;
|
|
#elif defined(VTK_USE_WIN32_THREADS)
|
|
return t1 == t2;
|
|
#elif defined(VTK_USE_SPROC)
|
|
return t1 == t2;
|
|
#else
|
|
// No threading implementation. Assume all callers are in the same
|
|
// thread.
|
|
return 1;
|
|
#endif
|
|
}
|
|
|
|
// Print method for the multithreader
|
|
void vtkMultiThreader::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
|
|
os << indent << "Thread Count: " << this->NumberOfThreads << "\n";
|
|
os << indent << "Global Maximum Number Of Threads: " <<
|
|
vtkMultiThreaderGlobalMaximumNumberOfThreads << endl;
|
|
os << "Thread system used: " <<
|
|
#ifdef VTK_USE_PTHREADS
|
|
"PTHREADS"
|
|
#elif defined VTK_USE_SPROC
|
|
"SPROC"
|
|
#elif defined VTK_USE_WIN32_THREADS
|
|
"WIN32 Threads"
|
|
#elif defined VTK_HP_PTHREADS
|
|
"HP PThreads"
|
|
#else
|
|
"NO THREADS SUPPORT"
|
|
#endif
|
|
<< endl;
|
|
}
|
|
|