ある特定のガイドラインに従えば、スレッド化されたコードをプラグインで利用できます。以下にあげるのは、この場合の注意事項です。
MThreadPool は、タスクの割り当てが可能なスレッドのプールへのアクセスを提供します。タスクの数は、スレッドの数と同じである必要はありません。実際、負荷を分散させるには、スレッド数よりもタスク数の方が多いことが望ましいです。Maya では、最大限に効率化するために、複数のスレッドの間で内部的に作業が分散されます。プール内のスレッドの数は、論理プロセスの数と同じです。使用のたびにスレッド プールを削除する必要はありません。むしろ、平行領域が完了したときにスレッドは休止状態に入る、つまりスレッドはすばやく再起動できるので、パフォーマンス上の理由から言っても削除はしないことをお勧めします。
MThreadAsync では、長期間実行可能なスレッドを 1 つまたは複数作成することができます。これらのスレッドは MThreadPool によって作成および管理されるスレッド プールから取得されず、独立したスレッドになります。これらのスレッドを使用すると、タスクを長時間実行できます。これらはスレッド プールから作成されるものではないので、サブスクリプションの超過(活動中のスレッド数が使用可能なハードウェア リソースを超過している状態)を避けるためにも、このようなスレッドの数や負荷は慎重に管理する必要があります。
MMutexLock は、MThreadPool スレッドと MThreadAsync スレッドの両方で使用可能なロッキング プリミティブです。スレッドの標準 Mutex ロッキングが可能です。
MSpinLock はスピン待機するロックなので、ロックが非常に短時間維持されるような状況では、Mutex ロックよりも効率的です。ただし、ロックはスピン待機されるため、大量の CPU が消費されますから、長時間、ロックしたままになるような状況では使用すべきではありません。
次の例は、シリアルとスレッド化のアプローチを使用して、素数を検索する方法を示しています。スレッド化アプローチでは、MThreadPool クラスが使用されています。
#include <math.h> #include <maya/MIOStream.h> #include <maya/MSimple.h> #include <maya/MTimer.h> #include <maya/MGlobal.h> #include <maya/MThreadPool.h> DeclareSimpleCommand( threadTestCmd, PLUGIN_COMPANY, "2017"); typedef struct _threadDataTag { int threadNo; long primesFound; long start, end; } threadData; typedef struct _taskDataTag { long start, end, totalPrimes; } taskData; #define NUM_TASKS 16 // No global information used in function static bool TestForPrime(int val) { int limit, factor = 3; limit = (long)(sqrtf((float)val)+0.5f); while( (factor <= limit) && (val % factor)) factor ++; return (factor > limit); } // Primes finder. This function is called from multiple threads MThreadRetVal Primes(void *data) { threadData *myData = (threadData *)data; for( int i = myData->start + myData->threadNo*2; i <= myData->end; i += 2*NUM_TASKS ) { if( TestForPrime(i) ) myData->primesFound++; } return (MThreadRetVal)0; } // Function to create thread tasks void DecomposePrimes(void *data, MThreadRootTask *root) { taskData *taskD = (taskData *)data; threadData tdata[NUM_TASKS]; for( int i = 0; i < NUM_TASKS; ++i ) { tdata[i].threadNo = i; tdata[i].primesFound = 0; tdata[i].start = taskD->start; tdata[i].end = taskD->end; MThreadPool::createTask(Primes, (void *)&tdata[i], root); } MThreadPool::executeAndJoin(root); for( int i = 0; i < NUM_TASKS; ++i ) { taskD->totalPrimes += tdata[i].primesFound; } } // Single threaded calculation int SerialPrimes(int start, int end) { int primesFound = 0; for( int i = start; i <= end; i+=2) { if( TestForPrime(i) ) primesFound++; } return primesFound; } // Set up and tear down parallel tasks int ParallelPrimes(int start, int end) { MStatus stat = MThreadPool::init(); if( MStatus::kSuccess != stat ) { MString str = MString("Error creating threadpool"); MGlobal::displayError(str); return 0; } taskData tdata; tdata.totalPrimes = 0; tdata.start = start; tdata.end = end; MThreadPool::newParallelRegion(DecomposePrimes, (void *)&tdata); // pool is reference counted. Release reference to current thread instance MThreadPool::release(); // release reference to whole pool which deletes all threads MThreadPool::release(); return tdata.totalPrimes; } // MSimple command that invokes the serial and parallel thread calculations MStatus threadTestCmd::doIt( const MArgList& args ) { MString introStr = MString("Computation of primes using the Maya API"); MGlobal::displayInfo(introStr); if(args.length() != 2) { MString str = MString("Invalid number of arguments, usage: threadTestCmd 1 10000"); MGlobal::displayError(str); return MStatus::kFailure; } MStatus stat; int start = args.asInt( 0, &stat ); if ( MS::kSuccess != stat ) { MString str = MString("Invalid argument 1, usage: threadTestCmd 1 10000"); MGlobal::displayError(str); return MStatus::kFailure; } int end = args.asInt( 1, &stat ); if ( MS::kSuccess != stat ) { MString str = MString("Invalid argument 2, usage: threadTestCmd 1 10000"); MGlobal::displayError(str); return MStatus::kFailure; } // start search on an odd number if((start % 2) == 0 ) start++; // run single threaded MTimer timer; timer.beginTimer(); int serialPrimes = SerialPrimes(start, end); timer.endTimer(); double serialTime = timer.elapsedTime(); // run multithreaded timer.beginTimer(); int parallelPrimes = ParallelPrimes(start, end); timer.endTimer(); double parallelTime = timer.elapsedTime(); // check for correctness if ( serialPrimes != parallelPrimes ) { MString str("Error: Computations inconsistent"); MGlobal::displayError(str); return MStatus::kFailure; } // print results double ratio = serialTime/parallelTime; MString str = MString("\nElapsed time for serial computation: ") + serialTime + MString("s\n"); str += MString("Elapsed time for parallel computation: ") + parallelTime + MString("s\n"); str += MString("Speedup: ") + ratio + MString("x\n"); MGlobal::displayInfo(str); return MStatus::kSuccess; }