Written by Tal Alon - May 2011
When a program is executed it is called a ‘process’. Our computer seems to run many such processes simultaneously, the Antivirus software, the web browser, file-manager, Word etc. are all running at the same time. You can activate the Task-Manager and click the ‘Processes’ tab to see the ones that are running on your computer now. This multitasking is an illusion made possible by the ability of the operating system (OS) to quickly (nanoseconds) switch between processes - suspending one process while running the others and then coming back to that process to continue its execution from where it left it. A computer with more than one CPU and the correct OS can actually perform several lines of code at the same time so that one process can run on one CPU while a second process runs on another, but the OS still has to do a lot of switching since there are more processes than CPUs.
A process can usually perform only one instruction at a time, so for example - while a for loop is executed the GUI timer will not call its callback function, and the rest of the program is stuck (even the GUI is not responsive) until the loop ends and the function exits. It is possible however to split a process into several ‘threads’ (see the sketch above) that will run simultaneously on different CPUs or be switched by the OS in a similar way to different processes. This is called Multithreading. We can then run a loop on a separate thread so that even while it iterates our GUI will stay responsive. We want to split a program into several ‘threads’ to allow it to perform more than one time-critical action at any given time, such as collecting data via a precise loop and showing the data graphically on the GUI.
In this post we present a simple way to create and run code in a separate thread.
All the functions shown here and the rest of the multithreading functions are located in Library-->Utility-->Multithreading.
The Simplest Way to Create a New Thread
The idea is rather simple, you can write a function with the special prototype:
int CVICALLBACK ThreadFunction (void *functionData);
And at any time you can instruct the program to run this function in a new and separate thread (while the main thread keeps running separately). The quickest and simplest way to do this in CVI is by using the function ‘CmtScheduleThreadPoolFunction’.
For example, If I create a thread function called 'Thread1' that looks like this (same prototype as before):
int CVICALLBACK Thread1 (void *functionData)
for (i=0 ; i<100 ; i++)
SetCtrlVal(panelHandle, PANEL_NUMERICTHERM_2, i);
I can launch it in a new thread running this function simply by writing the following line:
CmtScheduleThreadPoolFunction (DEFAULT_THREAD_POOL_HANDLE, Thread1, NULL, NULL);
After this line our process is divided into two separate threads running in parallel. The second thread terminates when the function finishes whatever it is it's doing and returns. A graphical representation of this is shown at the top of this post.
The last two arguments of ‘CmtScheduleThreadPoolFunction’ can be used for more complex operations and you can read more about it in CVI's help files (also available online).
How to Perform an Action Immediately as a Thread Exits
There are many ways to monitor the execution progress of a thread function. I will demonstrate one method which I find quite helpful.
First define a global int variable that will hold the unique thread handle:
Now instead of using ‘CmtScheduleThreadPoolFunction’ use ‘CmtScheduleThreadPoolFunctionAdv’ like this:
Where 'Thread1' is the name of the function we want to run in a new thread, 'EndFunction' is the function we want to execute when the 'Thread1' function returns and '&ThreadID1' is the address of the integer handle we declared globally before.
In this configuration the function 'EndFunction' will run automatically as soon as the thread function finshes and returns. And it will run in the thread in which ‘CmtScheduleThreadPoolFunctionAdv’ was called (usually in your case it will be the main thread). The 'EndFunction' should have a specific prototype that looks like this:
void CVICALLBACK LaunchThread2 (int poolHandle,
unsigned int event,
The next post features another important aspect of multithreading - Locks. In it I discuss the way to protect variables and shared assets by using the following functions: