#include <memory>
#include <math.h>
#include <maya/MIOStream.h>
#include <maya/MSimple.h>
#include <maya/MTimer.h>
#include <maya/MGlobal.h>
#include <maya/MThreadAsync.h>
#include <maya/MThreadPool.h>
#include <maya/MSpinLock.h>
#include <mutex>
#include <thread>
#include <chrono>
#define NUM_TASKS 32
#define NUM_ASYNC_TASKS 13
MThreadRetVal Pi(void *data);
typedef struct _threadDataTag
{
int threadNo;
double pi, step, *globalPi;
int start, end;
std::mutex *mutexLock;
}threadData;
typedef struct _taskDataTag
{
int iterations;
double totalPi;
}taskData;
double CalcPiSingleThreaded(int iterations)
{
double pi = 0;
double step = 1.0/double(iterations);
for( int i = 0; i < iterations; i++ )
{
double x = step * ((double)i-0.5);
pi += 4.0 / (1.0 + x*x);
}
pi /= double(iterations);
return pi;
}
MThreadRetVal Pi(void *data)
{
threadData *myData = (threadData *)data;
double pi = 0;
for( int i = myData->start; i < myData->end; i++ )
{
double x = myData->step * ((double)i-0.5);
pi += 4.0 / (1.0 + x*x);
}
myData->pi = pi;
return (MThreadRetVal)0;
}
void DecomposePi(void *data, MThreadRootTask *root)
{
taskData *taskD = (taskData *)data;
int iterationsPerTask = taskD->iterations/NUM_TASKS;
int limit;
threadData tdata[NUM_TASKS];
double step = 1.0f/taskD->iterations;
for( int i = 0; i < NUM_TASKS; ++i )
{
limit = (i+1)*iterationsPerTask;
tdata[i].threadNo = i;
tdata[i].pi = 0;
tdata[i].start = i*iterationsPerTask;
limit = tdata[i].start + iterationsPerTask;
tdata[i].end = ( limit < taskD->iterations) ? limit : taskD->iterations;
tdata[i].step = step;
}
for( int i = 0; i < NUM_TASKS; ++i )
{
taskD->totalPi += tdata[i].pi;
}
}
double CalcPi(int iterations)
{
double Pi = 0;
taskData tdata;
tdata.iterations = 0; tdata.totalPi = 0;
{
tdata.iterations = iterations;
tdata.totalPi = 0;
Pi = tdata.totalPi/iterations;
}
return Pi;
}
MThreadRetVal SpinSyncPi(void *data)
{
threadData *myData = (threadData *)data;
double pi = 0;
for( int i = myData->start; i < myData->end; i++ )
{
double x = myData->step * ((double)i-0.5);
pi += 4.0 / (1.0 + x*x);
}
myData->spinLock->lock();
(*myData->globalPi) += pi;
myData->spinLock->unlock();
return 0;
}
void DecomposeSpinSyncPi(void *data, MThreadRootTask *root)
{
taskData *taskD = (taskData *)data;
int iterationsPerTask = taskD->iterations/NUM_TASKS;
int limit;
std::unique_ptr<MSpinLock> spinLock(
new MSpinLock());
{
threadData tdata[NUM_TASKS];
double step = 1.0f/taskD->iterations;
for( int i = 0; i < NUM_TASKS; ++i )
{
limit = (i+1)*iterationsPerTask;
tdata[i].threadNo = i;
tdata[i].pi = 0;
tdata[i].globalPi = &taskD->totalPi;
tdata[i].start = i*iterationsPerTask;
limit = tdata[i].start + iterationsPerTask;
tdata[i].end = ( limit < taskD->iterations) ? limit : taskD->iterations;
tdata[i].step = step;
tdata[i].spinLock = spinLock.get();
}
for( int i = 0; i < NUM_TASKS; ++i )
{
taskD->totalPi += tdata[i].pi;
}
}
}
MThreadRetVal MutexSyncPi(void *data)
{
threadData *myData = (threadData *)data;
double pi = 0;
for( int i = myData->start; i < myData->end; i++ )
{
double x = myData->step * ((double)i-0.5);
pi += 4.0 / (1.0 + x*x);
}
myData->mutexLock->lock();
(*myData->globalPi) += pi;
myData->mutexLock->unlock();
return 0;
}
void DecomposeMutexSyncPi(void *data, MThreadRootTask *root)
{
taskData *taskD = (taskData *)data;
int iterationsPerTask = taskD->iterations/NUM_TASKS;
int limit;
std::mutex* mutexLock = new std::mutex();
{
threadData tdata[NUM_TASKS];
double step = 1.0f/taskD->iterations;
for( int i = 0; i < NUM_TASKS; ++i )
{
limit = (i+1)*iterationsPerTask;
tdata[i].threadNo = i;
tdata[i].pi = 0;
tdata[i].globalPi = &taskD->totalPi;
tdata[i].start = i*iterationsPerTask;
limit = tdata[i].start + iterationsPerTask;
tdata[i].end = ( limit < taskD->iterations) ? limit : taskD->iterations;
tdata[i].step = step;
tdata[i].mutexLock = mutexLock;
}
for( int i = 0; i < NUM_TASKS; ++i )
{
taskD->totalPi += tdata[i].pi;
}
}
delete mutexLock;
}
double CalcSpinSyncPi(int iterations)
{
double Pi = 0;
taskData tdata;
{
tdata.iterations = iterations;
tdata.totalPi = 0;
Pi = tdata.totalPi/iterations;
}
return Pi;
}
double CalcMutexSyncPi(int iterations)
{
double Pi = 0;
taskData tdata;
{
tdata.iterations = iterations;
tdata.totalPi = 0;
Pi = tdata.totalPi/iterations;
}
return Pi;
}
MThreadRetVal AsyncPi(void *data)
{
threadData *myData = (threadData *)data;
for( int i = myData->start; i < myData->end; i++ )
{
double x = myData->step * ((double)i-0.5);
myData->pi += 4.0 / (1.0 + x*x);
}
return 0;
}
static volatile int g_async_count = 0;
void AsyncCB(void *data)
{
g_async_count++;
}
bool Maya_InterlockedCompare(volatile int* variable, int compareValue)
{
bool rtn = (*variable == compareValue);
return rtn;
}
void WaitForAsyncThreads(int val)
{
while( !Maya_InterlockedCompare(&g_async_count, val)) {
std::this_thread::yield();
}
}
double CalcAsyncPi(int iterations)
{
double Pi = 0;
g_async_count = 0;
{
int iterationsPerTask = iterations/NUM_ASYNC_TASKS;
int limit;
threadData tdata[NUM_ASYNC_TASKS];
double step = 1.0f/iterations;
for( int i = 0; i < NUM_ASYNC_TASKS; ++i )
{
limit = (i+1)*iterationsPerTask;
tdata[i].threadNo = i;
tdata[i].pi = 0;
tdata[i].start = i*iterationsPerTask;
limit = tdata[i].start + iterationsPerTask;
tdata[i].end = ( limit < iterations) ? limit : iterations;
tdata[i].step = step;
{
return 0;
}
}
WaitForAsyncThreads(NUM_ASYNC_TASKS);
for( int i = 0; i < NUM_ASYNC_TASKS; ++i )
{
Pi += tdata[i].pi;
}
Pi /= iterations;
}
return Pi;
}
{
MString str =
MString(
"Invalid number of arguments, supply iteration count, usage: threadTestWithLocksCmd 100000");
}
int iterations = args.
asInt( 0, &stat );
if ( MS::kSuccess != stat ) {
MString str =
MString(
"Invalid number of arguments, supply iteration count, usage: threadTestWithLocksCmd 100000");
}
double pi = 0.0;
double elapsedTime = 0.0;
pi = CalcPiSingleThreaded(iterations);
str =
MString(
"Unthreaded computation, pi = ") + piStr +
MString(
" calculated in ") + elapsedTime +
MString(
"s");
pi = CalcPi(iterations);
str =
MString(
"Threaded computation, pi = ") + piStr +
MString(
" calculated in ") + elapsedTime +
MString(
"s");
pi = CalcSpinSyncPi(iterations);
str =
MString(
"Threaded computation with spin-lock synchronization, pi = ") + piStr +
MString(
" calculated in ") + elapsedTime +
MString(
"s");
pi = CalcMutexSyncPi(iterations);
str =
MString(
"Threaded computation with mutex synchronization, pi = ") + piStr +
MString(
" calculated in ") + elapsedTime +
MString(
"s");
pi = CalcAsyncPi(iterations);
str =
MString(
"Threaded computation with async thread, pi = ") + piStr +
MString(
" calculated in ") + elapsedTime +
MString(
"s\n");
}