LabWindows/CVI

Monitoring and Controlling Secondary Threads

When you schedule a function to run in a secondary thread, you can monitor the execution status of the scheduled function. To obtain the execution status of a scheduled function, call CmtGetThreadPoolFunctionAttribute to get the value of the ATTR_TP_FUNCTION_EXECUTION_STATUS attribute. You also can register a callback that the thread pool calls immediately before a scheduled function executes and/or immediately after a scheduled function executes. You must use CmtScheduleThreadPoolFunctionAdv to schedule the function if you want to register such a callback.

Typically, secondary threads should finish executing before the main thread exits the program. If the main thread exits before secondary threads finish executing, the secondary threads might not get a chance to clean up resources that they allocated. Any libraries used by those secondary threads also might be denied an opportunity to clean up properly.

You can call CmtWaitForThreadPoolFunctionCompletion to wait safely for your secondary threads to finish execution before allowing your main thread to exit.

In some cases, your secondary thread function must keep performing some task until the main thread signals it to stop. In this case, the secondary thread typically performs its task inside a while loop. The while loop condition is an integer variable that the main thread sets to a nonzero value when it wants to signal the secondary thread to stop executing. The following code shows how to use a while loop to control when a secondary thread finishes executing.

volatile int quit = 0;
int main (int argc, char *argv[])
{

int functionId;
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, ThreadFunction, NULL, &functionId);
// This would typically be done inside a user interface
// Quit button callback.
quit = 1;
CmtWaitForThreadPoolFunctionCompletion (DEFAULT_THREAD_POOL_HANDLE, functionId, 0);
return 0;

}

int CVICALLBACK ThreadFunction (void *functionData)
{

while (!quit) {

. . .

}
return 0;

}

Note Note  If you use the volatile keyword, this code will function properly in an optimizing compiler such as Microsoft Visual C++. An optimizing compiler determines that nothing inside the while loop can change the value of the quit variable. Therefore, as an optimization, the compiler might use only the initial value of the quit variable in the while loop condition. Use the volatile keyword to notify the compiler that another thread might change the value of the quit variable. As a result, the compiler uses the updated value of the quit variable each time the loop executes.

Sometimes it is convenient to suspend execution of a secondary thread while the main thread is performing another task. If you suspend a thread that is executing OS code, you might leave the OS in an invalid state. Therefore, you should always call the Windows SDK function SuspendThread from the thread you want to suspend. This way, you know that the thread is not suspended while executing critical code. It is safe to call the Windows SDK function ResumeThread from another thread. The following code demonstrates how to do this.

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;

}