LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

while loop priority

 

I have a multithreaded application that runs 9 seperate while loops simultaneously.  Most of the loops are entirely contained in parallel subVIs with normal priority and execution thread set to its caller (communication is handled via queues\user events\functional globals).  Some of the loops are embedded in the top level VI itself, with their subVIs also set to normal priority\same-as-caller thread (for example, the UI loop).  However, there is one loop (embedded in the top level VI) whose sole task is to respond to a DAQmx change detection event (via a registered dynamic event wired to an event structure), sample some digital lines, and send them for processing via a queued buffer.  Due to various reasons, this event-driven (essentially interrupt-driven) digital aquisition is non-buffered (hardware-timed single-point), so it is critical that this loop have the highest priority in terms of execution, as often times this loop will need to respond, acquire, and queue data up to 50 times a second.  I have set the subVIs in this critical loop to Highest priority and to the Data Aquisition thread.  Additionally, I have programmatically set the thread priority of the application itself to High priority in Windows as shown in this KnowledgeBase article.  

Have I done everything possible to ensure that this critical loop will run as deterministically and efficiently as possible given a (non-realtime) Windows environment?  Am I missing anything else?  (see attached picture for relevant section of code)

I'm aware that instead of while loops, it might be possible to use timed loops and set priorities to them.  My concern with using this method is that the critical loop's only "wait function" (giving up thread priority) is waiting on the event structure within it.  If I used a Timed Loop, there would essentially be two points in the cycle where thread priority is released.  Additionally, if another (lower priority) timed loop is executing when my critical loop becomes ready to start again, it has to wait until the lower priority timed loop completely finishes before it can start the new cycle.  This is not the behavior I want--I want the critical loop to only wait at the event structure, ready to seize thread priority from whatever else may be running when an interrupt is generated by the DAQmx event.

 
Message 1 of 8
(7,818 Views)
You may have been talking about this as one of the options, but I wasn't sure, so I'll throw it out there:

Instead of having a timed-loop with an event structure inside of it to wait on the change detection event, you can actually set the timed-loop's timing source to be your change detection event and get rid of the event structure altogether. That should unify your problem of having event-based code with special priority requirements.

Message Edited by Jarrod S. on 07-01-2007 11:58 PM

Jarrod S.
National Instruments
Message 2 of 8
(7,777 Views)
 

A Help page with some info...

P.S. Fantastic looking code.

 

Message Edited by Jarrod S. on 07-02-2007 12:02 AM

Jarrod S.
National Instruments
0 Kudos
Message 3 of 8
(7,774 Views)
Ah yes, I didn't think to make the DAQmx task the timing source itself.  A couple of concerns before I begin transitioning the code...

1)  I already have a fully configured Digital Change Detection task set up for the lines I want to monitor.  So when use the "DAQmx Create Timing Source" subVI, I'd like to select the "Signal from Task" option and use the "Change Detection Event" option wired "signal" input.  That seems like the appropriate settings given the way I registered the event in the current code.  Or do I use the "Sample Clock" option on the "signal" input?  This is in contrast to using the "Digital Change Detection" mode of the subVI to directly create a timing source from the lines (as shown in the "Event Response.vi" example from the Example Finder).  Also, I have a counter task whose sample clock is the change detection event, so I could create a timing source from this task as well ("Signal from Task" mode, "Sample Clock" option).  Is any particular route better\more efficient?

2)  Accoding to the "DAQmx Create Timing Source" subVI help, whatever task is wired is started automatically when the code reaches the timed loop.  This is a bit problematic for me, as I would like to dynamically turn on and turn off the task based on user input (the current way I've created the code--as a dynamically regestered DAQmx event--allows for this).  Is there any way to preserve this functionality using a timed loop?

3)  If I transition other loops in this program (some hidden in the "engine" subVIs) and set timed loop priorities, I am still concerned that the critical loop may be stuck waiting for other (lower priority) timed loops to finish executing, regardless of how the subVI priorities are assigned.  According to the LabView help on timed structure priorities, once the priority of pending structures are compared, the selected structure must completely execute before the next structure starts.  So if my critical loop and another loop want to start at the same time, then the critical loop will completely execute before the other, which is good.  But once the critical loop finishes executing, it has to go back into the timed structure "queue," meaning that it must wait for any currently running (lower priority) timed structure to completely finish before it can start again (even if the priority of the critical loop allows it to jump to the head of the queue).  Or, because the critical loop is based on an irregular timing source, it will sit there waiting (until it timeouts) to iterate, and thus block lower priority loops.  It's all a little confusing--the help is not absolutely clear, and I'm not sure I want to spend a bunch of time creating example code to test all the possible behaviors.  Things are clearer (for the time being) using while loops: in the case of parallel while loops, I imagine that the critical loop can interrupt a lower priority loop even if that loop has not finished its current iteration, given that the critical while loop subVIs are set to higher priority than the other while loops.  Clarification on timed structures is needed.

P.S.  Thanks for the complement--this code will eventually be passed on to others to read and perhaps modify, so I spent the time to make a concise and easily readable\understandable architecture.
0 Kudos
Message 4 of 8
(7,741 Views)


@Yuri33 wrote:

3)  If I transition other loops in this program (some hidden in the "engine" subVIs) and set timed loop priorities, I am still concerned that the critical loop may be stuck waiting for other (lower priority) timed loops to finish executing, regardless of how the subVI priorities are assigned.  According to the LabView help on timed structure priorities, once the priority of pending structures are compared, the selected structure must completely execute before the next structure starts.  So if my critical loop and another loop want to start at the same time, then the critical loop will completely execute before the other, which is good.  But once the critical loop finishes executing, it has to go back into the timed structure "queue," meaning that it must wait for any currently running (lower priority) timed structure to completely finish before it can start again (even if the priority of the critical loop allows it to jump to the head of the queue). 



Let me start with this point first. I don't believe this is true, so if you could point out the Help documentation that seems to imply this, I would appreciate it. I looked through the Timed Loop help regarding priorities and I did find a sentence that made mention to the fact that a lower priority process couldn't start to execute until a higher priority process had finished executing. But I believe higher priority Timed Loops can and will preempt lower priority loops at any time, regardless of the lower priority loop's execution status.
Jarrod S.
National Instruments
0 Kudos
Message 5 of 8
(7,722 Views)
From the LV 8.2 Help, "Setting the Priority of a Timed Structure:"


You can assign a priority for each frame of a Timed Sequence or Timed Loop with frames. When you run a VI that contains timed structures, LabVIEW checks the priority of any frame ready to execute on the block diagram and starts the frame with the highest priority.

The following block diagram contains a Timed Loop and a Timed Sequence. The Priority value of the first frame of the Timed Sequence (200) is higher than the priority of the Timed Loop (100) and therefore executes first.

(multiple timed structures block diagram)

After the first frame of the Timed Sequence executes, LabVIEW compares the priority of other structures or frames that are ready to execute. The priority of the Timed Loop (100) is higher than the priority of the second frame of the Timed Sequence (50). LabVIEW executes an iteration of the Timed Loop and then compares the priority of the structures or frames that are ready to execute. The Timed Loop priority (100) is higher than the second frame of the Timed Sequence (50). In this example, the Timed Loop will execute completely before the second frame of the Timed Sequence executes.



Maybe I'm misreading the explanation.  The way it seems to be explained above, either 1) the higher priority loop must wait for the lower priority frame to finish before it can start again (as I thought), or 2) the lower priority frame never executes, as the higher priority loop keeps going to the head of the queue.  If higher priority timed loops can interrupt lower priorty loops even while they are executing, then that issue is resolved.  That still leaves the other two, however.
0 Kudos
Message 6 of 8
(7,718 Views)
The key line to read here is "frames that are ready to execute." The higher priority loop is set to run at a specific rate. The time between when it finishes one iteration and starts the next is the time in which lower priority loops can execute. If there is no time left over, then you can run into a situation called thread starvation, where lower priority background tasks never run. They are literally starved of processor time.

In summary: higher priority loops will always preempt lower priority tasks, so make sure they leave some time between iterations for the lower priority tasks to execute.
Jarrod S.
National Instruments
0 Kudos
Message 7 of 8
(7,707 Views)
Okay, so since my critical loop's timing source is the change detection events, the "downtime" would be when the loop is waiting for an event, correct?  This would be only the time other loops would be free to run, and those loops would be pre-empted mid-iteration if a change detection event occurs.  So as long as the execution of the loop itself is fast (relative to the average time between events), then plenty of processor time would be left for other loops.  This I think is doable, since the only function of the critical loop is to read the digital lines, latch a counter, and enque that data for processing in a lower priority loop.

There is still the issue with starting and stopping the task, however.  If that can be worked out, I think I'm convinced that the timed loop is the best way to go.

Thanks for all your input so far.

Message Edited by Yuri33 on 07-02-2007 11:51 AM

0 Kudos
Message 8 of 8
(7,703 Views)