03-05-2008 12:47 PM
I normally use the windows SDK synchronization functions to protect data in multi threaded applications, but every now and then I use the CVI Lock functions and often run into problems for example....
I have an application that loads a DLL. Both the main application and the DLL have multiple threads. The DLL has a worker thread that gathers data, while holding a lock (call it dll_lock) and has a timer on the UI that updates the DLL's UI while also holding the lock.
The main application periodically reads some data from the DLL (from a UI Timer callback). This read function holds the dll_lock while copying the data.
The whole things runs for hours without problems until I call "RunPopupMenu" then my UI thread hangs. The UI seems to hang even if the dll's worker thread and timer are not running in which case the RunUserInterface thread is the only one getting the lock. The UI hangs on the first call to CmtGetLock(dll_lock) (in my dll when the Timer in my main applications calls the dll read function.) after calling RunPopupMenu.
The application freezes only if I have the OPT_TL_PROCESS_EVENTS_WHILE_WAITING flag set for the dll_lock. If I set the flag to 0, RunPopupMenu, doesn't hang my application, but according to the documentation for CmtNewLock, I should set the flag because I do get the lock in panel callbacks and I update panels while holding it?
Why does RunPopupMenu freeze my UI in this case when nothing else I have tested does?
So far as I can tell, the CmtGetLock function has some sort of event handler that calls a subset of the panel callbacks while blocked when the OPT_TL_PROCESS_EVENTS_WHILE_WAITING flag is set? Does this also mean that with the flag set I can have event callbacks called from a thread that is not the RunUserInterface thread? (called from the blocked CmtGetLock function on some other thread?)
Also, because event callbacks from the CmtGetLock are nested, calling CmtGetLock from multiple panel event callbacks (clicking a button a dozen time), while waiting on a lock, will happily over-flow the stack and GPF an application.
I don't think this behavior is intuitive and I think some further explanation on how the locks work is required in the documentation or a knowledge base.
03-06-2008 09:21 AM
03-06-2008 12:50 PM
I disagree that you shouldn't update UI controls from multiple threads. CVI Controls are thread safe and that is one of the stand out benefits of using CVI for data acquisition applications. I can update my time sensitive , data intensive, controls from a data acquisition thread without having to queue event messages.
I've used PostDeferredCall in some cases, but it has fallbacks. For example, when the user drags the panel around, resizes it, or just hold down the mouse button on the title bar, the dialog messages are blocked. Using PostDeferredCall queues all of the callbacks and then bursts through them. I also have to pass large amounts of data to be plotted which means I have to dynamically allocate and copy the data on a PostDeferredCall or use another very large ThreadSafeQueue. This causes my memory footprint to balloon when those events are queue.
Alternatively, I can plot the data directly to the control from my data acquisition thread. No additional memory allocation, no queued event callbacks. So far as I know, this is perfectly acceptable in CVI, though I agree would hang a Win32 application in seconds. CVI does not use Win32 controls.
03-07-2008 09:39 AM