Multithreading Utilities

Availability LightWave 6.0 | Component Layout, Modeler | Header lwmtutil.h

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 10 separate mutexes. These are numbered from 0 to 9 and are passed as the second argument to lock and unlock. You might think of these as 10 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.

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);
   } LWMTUtilFuncs;
mtid = create()
Returns an LWMTUtilID that can be used by the lock and unlock functions. The return value is NULL if create fails.
destroy( mtid )
Free resources allocated by create.
ok = lock( mtid, index )
Blocks until the mutex becomes available. Returns true if successful, or false if the lock couldn't be executed for some reason. The index is an integer from 0 to 9 that identifies which of the ten mutexes to lock. If another thread has already called lock for this mutex, the calling thread waits until the other thread calls unlock.
ok = unlock( mtid, index )
Release the mutex. If another thread has been waiting for this mutex, that thread will execute. Returns true if successful, otherwise false.

Example

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 );