LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

What causes many unknown threads to appear?

My application has multiple threads running in it.



When I was having thruput problems on my hardware, I started removing my threads one-by-one.



However, when I was down to minimal number of application threads, I was still getting threads that would not go away.



(1) main thread.


(2)OpenComConfig() caused a thread to appear?


(3) select a menu, opened two(2) threads?


(4) RunUserInterface() opened a thread?



When the minimal two application threads were running, TaskManager still indicated 4 unknown threads running (+1 main thread).



Is there a way to remove these threads? Or do I need them for my CVI application?



Do I need to add ProcessSystemEvents() all over my threads, or will the compiled code automatically round-robin my threads?

0 Kudos
Message 1 of 6
(3,900 Views)
I know that some fucntion calls in CVI spawn new threads. One of these is the AsyncTimer library another is RunUserInterface(), OpenComConfig() will do so too. I would not be too concerned about this, it's how they were written to provide better performance and should be pretty much transparent to you.

The operating system handles scheduling of threads, in Windows NT, 2000, and XP, this is done by a truly preemptive scheduler that will (eventually) give all threads some amount of time to process based upon their priority and a few other factors. As far as I know, all threads within CVI are created with normal priority unless you jump through some hoops to do otherwise. These threads all get equal priority in the thread scheduler and are serviced sequentially as their time slice comes up (that is severely oversimplified but it is generally true, there are exceptions when thread locks and blocking come into play).

ProcessSystemEvents() and ProcessDrawEvents() are only applicable to the CVI environment and have little to do with the underlying thread scheduler except to notify the scheduler that a thread is giving up some time. What those functions do is to provide a manual means of relinquishing control from the current thread back to the current RunUserInterface() thread to allow updates of the user interface and service of user generated events.

I'm certainly no expert on this, and I am sure others can answer the questions more deeply, but that should give you a general overview.
Martin Fredrickson
Test Engineer

Northrop Grumman
Advanced Systems and Products
San Diego, CA 92128
0 Kudos
Message 2 of 6
(3,892 Views)
Hi,
I might add to what MJF said. The task manager reports the thread count of all threads associated with your app. You might only programatically code you app around 5 threads, but threads from other library functions and utilities that you app needs get added to this tally. I'm not sure what your app is doing or what utilities it might be using. It would really depend. For example, one of my more complicated apps has over a dozen threads programatically, but the task manager shows 44 threads. I'm using DataSockets, FieldPoint, and SQL all in the same app.

It sounds like this is seriously bothering you, so can try to figure it out. There is a feature that allows you to switch threads in the debugger. You can set breakpoints all over your code, and when a thread halts to debug, switch threads and see what functions other threads are running.
If you aren't sure whether say, DataSockets, is the cause of some extra threads, set some breakpoints before you connect to an item and check the task manager thread count. Then open a DataSocket item, and check again. And do the same when you close the Datasocket item. If the thread count doesn't fall, then something in DataSockets is allowing the thread to stay alive. My experience is that whatever the behavior is, it is almost always repeatable.
And, please, I'm not picking on DataSockets. I don't want to be flamed by members of this group! I'm simply using it as a hypothetical example. The same method mentioned above can be used with any other function or technology.
If you are multithreading your app, you need to understand how the threading is truly working versus how you intended for it to work. If your app is built around some core technology that is overloaded in your present threading model, you might be able to change your model to relieve the bottleneck.

Orlan
0 Kudos
Message 3 of 6
(3,882 Views)
Thanks for the responses. I appreciate this discussion.

It seems like my problem thread was that one of my threads that did not manually call ProcessSystemEvents().

- My thread did not allow for CVI threads to process GUI commands. When my thread was activated (at 1Hz), GUI processing had sloooow reaction time (if any, sometimes it stopped). When I added ProcessSystemEvents(), the 1Hz thread was properly "timed out" and processing went to my other threads as what I expected in a round-robin (all threads same priority) configuration.

- As Martin mentioned, I assumed that the ProcessSystemEvents() should not have affected the scheduler's impact on the other threads. The scheduler should have timed out my ~200msec long thread (running at 1Hz), so that my other threads (one at 0.5Hz blinking an LED that reads a COM port for GPS data) could be executed. However, experimentation indicated that without the ProcessSystemEvents(), all processes did not get processor time until the 1Hz thread finished - 0.5Hz blinking did not occur until ProcessSystemEvents() was thrown all over the 1Hz thread.


void thread1Hz_notWorking()
{
~~~WaitForSingleObject(halt_event,1000)
~~~{
~~~~~~// do processing about 100msec
~~~~~~// do processing about 100msec
~~~}
}

void thread_Half_Hz()
{
~~~WaitForSingleObject(halt_event,2000)
~~~{
~~~~~~SetCtrlVal(panel, led_control, 1 );
~~~~~~// do processing
~~~~~~SetCtrlVal(panel, led_control, 0 );
~~}
}

void thread1Hz_working()
{
~~~WaitForSingleObject(halt_event,1000)
~~~{
~~~~~~// do processing about 100msec
~~~~~~ProcessSystemEvents();
~~~~~~// do processing about 100msec
~~~~~~ProcessSystemEvents();
~~~}
}



So if the CVI threads are not interfering my same-priority-threading scheme, why is the LED not blinking at 1/2 Hz, until I put ProcessSystemEvents() into the 1Hz thread? Is there another solution I am missing?

Thanks.

0 Kudos
Message 4 of 6
(3,867 Views)
I don't know this for sure, but I believe that user interface threads get a lower priority than others. This is where the ProcessSystemEvents() and ProcessDrawEvents() functions come into play.

Judicious use of those functions and putting all of your UI code in a separate thread will keep things snappy. You may also want to look into using SetSleepPolicy() to tell CVI which threads are more or less important. I generally set almost all threads to the sleep more setting.
Martin Fredrickson
Test Engineer

Northrop Grumman
Advanced Systems and Products
San Diego, CA 92128
0 Kudos
Message 5 of 6
(3,856 Views)
Hi.

Here is another solution.

You could try using asynchronous timers (see asynctmr.fp). All async timers run in a single high-priority thread, so timing is accurate and reliable.

Note that UI updates, disk reads/writes and other time-consuming operations should not be done in timer callbacks. You can signal other threads to handle these (using PostDeferredCall() or PostDeferredCallToThread()).

Regards,
Colin.
0 Kudos
Message 6 of 6
(3,841 Views)