Using Thread Local Variables
- Updated2023-02-21
- 2 minute(s) read
Using Thread Local Variables
Thread local variables are similar to global variables in that they are accessible from any thread. While global variables hold a single value for all threads, thread local variables hold separate values for each thread in which they are accessed. You typically use thread local variables when your program is structured so that it performs a particular task in more than one context at the same time, spawning a secondary thread for each context. For example, if you write a parallel tester program that spawns a thread to handle each unit under test, you might use thread local variables to hold information that is specific to each unit (for example, the serial number).
Although the Windows SDK provides a mechanism for creating and accessing thread local variables, this mechanism limits the number of thread local variables you can have in each process. The LabWindows/CVI Utility Library thread local variable functions do not have this limitation. The following code demonstrates how to create and access a thread local variable that holds an integer.
volatile int quit = 0;
volatile int suspend = 0;
int main (int argc, char *argv[])
{
int functionId;
HANDLE threadHandle;
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, ThreadFunction, NULL, &functionId);
. . .
// This would typically be done in response to user input or a
// change in program state.
suspend = 1;
. . .
CmtGetThreadPoolFunctionAttribute (DEFAULT_THREAD_POOL_HANDLE, functionId, ATTR_TP_FUNCTION_THREAD_HANDLE, &threadHandle);
ResumeThread (threadHandle);
. . .
return 0;
}
int CVICALLBACK ThreadFunction (void *functionData)
{
while (!quit) {
if (suspend) {
SuspendThread (GetCurrentThread ());
suspend = 0;
}
. . .
}
return 0;
}
int CVICALLBACK ThreadFunction (void *functionData);
int tlvHandle;
int gSecondaryThreadTlvVal;
int main (int argc, char *argv[])
{
int functionId;
int *tlvPtr;
if (InitCVIRTE (0, argv, 0) == 0)
return -1; /* out of memory */
CmtNewThreadLocalVar (sizeof(int), NULL, NULL, NULL, &tlvHandle);
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, ThreadFunction, 0, &functionId);
CmtWaitForThreadPoolFunctionCompletion (DEFAULT_THREAD_POOL_HANDLE, functionId, 0);
CmtGetThreadLocalVar (tlvHandle, &tlvPtr);
(*tlvPtr)++;
// Assert that tlvPtr has been incremented only once in this thread.
assert (*tlvPtr == gSecondaryThreadTlvVal);
CmtDiscardThreadLocalVar (tlvHandle);
return 0;
}
int CVICALLBACK ThreadFunction (void *functionData)
{
int *tlvPtr;
CmtGetThreadLocalVar (tlvHandle, &tlvPtr);
(*tlvPtr)++;
gSecondaryThreadTlvVal = *tlvPtr;
return 0;
}