LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

Thread synchronization and control

In Labwindows CVI, what is the mechanism for controlling the following:

1) avoiding spin-locking - in Visual Studio, typically spin locking is avoided by providing a "micro-break" in the thread loop by some form of wait. In VS6/VS7.net Sleep() will do the trick and the compiler will perform context switch for the thread. In the case of CVI I tried Delay() and it does not appear to work at all. CPU using is also very high when thread is running. What can someone do to fix this in CVI?
2) Thread control - Windows system32 functions supports thread control such as ResumeThread() and SuspendThread() as well as changing priority etc. The CVI api returns ID in integer form while the windows API expects thread handle. Is the CVI id same as
the thread handle. How can someone using CVI API to obtain a windows thread handle with threads created by CmtScheduleThreadPoolFunction() ?
0 Kudos
Message 1 of 7
(4,703 Views)
Hi,

Do you mean spin-locking? This refers to multi-processor environments.

Delay() is a busy wait, i.e. it does not dump the remainder of the thread's quantum. You do need to use Sleep(0) as you say.

Just ensure the Windows SDK is installed and include windows.h in your code. You can then use Sleep() and similar functions.

As regards the high CPU utilisation, my understanding is that CVI threads are always ready to run, i.e. it does not wait on OS objects so it will always take its full 20 ms quantum. If no other threads are ready to run it will steal time away from the system idle process. This is not really a problem as you just get the processor running in the CVI thread, rather than the system idle thread. If other threads become ready to run then
they will get queued by the thread scheduler in the normal way.

Other forum users may add more detail.

Regards

Jamie Fraser
0 Kudos
Message 2 of 7
(4,703 Views)
Thanks for your input James

In a couple of my threads I have a long list of serial events that has to run thru and I wish to create a suspend command to be able to pause it half way and resume from the same thread position where it last left off. Will SuspendThread() do the trick here in CVI too? Windows SuspendThread() function requires thread handle and I am not sure if CVI thread ID is the same thing (so just recasting the integer CVI ID to a windows HANDLE or I have to do some type of mapping)?
0 Kudos
Message 3 of 7
(4,703 Views)
Running a couple of thread related function panels in CVI and looking at thread ID's in Windows Performance Monitor suggest these are one and the same so you should be able the CVI ID in Windows functions. I would just give it a go.

Also, SwitchToThread() may be better than Sleep(0), although I think they do much the same thing.

Jamie
0 Kudos
Message 4 of 7
(4,703 Views)
The proper way to avoid spin-locking while waiting for a thread to terminate (i.e. become "signaled") is to use the Win32 SDK call WaitForSingleObject() or WaitForMultipleObjects(). Spin-locking, sometimes called a busy wait or a busy loop, wastes CPU cycles needlessly and is considered amateurish if not flat out stupid. You can obtain a thread handle as the returned value from _beginthreadex() which is the correct way to start a thread (NOT CreateThread()).
The main thread's handle is also available from the PROCESS_INFORMATION struct filled in as a result of the CreateProcess() function. You can get a pseudo-handle to a thread from within the thread with the GetCurrentThread() function. You almost certainly do not want to use the suspendthread() function o
r the resumethread() functions (usually used only with debuggers). You can use the Win32 SDK function Sleep() to wait a set amount of time without spinlocking. N.I. has told me various stories over the years as to how their function Delay() actually works.

A problem with CVI is how do you keep a GUI interactive for the user while using Sleep(). I usually create a wait routine that calls Sleep for 50 or 100 milliseconds at a time interspersed with ProcessSystemEvents() calls.

You can also synchronize threads with any number of other Win32 facilities, including critical sections, mutexes, semaphores, interlocked variables, and events.

I recommend "Multithreading Applications in Win32" Beveridge & Weiner, or "Advanced Windows" by Richter. Also read the Win32 SDK help info on processes and threads.

This isn't necessarily trivial stuff and you have to get it right otherwise you just make a mess.
0 Kudos
Message 5 of 7
(4,703 Views)
Thanks very much for your feedback.

I am trying to build a pause and resume button when "freezes" in-between a very long list of steps within a thread function. I tried to use CVI thread function initally to maintain company codebase compatibility. I found the CVI thread ID doesnt seemed to work as windows thread handle needed for ResumeThread() and SuspendThread(). If I must use mutex or locks than I must "sprinkle" the WaitForSingleObject() type call throughout the thread function in this case? Is there a way to avoid this ?
0 Kudos
Message 6 of 7
(4,703 Views)
N.I. hasn't made it very easy. They have tried to "help" you by coming up with some threading functions, mostly associated with managing a thread pool which will automagically create a thread for you and execute a function on it, obviating the need for you to ever "know" the actual Win32 thread handle. NI gives you a function to get a ThreadID, but that doesn't do you any good if you need the thread handle: for security purposes, you can't get the thread handle from the ThreadID. It's not clear that the NI "thread ID" is the actual native Win32 ThreadID in any event.

Are you trying to control a thread in another process, or within the same process? If you managed to create a thread within the same process, then you must have a handle for it, unless you let an NI call do it for you.

To correct my earlier response, the native Win32 SDK function CreateThread() does work just fine with the CVI C runtime environment, and it does return a handle to the created thread.

Yes, one way to implement this would be to use a single mutex or semaphore to indicate "run" or "stop" and then, at selected places in the thread function where it makes sense to pause, insert a WaitForSingleObject call. If you then set the semaphore the controlled thread would run until it hit the WaitForSingleObject call, then wait until it was released by the semaphore being cleared by the controlling thread.

If you use the Win32 SuspendThread call, you'll stop the controlled thread at some arbitrary point when the OS gets around to executing the call, though it should happen fairly quickly after you make the call. But, as we know, you'll need the actual Win32 thread handle to do this.

If you use the native Win32 SDK thread functions, you'll have to be aware of the concept of "pseudo-handles" Vs. a true handle. For example, GetCurrentThread() returns a pseudo-handle, not a true handle. A Win32 pseudo handle is only self-referrent - that is, it only functions as a handle within that thread - so it wouldn't work for you to control another thread. you can use the Win32 DuplicateHandle funciton to get a true handle that can be given to another thread.

I'd say find out where the thread that you want to control is being created and change the code if necessary to CreateThread() so you have the Win32 handle, then you can use SuspendThread() and ResumeThread().

Hope this helps.
Message 7 of 7
(4,703 Views)