Open Inventor Release 2024.2.0
 
Loading...
Searching...
No Matches
Thread Local Storage (TLS)

In some cases data is stored in a class static (or even a local static) variable. This is an obvious problem for multiple threads. Making the data a non-static member variable may reduce the chances of a crash, but is still a problem because two threads could be traversing the same node at the same time.

A safe solution is to guard access to the class static data with a class static mutex. However this could significantly decrease performance because the thread that owns the mutex will block all other threads from traversing any instance of this node class. (There is also the overhead of locking and unlocking the mutex, but that is less important here.)A better solution is to use “thread local storage” (TLS) so that each thread has its own copy of the data. Effectively the data is class static in each thread and a mutex is not required. See your favorite thread programming book for a detailed discussion of TLS. Open Inventor provides a platform-independent TLS manager that makes it relatively easy to use TLS in node classes.

The Open Inventor TLS manager only uses a single “thread key.” This is
important because thread keys are a limited resource.

The following steps demonstrate how to add TLS to a node class:

  1. In the class header file, declare a thread local storage initialization method like this:

C++ :

static void initTLSClass();
  1. Also in the class header file, declare a struct that defines the variables to be in thread local storage. By convention in Open Inventor code this struct is named “MTstruct”. For example:

C++ :

struct MTstruct
{
SoSearchAction* searchAction;
SoGetMatrixAction* matrixAction;
};

There should only be one TLS struct per class.

Generally you do not need to #include additional header files in the class header file, you can just use opaque declarations like this:

C++ :

class SoSearchAction;
class SoGetMatrixAction;
  1. In the static initClass() method, reserve space for the local storage like this:

C++ :

void
myNode::initClass()
{
SO__NODE_INIT_CLASS( myNode, "myNodeClass", SoNode );
SB_THREAD_INIT_CLASS( myNode, MTstruct );
}
  1. In the initTLSClass() method, initialize the local storage like this:

C++ :

void
myNode::initTLSClass()
{
struct myNode::MTstruct* mtstruct = ( struct myNode::MTstruct* )GET_THREAD_LOCAL_STORAGE( myNode );
mtstruct->searchAction = NULL;
mtstruct->matrixAction = NULL;
}
  1. In the class source file, access the thread local storage like this:

C++ :

// Old code: static SoSearchAction *sa = NULL;
struct myNode::MTstruct* mtstruct = ( struct myNode::MTstruct* )GET_THREAD_LOCAL_STORAGE( myNode );
SoSearchAction* sa = mtstruct->searchAction;
if ( sa == NULL )
sa = new SoSearchAction;
else
sa->reset();

or access a specific variable in thread local storage like this:

C++ :

SoSearchAction* sa = ( SoSearchAction* )GET_THREAD_LOCAL_VAR( myNode, MTstruct, searchAction );

Thread Local Storage can also be used in non SoNode derivated
classes.In this case, additional macros are provided to help you integrate TLS
management in your class, like SB_THREAD_TLS_HEADER() and SB_THREAD_TLS_SOURCE(). As described
above, create an initClass() and an initTLSClass() methods to initialize local storage.