Multithreading UtilitiesAvailability LightWave® 6.0 Global Call LWMTUtilFuncs *mtutil; mtutil = global( LWMTUTILFUNCS_GLOBAL, GFUSE_TRANSIENT ); The global function returns a pointer to an LWMTUtilFuncs. typedef struct st_LWMTUtilFuncs {
LWMTUtilID (*create)(void);
void (*destroy)(LWMTUtilID mtid);
int (*lock)(LWMTUtilID mtid, int mutexID);
int (*unlock)(LWMTUtilID mtid, int mutexID);
LWMTGroupID (*groupCreate)(int count);
void (*groupDestroy)(LWMTGroupID mtgrpid);
int (*groupLockMutex)(LWMTGroupID mtgrpid,int mutexID);
int (*groupUnlockMutex)(LWMTGroupID mtgrpid,int mutexID);
LWMTThreadID (*groupAddThread)(LWMTGroupID mtgrpid, LWMTThreadFunc func,int size,void *arg);
LWMTThreadID (*groupGetThreadID)(LWMTGroupID mtgrpid, int index);
int (*groupGetThreadCount)(LWMTGroupID mtgrpid);
int (*groupRun)(LWMTGroupID mtgrpid);
int (*groupBegin)(LWMTGroupID mtgrpid);
void (*groupSync)(LWMTGroupID mtgrpid);
void (*groupAbort)(LWMTGroupID mtgrpid);
void (*groupKill)(LWMTGroupID mtgrpid);
int (*groupIsDone)(LWMTGroupID mtgrpid);
int (*groupIsAborted)(LWMTGroupID mtgrpid);
int (*groupThreadResult)(LWMTGroupID mtgrpid,int index);
int (*threadCheckAbort)();
int (*threadCheckAbort)(LWMTThreadID thrdid);
int (*threadCheckRunning)(LWMTThreadID thrdid);
LWMTThreadID (*threadGetID)(void);
void* (*threadGetArg)(void);
void* (*threadGetArgByID)(LWMTThreadID thrdid);
int (*threadGetIndex)(void);
int (*threadGetIndexByID)(LWMTThreadID thrdid);
int (*threadGetThreadCount)(LWMTThreadID thrdid);
LWMTGroupID (*threadGetGroupID)(LWMTThreadID thrdid);
void (*threadSetData)(void* ptr);
void* (*threadGetData)(void);
void (*threadSleep)(int delay);
int (*groupWait)(LWMTGroupID mtgrpid,unsigned int);
LWMTRWLockID (*rwlockCreate)(void);
void (*rwlockDestroy)(LWMTRWLockID rwlock);
void (*rwlockReadLock)(LWMTRWLockID rwlock);
int (*rwlockReadLockTimeout)(LWMTRWLockID rwlock, unsigned int spintries);
void (*rwlockReadUnlock)(LWMTRWLockID rwlock);
void (*rwlockWriteLock)(LWMTRWLockID rwlock);
void (*rwlockWriteUnlock)(LWMTRWLockID rwlock);
void (*rwlockWriteToReadLock)(LWMTRWLockID rwlock);
} LWMTUtilFuncs;
Mutex-only Functions The multithreading global supplies a mutex (mutual exclusion) mechanism for managing threaded execution of your plug-in. LightWave® may invoke your plug-in from multiple threads simultaneously, which has the effect of threading your code. But when doing certain things, for example when reading and writing global data, the threads of your code should be executed one at a time, rather than all at once. The mutex mechanism is a way for the threads of your code to cooperate in waiting for one another. Think of a mutex as a dressing room, a place where a thread can have some privacy. Any time your plug-in needs to do something synchronously (one thread at a time), you ask to be let into the dressing room by calling lock. If another thread (another "you") is already in that dressing room, your thread waits until the other thread is done. Then your thread gets the dressing room, and other threads that want that dressing room must wait for you to finish. When you're finished, you call unlock. The LWMTUtilID returned by the create function allows you to use up to 129 separate mutexes. These are organized as one thread lock, numbered 0, and 128 generic locks numbered 1 to 128. The distinction is purely for organizational reasons. There is no functional difference between the locks. The number of the lock is passed as the second argument to lock and unlock. You might think of these as 129 different dressing rooms. Multithreading is a complex topic. If you're unfamiliar with it, you're encouraged to seek out a general programming text that discusses the writing of thread-safe code.
Thread Group Functions Cross-platform threading support is provided by the functions in the following
sections. Threads are powerful tools for the developer that allow simultaneous
paths of execution to exist within the same application. On single-core,
single-processor systems, threads typically execute synchronously. However, on
multi-processor (or multi-core) systems, threads will often execute in true
parallel, allowing the application to be more responsive than would be allowed
by a single-path execution model.
Thread Functions
Read/Write Lock Functions (9.5+)
History LightWave® 9.0 introduced the Thread Group and Thread support functions. LightWave® 9.5 added read/write locks. Mutex-only Example (legacy) This code fragment outlines the sequence of steps you'd take to use a mutex. #include <lwmtutil.h>
LWMTUtilFuncs *mtutil;
LWMTUtilID mtid;
mtutil = global( LWMTUTILFUNCS_GLOBAL, GFUSE_TRANSIENT );
if ( !mtutil )
...global not available, do this some other way...
/* create the mutex */
mtid = mtutil->create();
...
/* enclose critical code (code that must run synchronously) in
matching lock()/unlock() calls */
if ( mtutil->lock( mtid, 0 )) {
...do something that can't be threaded...
mtutil->unlock( mtid, 0 );
}
...
/* free the mutex when you no longer need it */
if ( mtid ) mtutil->destroy( mtid );
Mutex-only Example This code fragment illustrates the use of Thread Group functions for performing mutex-only activities. #include <lwmtutil.h>
LWMTUtilFuncs *mtutil;
LWMTGroupID mtgrpid;
mtutil = global( LWMTUTILFUNCS_GLOBAL, GFUSE_TRANSIENT );
if ( !mtutil )
...global not available, do this some other way...
// create the thread group to be used just for its mutex array
mtgrpid = mtutil->groupCreate(1);
...
// enclose critical code (code that must run synchronously) in
// matching lock()/unlock() calls
if ( mtutil->groupLockMutex( mtgrpid, 0 )) {
...do something that can't be threaded...
mtutil->groupUnlockMutex( mtgrpid, 0 );
}
...
// free the thread group when you no longer need it
if ( mtgrpid ) mtutil->groupDestroy( mtgrpid );
Threading Example The following code fragment shows an example of using threads.
#include <lwmtutil.h>
...
LWMTUtilFuncs *mtutil;
...
int my_thread_func(void *arg)
{
if(!mtutil)
return -1;
// the thread was added to the group with a NULL
// argument value, so 'arg' will be NULL. we ignore
// it.
while(!mtutil->threadCheckAbort())
{
...process thread function...
// be a well-behaved thread
mtFuncs->threadSleep(100);
}
return 0;
}
...
mtutil = global( LWMTUTILFUNCS_GLOBAL, GFUSE_TRANSIENT );
if ( !mtutil )
...global not available, do this some other way...
// create the thread group, add a thread, and launch it
LWMTGroupID mtgrpid;
mtgrpid = mtutil->groupCreate(1);
if(mtgrpid)
{
mtutil->groupAddThread(mtgrpid,my_thread_func,0,NULL);
mtutil->groupBegin(mtgrpid);
}
...
// when we're done, shut down the thread and release the group
if(mtutil && mtgrpid)
{
mtutil->groupAbort(mtgrpid);
while(!mtutil->groupIsDone(mtgrpid))
mtutil->threadSleep(100);
mtutil->groupDestroy(mtgrpid);
}
...
|