Jump to content

Q's - Whats all the fuss about


Recommended Posts

QUOTE (Mark Yedinak @ Apr 21 2009, 12:45 AM)

Done.

QUOTE (Mark Yedinak @ Apr 21 2009, 12:45 AM)

Creating parallel tasks in C or C++ is not a trivial task. You have to manually create your processes and threads. In LabVIEW this is all done for you. Drop two loops next to each other and you have parallel code. It is as simple as that.

I will concede Labview "parallelism" but I I think we are talking about concurrency and I would wholeheartedly agree that labview runs concurrent tasks but not parallel code. But it's not an area I'm an expert in and perhaps I'm being too pedantic (I don't really care how it works as long as it does...lol).

You are right though multithreading in C++ is not trivial. It is in Delphi though :)

QUOTE (Mark Yedinak @ Apr 21 2009, 12:45 AM)

. Since you already use notifiers it shouldn't be too difficult for you to use queues.

I see events rather differently.

Events (to me) are analogous to interrupts. Events can occur in any order and at any time and, on invocation, handler code is executed. A queue in Labview, however, does not generate events rather (from what you have described) you are taking the presence of data to mean that an event has occurred. You don't know what event has occurred until you have popped the element and decoded it The order is fixed (the position in the queue) and presumably, while this is happening, no other "events" can be processed so they cannot occur at any time (well perhaps they can occur at any time, but not be acted upon). The major difference between notifiers and queues is that notifiers can occur in any order and at any time and the "handler" (the section of code waiting) will be invoked.

I would be interested to see how you handle priorities with a queue. Lets say (for example) Event 1 must always be executed straight away (user presses Emergency Stop) but event 2 can wait (acquisition data available. And just to be annoying, lets say processing the acquisition data takes 10 minutes and you've got 100 of them in the queue when the e-stop comes in ;P ).

In an event driven environment, when Event 1 comes in its handler can check if the Event 2 is running and stop/pause it or postpone it (cut power and gracefully shut down acquisition).

Link to comment

Thanks for starting a new thread. Here's a link to the old thread.

QUOTE (ShaunR @ Apr 21 2009, 11:42 AM)

I will concede Labview "parallelism" but I I think we are talking about concurrency and I would wholeheartedly agree that labview runs concurrent tasks but not parallel code. But it's not an area I'm an expert in and perhaps I'm being too pedantic (I don't really care how it works as long as it does...lol).

If you have multiple processors, LabVIEW will run your nodes truly in parallel whether or not they are in different loops, different VIs, or just in different unconnected sections of a diagram, from everything I understand about their massive marketing blitz on this. If you only have one processor you will still see nice 'thread' scheduling that makes it seem like everything is working smoothly in parallel.

QUOTE (ShaunR)

I see events rather differently.

Events (to me) are analogous to interrupts. Events can occur in any order and at any time and, on invocation, handler code is executed. A queue in Labview, however, does not generate events rather (from what you have described) you are taking the presence of data to mean that an event has occurred. You don't know what event has occurred until you have popped the element and decoded it The order is fixed (the position in the queue) and presumably, while this is happening, no other "events" can be processed so they cannot occur at any time (well perhaps they can occur at any time, but not be acted upon). The major difference between notifiers and queues is that notifiers can occur in any order and at any time and the "handler" (the section of code waiting) will be invoked.

I would be interested to see how you handle priorities with a queue. Lets say (for example) Event 1 must always be executed straight away (user presses Emergency Stop) but event 2 can wait (acquisition data available. And just to be annoying, lets say processing the acquisition data takes 10 minutes and you've got 100 of them in the queue when the e-stop comes in ;P ).

In an event driven environment, when Event 1 comes in its handler can check if the Event 2 is running and stop/pause it or postpone it (cut power and gracefully shut down acquisition).

It's been a while since I messed with interrupts, but I don't think they are as different from queues as you think. On the microcontrollers I've used, if an interrupt comes in, other interrupts are masked, except for the non-maskable interrupt (which is your high-priority e-stop). One had to make the interrupt handling code as short as possible, otherwise other interrupts would stack up behind, just like in a labview queue. If you allowed new interrupts to be generated before the interrupt service routine finished, you risked infinite nesting of your interrupt calls.

With any event driven system, the maximum amount of time an event takes to be handled determines the latency of the system to handle new events. It would be nearly pointless to use any event-driven system to handle a 10-minute monolithic process. If you need to handle other events, you can usually break up a long process into many successive events, and throw the follow-on events from inside the handler. That's a state machine, which is another great use for a queue.

If you look at real-time OS design, it is basically the same problem. Every operation of the processor has to be divided into time slices, and between each one, the system has to check whether other higher-priority tasks are pending. You could easily implement this with LV queues, since you can flush the queue, and then evaluate whether the pending items should be reordered, and stuff them back into the front of the queue. How granular each event needs to be is just a design decision, and it's the same decision in an RTOS or a LV Queue-driven event handler.

If you need a high-priority system, like an emergency stop, that can interfere with the code inside any event handler, you should have a separate queue for that (in addition to whatever hardware interlocks you need).

QUOTE (ShaunR)

The major difference between notifiers and queues is that notifiers can occur in any order and at any time and the "handler" (the section of code waiting) will be invoked.

No, the major difference is that queues are FIFO, and notifiers are broadcast events with no history. If your notifier handler is not fast enough, you will lose events rather than stacking them up and falling behind like a queue would.

So, I'm tired of typing now. What more is it going to take, besides the ardent fan base of dozens or hundreds of users on this board, to convince you that queues are actually pretty darn useful?

Link to comment

I still fail to see how you can say that a queued message is not generating an event. A message can be queued from anywhere at any time just like your interrupts. The event handler (the part of the code taking messages from the queue) processes them as soon as the arrive just like an interrupt handler. Also, an interrupt handler will only be working on a single event at a time just like a queue. The old Motorola 68000 family processors had 7 interrupt levels which denoted priority levels. In LabVIEW if you created 7 queues and had 7 parallel message handlers (one for each queue) your system would not behave any differently than a 68000 processor. What you do and how events are processed is up to the "interrupt" handler. You had to write the specifics of your ISR for the 68K too. In addition, since the 68K was single threaded higher priority interrupts caused the code in the lower priority ISRs to stop running. Only one thing could be running at one time on that processor. For multithreaded, multicore systems you still need to figure out a way for one task to stop another. This would is true regardless of whether you are using LV or not. Multiple priorities don't really solve this problem when you have multiple parallel tasks running since each task is independent. In addition if you are using a single queue for events you can always queue a high priority task at the front of the queue. This way that event will be processed next.

With respect to concurrent or parallel I think you are being a bit picky about the terms. Of course if you have a single CPU nothing every trully runs in parallel. However with multicore CPUs no LabVIEW does utiltize all of the cores. You don't even have to change your code for this to happen. I am not sure how old versions of LV would handle this but certainly the newer versions are aware of multiple cores. This is not true in the text based languages. You have to jump through quite a few hoops to take advantage of multiple cores with a single application.

Link to comment

QUOTE (Mark Yedinak @ Apr 23 2009, 05:40 AM)

With respect to concurrent or parallel I think you are being a bit picky about the terms.

I think there's a distinction worth maintaining, because LabVIEW doesn't do both things well.

  • Concurrency is the ability to do multiple things at once - LabVIEW does this very well (parallel execution paths, independent for/while loops etc) and will utilize multiple processors/cores to run several different processes concurrently.
  • Parallel processing is the ability to split a single task across multiple processors/cores, and LabVIEW doesn't do this well at all. Something like a parallel For-loop is needed; i.e. the ability to take a single section of code, and replicate it across several cores, hopefully also with automatic partitioning of arrays (or at least simple ways to choose how they are partitioned).

Cheers ~ Greg

Link to comment

QUOTE (GregSands @ Apr 22 2009, 04:30 PM)

I think there's a distinction worth maintaining, because LabVIEW doesn't do both things well.

  • Concurrency is the ability to do multiple things at once - LabVIEW does this very well (parallel execution paths, independent for/while loops etc) and will utilize multiple processors/cores to run several different processes concurrently.
  • Parallel processing is the ability to split a single task across multiple processors/cores, and LabVIEW doesn't do this well at all. Something like a parallel For-loop is needed; i.e. the ability to take a single section of code, and replicate it across several cores, hopefully also with automatic partitioning of arrays (or at least simple ways to choose how they are partitioned).

Cheers ~ Greg

LabVIEW does split code across multiple cores. It does this now and it does a fairly decent job of it. If however you mean taking a single FOR loop and splitting its iterations across cores then I would agree with you that LV does not do this. However this would be a nontrivial task. Currently though LV does run nodes (and I am using NI's definition of a node) on separate cores. It automatically schedules things for you. Granted, LV realtime gives you more control over it but it works on desktop systems too.

Link to comment

QUOTE (Mark Yedinak @ Apr 22 2009, 02:58 PM)

LabVIEW does split code across multiple cores. It does this now and it does a fairly decent job of it. If however you mean taking a single FOR loop and splitting its iterations across cores then I would agree with you that LV does not do this. However this would be a nontrivial task. Currently though LV does run nodes (and I am using NI's definition of a node) on separate cores. It automatically schedules things for you. Granted, LV realtime gives you more control over it but it works on desktop systems too.

Rumor is that in the next version of labview you'll be able to right-click on a for loop and select how many cores to run it on.

Link to comment

QUOTE (jdunham @ Apr 21 2009, 09:23 PM)

Your talking about not interrupting an interrupt on a microcontroller with one interrupt level. An interrupt, (generally-as it's name suggests) "interrupts" program execution. If your main program is running and an interrupt comes in, on a microcontroller, it will automagically switch to the interrupt vector where your handler sits after pushing the program counter and other state information onto the stack. Once the interrupt has been serviced, it will pop the stack and resume program execution.

But.

If you remember I said I view events in a similar way to interrupts (analogous, not that they were), and qualified that by saying that they can happen in any order and at any time. which is is true. An interrupt can be from any of a number of sources (character comes in on the USART, watchdog timer, A/D conversion etc) which, when this "event" occurs will immediately pause the main program execution and jump to the handler(s). And one of those "events" may be every 20ms and another may be when there is a "T" in the day and the girlfriend has gone to see her mother.

QUOTE (jdunham @ Apr 21 2009, 09:23 PM)

With any event driven system, the maximum amount of time an event takes to be handled determines the latency of the system to handle new events.
It would be nearly pointless to use any event-driven system to handle a 10-minute monolithic process
. If you need to handle other events, you can usually break up a long process into many successive events, and throw the follow-on events from inside the handler. That's a state machine, which is another great use for a queue.

Are fou saying that VB, C++ or Delphi couldn't handle a file search? (of course your not :P ) A file search can take more than 10 mins and when it finds a file matching the search criteria, raises an event (usually with passing a search record). The main program is just sitting there (animating an icon, refreshing the display, picking its nose) untill the event tells it its found something.

I'll start another thread about Labview, state machines and why windows programmers love them....lol.

QUOTE (jdunham @ Apr 21 2009, 09:23 PM)

But I've just been convinced that Labview is parallel in nature :o ). Surely we just parallel up our slices until its big enough for our complete task :)

QUOTE (jdunham @ Apr 21 2009, 09:23 PM)

No, the major difference is that queues are FIFO, and notifiers are broadcast events with no history. If your notifier handler is not fast enough, you will lose events rather than stacking them up and falling behind like a queue would.

Indeed (well 50% indeed anyway). Queues are a particular type of buffer where only the first and last elements are accessible (FIFO,FILO). If your consumer is slower than your producer (as in my example), your buffer (queue) will just increase until you reach a limit (resources or you've fixed the length of the queue). However, with notifiers, if your consumer is slower than your producer your producer can just sit idle until it receives some indication (another notifier perhaps) that the sub process has finished. A queue based system demands that things are taken off the queue faster than they are put on the queue. Notifiers do not have this limitation (but they do have limitations). The consumer is idle until a start "event" has occurred and the producer is "idle" until the "process complete" event has occurred.

I'm not anti-queues. I just don't think they are the magic bullet to program design which some people (not necessarily on this forum) seem to think they are.

QUOTE (jdunham @ Apr 21 2009, 09:23 PM)

I've still got Marks post to do :P

QUOTE (Mark Yedinak @ Apr 22 2009, 06:40 PM)

I still fail to see how you can say that a queued message is not generating an event. A message can be queued from anywhere at any time just like your interrupts. The event handler (the part of the code taking messages from the queue) processes them as soon as the arrive just like an interrupt handler. Also, an interrupt handler will only be working on a single event at a time just like a queue.

/quote]

A queue doesn't generate events, neither does it react to events WHEN they happen (which is what is meant by event driven). I would consider an OnQueue or OnDeQueue to be an event that would be "generated" by a queue (which doesn't exist in Labview). Your queue implementation is a history (or buffer) of "events" that have occurred at some point in the past and the order in which they occurred (user clicks something on screen, DAQ, VISA or whatever). It is an extension to the logging example in the examples directory.

It will only process these historic events if it is at the front of the queue therefore it will only process it immediately if there is only 1 in the queue (queue of one sounds familiar
:P
)

The old Motorola 68000 family processors had 7 interrupt levels which denoted priority levels. In LabVIEW if you created 7 queues and had 7 parallel message handlers (one for each queue) your system would not behave any differently than a 68000 processor. What you do and how events are processed is up to the "interrupt" handler. You had to write the specifics of your ISR for the 68K too. In addition, since the 68K was single threaded higher priority interrupts caused the code in the lower priority ISRs to stop running. Only one thing could be running at one time on that processor. For multithreaded, multicore systems you still need to figure out a way for one task to stop another. This would is true regardless of whether you are using
LV
or not. Multiple priorities don't really solve this problem when you have multiple parallel tasks running since each task is independent. In addition if you are using a single queue for events you can always queue a high priority task at the front of the queue. This way that event will be processed next.

Whew. What a lot of effort to mimic a 20 year old single threaded processor :P . This example, however, is a good example of interrupts interrupting interrupts.

The key point here though is that WHEN the interrupt occurs "code in the lower priority ISRs to stop running"! Not "the interrupt will be serviced IF the request is at the front of the queue".

QUOTE (Mark Yedinak @ Apr 22 2009, 06:40 PM)

With respect to concurrent or parallel I think you are being a bit picky about the terms. Of course if you have a single CPU nothing every trully runs in parallel. However with multicore CPUs no LabVIEW does utiltize all of the cores. You don't even have to change your code for this to happen. I am not sure how old versions of
LV
would handle this but certainly the newer versions are aware of multiple cores. This is not true in the text based languages. You have to jump through quite a few hoops to take advantage of multiple cores with a single application.

I think Greg answered this better than I.

Link to comment

As an old hardware guy I have to make a point.

Interupts and traps are similar but differ in their origin and their timing. Interupts are asyncronous while traps are syncronous.

Interupts can at any time regardless of what is happening in the code. An example of this is you move the mouse and an interupt is fired (a signal is asserted on a bus) reuslting in the current code being pushed on to the satack and the code located at the associated interupt vector is executed.

A software trap differs in that it occurs as a result of some code event example, a mutex is released so the code servicing the release can check if other are waiting and if so fire the trap which can call the OS scheduler to change a thread from a resource wait state to runable and schedule same.

So interupts are hardware, and traps are software. Since LV is platform independent, the reliance of the hardware interupts to implement all of the syncronizations functions would be very challenging.

We now return you to your normally scheduled program.

Ben

Link to comment

QUOTE (ShaunR @ Apr 23 2009, 12:08 AM)

I'm not anti-queues. I just don't think they are the magic bullet to program design which some people (not necessarily on this forum) seem to think they are.

OK, It's been a fun thread and most things everyones said are basically correct and don't need a response except the quoted line. I have written several large applications, including an enormous one with a team working on it now, and they use lots of queues [and notifiers] for event-driven behavior and they work great. There is plenty of asynchronous behavior, and the various user interface screens feel natural because they are event driven (with the event structure) and they use queues to communicate with the various processes they need to effect. Often the receive status updates via notifier.

Occasionally I am asked to do maintenance from very old programs before I started to use queues (some of them pre-date the introduction of queues), and not only do they work less naturally from the end user perspective, but it is a pain to maintain the code since everything is in one big hairy loop or else there are lots of crazy locals and globals causing race conditions. In addition those apps are not as big, because those problems get exponentially worse as the program size grows, so there is kind of a limit to how big the app can get before it is too much work.

Every time I experience this, I think, "Wow, queues are really the magic bullet to program design that makes large application development feasible in LabVIEW". I'm sure there could be other ways to develop large applications, but queues are very flexible and robust, and have a terrific API (unlike the horrible File I/O library), and have great performance. Obviously you have a different opinion, but I encourage you to try a big application with queues, and I think you won't go back.

Link to comment

QUOTE (Mark Yedinak @ Apr 22 2009, 04:58 PM)

If however you mean taking a single FOR loop and splitting its iterations across cores then I would agree with you that LV does not do this. However this would be a nontrivial task.
A non-trivial task? Really? So, in other words, you'd be impressed if LabVIEW could do that? We're always looking for features that would impress our customers... I'll let some of my developer buddies know that you'd like to see that in the August 2009 release...

:ninja:

Link to comment

QUOTE (Aristos Queue @ Apr 23 2009, 09:59 AM)

A non-trivial task? Really? So, in other words, you'd be impressed if LabVIEW could do that? We're always looking for features that would impress our customers... I'll let some of my developer buddies know that you'd like to see that in the August 2009 release...

:ninja:

I am continually impressed by all the "magic" that occurs under the hood of LabVIEW. This would be a great enhancement to LV when it gets added in the next release. This is one more reason that I think NI should get more aggressive about promoting LV as a general purpose programming language. It allows applications to benefit from current technology where other languages are still quite a ways off, at least with respect to the ease of using these features. However that is an entirely different topic for discussion. Anyway, feel free to pass along a job well done to the developers on my behalf.

Link to comment

QUOTE (jdunham @ Apr 23 2009, 03:42 PM)

Giving up already :o

I believe the Event Structure to be the best innovation in labview since.....well...I can't remember when. Why don't they receive by a queue?

QUOTE (jdunham @ Apr 23 2009, 03:42 PM)

Occasionally I am asked to do maintenance from very old programs before I started to use queues (some of them pre-date the introduction of queues), and not only do they work less naturally from the end user perspective, but it is a pain to maintain the code since everything is in one big hairy loop or else there are lots of crazy locals and globals causing race conditions. In addition those apps are not as big, because those problems get exponentially worse as the program size grows, so there is kind of a limit to how big the app can get before it is too much work.

I don't see why they should work less naturally just because they don't use queues.

QUOTE (jdunham @ Apr 23 2009, 03:42 PM)

Every time I experience this, I think, "Wow, queues are really the magic bullet to program design that makes large application development feasible in LabVIEW". I'm sure there could be other ways to develop large applications, but queues are very flexible and robust, and have a terrific API (unlike the horrible File I/O library), and have great performance. Obviously you have a different opinion, but I encourage you to try a big application with queues, and I think you won't go back.

It's always been feasible (and fairly straight forward).

You seem to be under the impression I've never used queues. I have written several queue based applications where that technique was the most appropriate (2 of them with a team of 8 Labview programmers). But I have written far more where it was not. So I guess I have gone back, and forward, and back......etc.

I'm not sure of your criteria for "big" but I tend to gauge the scale of a project on how much hardware I have to interface too since that is probably 75% of the programming time on most most of my applications. The current one involves 12 motors, 8 marposs probes, 5 camera's, 192 digital IO's, 2 analogue inputs, 12 analogue outputs and 3 proprietary devices using MVB , CAN and RS485. This part of the project I would consider medium sized since it is one of 3 machines (which are similar but not identical) and will be part of an automated production line.

Link to comment

QUOTE (ShaunR @ Apr 23 2009, 08:18 PM)

I second this part. Why can't we wire up a queue (or notifier and occurrence of course) to an event structure? It's a logical extension of the current ability to use queues.

QUOTE (ShaunR @ Apr 23 2009, 08:18 PM)

I don't see why they should work less naturally just because they don't use queues.

I also agree with this. It all comes down to the application architecture. I've recently done a relatively large application using not a single queue yet it's all modular and rather easy to follow. Instead of queues I used user events.

For me the big drawback of queues and notifiers is that there has to be a part of the code which is waiting for data to arrive. With an event, this is not the case. With an event, the code to receive new data can be one pane of an event structure. You can even have multiple "receiver" panes in one event handler, each one with their own strictly defined data type (No variants and so on).

Just my 2c.

Shane.

Link to comment

QUOTE (shoneill @ Apr 24 2009, 08:26 AM)

For me the big drawback of queues and notifiers is that there has to be a part of the code which is waiting for data to arrive. With an event, this is not the case. With an event, the code to receive new data can be one pane of an event structure. You can even have multiple "receiver" panes in one event handler, each one with their own strictly defined data type (No variants and so on).

Just my 2c.

Shane.

Succinctly put! That is why queues are not events.

You can even have multiple event structures linked to a single event (that's how I get round the local variable on Latch booleans).

What (IMHO) would be a good enhancement to events is.....

if you could define an event (say by right clicking on a control or indicator), plonk an event structure anywhere in your code (not just the same VI) and it appears in the list of events to link to. Then you could do things like when a DAQ digital line toggles and sets an indicator on your low level acquisition vi, an indicator on the screen toggles or an alarm dialogue appears or even kick off entire processes. It would make notifiers and occurrences obsolete and make rendezvous and semaphores actually useful. I would save weeks coding. We would also have an event scheme to rival any of the other event driven languages with the added bonus that we can also use dataflow.

Link to comment

I was perusing the internet this afternoon and came accross this:

Queued Statemachines

It seemed a very complicated solution just to acquire and display a graph. And an excellent example of why you should not use Queues for everything. They obfuscate and complicate.

So (for a bit of fun - I'm sad like that) I decided to rewrite it NOT using queues but instead using more traditional methods. In fact, I thought I'd demonstrate notifiers at the same time. It can be improved but the purpose was to replicate the queue example and I didn't want too spend more than an hour of my life doing it.

The result I'll let you judge for yourself. However it is a fraction of the size, fewer VI's, less complicated and extremely easy to understand unlike the queue example.

The example from the above website.

Download File:post-15232-1240670379.zip

Alternative.

Download File:post-15232-1240670495.zip

Link to comment

QUOTE (ShaunR @ Apr 23 2009, 11:18 AM)

I'm not exactly sure what you mean. I think the event structure is queued. If you invoke two or more value(signalling) properties then they will be handled on a FIFO basis, since there is some kind of queue behind the event structure. I agree it would be cool if LabVIEW made it easier to handle user and programmatic events in the same structure. I know you can register your own event, but it seems like a pain to me, when the queues are so easy.

Event structures and queues both have the problem that if the handler code is not fast enough, you'll fall behind and either miss events or stack them up with high latency, either of which is undesirable. You can programmatically trigger event structures with the Value(signalling) property, which makes them act a lot like... queues.

I guess a better question is how do you handle asynchronous activity in your programs? Do you poll for every possible status change on every component, or do you set up event handlers?

QUOTE

Well I found it difficult to manage an event-driven user interface in the same loop as several acquisition/control processes. If some of those processes had to maintain an internal state, it got even harder. If I wanted to reuse those hardware items in other applications, it was often easier to just rewrite the code. With a queue handling the inputs for a given device, I can have a modular program for that device which maintains any necessary state and accepts asynchronous event messages.

QUOTE

I have to admit it I got the impression that you rarely use them, and that you don't use all the features of them (that I and others have mentioned in previous posts). You'll have to forgive me, but I just don't see how anyone could use them regularly and then ask why others find them indispensable.

I am certainly open to other opinions. What architecture do you use for your majority of large applications where queues were not the best solution? Do you handle user input and environmental input (alarms, triggers, other state changes) in the same loop of execution? Do you pass messages between with some other mechanism? Do you run a monster event loop, and run everything in the timeout case, and make sure that every subvi can finish in 50ms or so? I would love to hear more about other architectures you prefer.

QUOTE

Sounds plenty big. Do state changes on one hardware device have asyncrhonous effects (triggers) on other devices? How do you handle that? If the user presses the STOP ALL/RESET/CANCEL button(s), how is that handled?

My current project has about 4000 VIs, and probably 2500 are running at in the main app, with about 25 parallel static loops and 2 to 100 or more dynamically spawned loops, all of them containing at least one queue or notifier for message passing and synchronization. When this system grew to about 1500 VIs, we couldn't maintain the code any more until we refactored everything and used a lot more queues. I think that a much smaller app of only a few dozen VIs could still benefit from using queues if there are mulitple asynchronous tasks.

QUOTE

A queue-driven event handler is exactly the same, though if your handler is not fast enough, queue messages will stack up. In many of my loops this is not a big deal. In an interrupt I think the call frames nest on a stack in the same situation, and whether or not this can be tolerated is a design decision. I don't see this as much different, and certainly the dataflow nature of labview makes it harder to intervene in executing code at an arbitrary point. That limitation affects any kind of LabVIEW code.

QUOTE ( @ Apr 25 2009, 07:52 AM)

I was perusing the internet this afternoon and came accross this:

Well I have a couple comments here. For one, I'm not a huge fan of over-using state machines. I always prefer dataflow. If I have to do four operations, I'd rather see four subvis in a row than four cases in a state machine loop. But other people really like them. The large app I mentioned above has very few state machines.

The second comment is that the example is just an illustration. When programming books talk about recursion, they almost always show the factorial operation. But no one ever uses a recursive program to calculate a factorial. It's just a common example because it's easy to get one's head around. So for you take this example to task is like saying recursion is useless because you could just calculate factorials with a for loop and a shift register (which is the right way to do it).

QUOTE (ShaunR)

Your example is a better solution to that problem, but we already established that the author wasn't trying to solve a problem so much as illustrate a scalable architecture.

Your rework still uses a notifier which isn't any different (to me) than a queue. Sometimes you want multiple listeners (notifiers) and sometimes you want to guarantee messages won't be skipped if you fall behind (queue). When you don't care about either, then they are equivalent. If your entire thesis is that queues are not as useful as notifiers, then I think you're being silly.

I made a VI, which isn't too much different than other stuff you've seen but I'll post it anyway. It's an architecture that is working well for me. I would still love to see more about what is working for you in your large applications.

target="_blank">post-1764-1240686447.png?width=400

Link to comment

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

What I actually meant was why do you use notifiers to receive updates when you are using a queue anyway for events. I've just read it back and see that I phrased it badly (the subject before being events) it was in response to the previous paragraph which finished with

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

they use queues to communicate with the various processes they need to effect. Often the receive status updates via notifier.

I tend (generally) to use one or the other as in many cases as (you point out later) their features can be seen to be synonymous.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

I use an appropriate strategy. Not really answering your question though, I know, but I'm not sure of what you have in mind. I tend to think through the partitioning and use encapsulation to distill interaction between sub components to a bare minimum and make each aynchronous task as autonomous as possible.

Generally it boils down to an error indication, start, stop and pause.

But I will give you a very typical example of an every day scenario that would be very complicated using events/queues/notifiers etc. But Labview makes very easy and can be done it minutes.

Lets assume the system is monolithic and only runs on one machine (a test/inspection machine for example) and say I have 32 digital inputs that indicate alarm conditions on of which only 8 of them are to be displayed on the user interface. I can (and do) arrange with the electrical guys that those 8 are all on the same port (I give them a spreadsheet with the pin numbers of the DIO device and define which sensors/outputs will be attached to what).Now I can have an asynchronously running digital input VI that all it has to do all day is read the status of those digital inputs and write them to a global as a 32bit number. Then I can easily mask them off in the user interface just by polling that global and (with the number to boolean function) show the user which ones they are in a 1D array of booleans or I can use the number as an index into an array of strings to show an error string. If you have multiple banks (like 128 in banks of 8) you can partition those banks for each hardware subsystem). Then your on-screen alarms become a 2D array of booleans, each row (or column) associated with each piece of hardware. Any other VI can also read that global if and when it wants to (none of that critcal section rubbish with Labview :) ). So if some other part of the system needs to now about it it can. Quick, simple and as I said takes a few minutes.

Now. This test machine needs to feed a part from a bowl feeder into the test/inspection section. Again. I create a "Bowl Feeder" vi that requires a Start (give me a part), Stop (shutdown), Pause (wait a mo 'cos somethings wrong) and error (or no error if everything is ok). I don't need a response that a part has arrived because that will be given by a sensor.

So I eventually end up with all these autonomous, asynchronous subsystems (each only requiring a start, stop, and pause). The start is usually from the main sequencing engine (single notifier if everything happens in parallel or one for each if they are staggered). The stop and pause can be a global (similar to that used in my previous posted example) and the subsystem handles its own errors and pauses all the other subs and the sequence engine while it figures out what to do about it and invokes the shut down procedure if it can't do anything.

Now. Distributed IO is a different kettle of fish!

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

Well I found it difficult to manage an event-driven user interface in the same loop as several acquisition/control processes. If some of those processes had to maintain an internal state, it got even harder. If I wanted to reuse those hardware items in other applications, it was often easier to just rewrite the code. With a queue handling the inputs for a given device, I can have a modular program for that device which maintains any necessary state and accepts asynchronous event messages.

I have always had the UI in its own loop. I used to "break" the link with globals and dynamic loading (the example I posted would have used globals instead of notifiers and would have been quite messy), now we have other tools like events, notifiers, queues, semaphores and the like. We have the tools to make more elegant solutions.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

I do rarely use them (in the way that they are often used). Not because I don't like them, but because they don't warrant the use in a lot of the systems I design (take the example above). I could use them, but a couple of notifiers and a small global do the job without having to define messaging scheme for interaction. If it were a distributed system or a supervisory system where a lot of information is being exchanged, then yes it would warrant it, but not just for a start, stop and pause. I'm an advocate of the choosing the right architecture for the specification rather than just throw a queue at it, which it strikes me a lot of people seem to be.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

I am certainly open to other opinions. What architecture do you use for your majority of large applications where queues were not the best solution? Do you handle user input and environmental input (alarms, triggers, other state changes) in the same loop of execution? Do you pass messages between with some other mechanism? Do you run a monster event loop, and run everything in the timeout case, and make sure that every subvi can finish in 50ms or so? I would love to hear more about other architectures you prefer.

See above

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

In the above example and in the case of an alarm dialogue. It would set the pause flag while it is on-screen (if that's whats required or it might just log it to a file...depends). Crowbar all the subsystems and invoke the "graceful shutdown.vi" on a reset or stop. And un-set the pause flag for a cancel. . Triggers would probably be hardware and catered for by the the individual subsystem responsible for it.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

My current project has about 4000 VIs, and probably 2500 are running at in the main app, with about 25 parallel static loops and 2 to 100 or more dynamically spawned loops, all of them containing at least one queue or notifier for message passing and synchronization. When this system grew to about 1500 VIs, we couldn't maintain the code any more until we refactored everything and used a lot more queues. I think that a much smaller app of only a few dozen VIs could still benefit from using queues if there are mulitple asynchronous tasks.

That depends on how much info they need to do their job. I prefer autonomous encapsulation of the task as it makes the code a lot more understandable and intuitive (and less documentation :P )

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

I think I see the where the difference in views lie. I don't see dataflow as a limitation. The fact that it is a a dataflow paradigm, means that you don't have to worry about state information. The function (or vi) gets executed when all its inputs have data. Its implicit. In event driven languages (I also program in Delphi and C++ by the way) you have to have a lot of state information to make the application work in an ordered fashion. This is unnecessary in Labview which is why it is fantastic for test/automation/inspection etc but sucks as a webserver (although NI would like to think its great). I recently wrote a bit-torrent application (lots of concurrent connections appearing and disappearing at random, asynchronous pipes etc). Wrote that in Delphi because it would be a nightmare in Labview. Square pegs don't fit in round holes.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

Well I have a couple comments here. For one, I'm not a huge fan of over-using state machines. I always prefer dataflow. If I have to do four operations, I'd rather see four subvis in a row than four cases in a state machine loop. But other people really like them. The large app I mentioned above has very few state machines.

Ditto. They hide functionality, can be difficult to conceptualise and break dataflow. That said. They do have the advantage that they compact code and enable selective branching. If used spareingly a definite asset. But often abused. I think were on the same page there :)

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

First off. I don't consider the former to be the "wrong way" just "another" way. There are many tools at our disposal and we should choose those that are appropriate. As I think I said in the notes. It was to demonstrate that the use of queues adds complexity and obfusification. It took me about an hour to write that, debug, benchmark and comment it (with coffees). I expect the same cannot be said for the original (excluding the pictures and write-up I mean). It may have been an illustration. But there are many out there that would do just such an app that way.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

Your example is a better solution to that problem, but we already established that the author wasn't trying to solve a problem so much as illustrate a scalable architecture.

Better? No. They both fulfill the spec. I think one is easier to read and understand because it uses Labviews dataflow more and the other is more complex and difficult to read because it breaks that dataflow and adds complexity to compensate.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

No. My thesis is that queues add complexity, are cryptic and (sometimes) require more VI's to be modified throughout the code. And that should be taken into account when designing a system since other alternatives can yield a more intuitive and easier to read solution and have better encapsulation.

QUOTE (jdunham @ Apr 25 2009, 08:12 PM)

I made a VI, which isn't too much different than other stuff you've seen but I'll post it anyway. It's an architecture that is working well for me. I would still love to see more about what is working for you in your large applications.

post-1764-1240686447.png?width=400

Many thanks.

One observation. It doesn't "go to sleep" it polls the status until it has something in the queue. So I'm guessing you have a wait so many milliseconds in the timeout case. That is the big difference between queues and notifiers. If you add another notifier (wait) to my example before the acquisition another after the AQ notify in the Subvi 2 (notify) and a third before the while loop in the main (also a notify just to kick off the aquisition in the first place) then you can run the system fully synchronised, flat out with no loss of data (3ms). You can't do that with a queue.

See attached:

Download File:post-15232-1240703966.zip

And if you read all that your a star....lol.

Link to comment

OK, I think we're converging: like queues and notifiers, think state machines are over-used. We're also proving that the way I spend my weekends is lame. Hopefully this is the last time I'll take the bait.

QUOTE (ShaunR @ Apr 25 2009, 05:03 PM)

Same thing would work better with a notifier. No polling, no latency.

QUOTE (ShaunR)

Still confused why you started this thread! :wacko: Queues are elegant and extremely useful. That's what the fuss is about. Where I think we agree is that if the system is NOT asynchronous and doesn't need event handling, then larding it up with an event handler or a state machine is not good.

QUOTE (ShaunR)

Amen, brother. Dataflow is your friend. Easy to read, simple coding. But when you have parallel processes, dataflow doesn't apply. If they need to share data, you can use globals, which have lots of problems, or queues, which don't.

QUOTE (ShaunR)

Well my app has a networked sensor array with dozens of concurrent connections, with data going in both directions. Each TCP or serial connection is handled with a lightweight process (diagram almost fits on one screen), which is cloned and spawned as a dynamic call. Each of these identical handlers feed their bytes to a central queue for parsing, analysis, notification, and logging. The comm handlers register their own queues so the central code knows how to send individual responses and control messages. Sometimes the comms appear and disappear at random (some radios are crappier than others), but the LabVIEW handles it smoothly. In short, it works great, and queues make it all happen. The peg's looking kind of round from where I sit.

QUOTE (ShaunR)

I generally run these handlers with infinite timeout, so there is no timeout case (and no wait function). LabVIEW's internal execution scheduler may have to poll the queue somewhere deep in the bowels of LV, but that's not exposed to me. We have dozens of queues waiting in parallel with very low overhead and very low latency when an event is fired, so I suspect it's not polling at all, but is really sleeping. I don't know what you mean about a difference between queues and notifiers. As far as waiting and timing out, they act exactly the same.

QUOTE (ShaunR)

OK that's why I'm still on this thread. I rewrote your version using queues. No globals, no polling (except to simulate acquisition), no latency, asynchronous (event-driven), no possibility of race conditions or data loss, and no crowbar needed -- all thanks to queues. Queues of data, not of messages. And yes, it runs as fast or as slow as you ask it to run. There is a little bit of jitter at 1 or 2 ms, but I think that is caused by using the Timeout case of the event structure, not by the queues and notifiers.

http://lavag.org/old_files/post-1764-1240766707.zip'>Download File:post-1764-1240766707.zip

Link to comment
QUOTE (jdunham @ Apr 26 2009, 12:29 PM)
I generally run these handlers with infinite timeout, so there is no timeout case (and no wait function). LabVIEW's internal execution scheduler may have to poll the queue somewhere deep in the bowels of LV, but that's not exposed to me.
Let me assure you -- it really does go to sleep. There is no CPU load at all from a sleeping queue prim. There is no polling for data. Thread A executes and goes to sleep on a queue. Thread B runs free. When Thread B puts data into the queue, it wakes up thread A. In fact, it doesn't even put the data into the queue. It puts it directly into the output of Thread A and A wakes up and starts running as if it had just gotten the data out of the queue.

Link to comment

QUOTE (Aristos Queue @ Apr 26 2009, 09:50 PM)

Let me assure you -- it really does go to sleep. There is no CPU load at all from a sleeping queue prim. There is no polling for data. Thread A executes and goes to sleep on a queue. Thread B runs free. When Thread B puts data into the queue, it wakes up thread A. In fact, it doesn't even put the data into the queue. It puts it directly into the output of Thread A and A wakes up and starts running as if it had just gotten the data out of the queue.

Indeed.

The differences are, when you get right down to the nitty gritty, more subtle than at first apparent (apart from the event structure being rather unwieldy but I digress).

For me the big advantage of user events is that I generally have Events sending data back and forth (through defined interfaces defined by events to and from several processes). When I want to control or listen to a process, I access it's list of events (method of acquisition may vary but often involves a queue) and I essentially have an API for that module. It really doesn't get simpler than that. I also like the fact that there are no variants or strings needed when the API gets a bit more varied. Each and every event has its own strict datatype which saves me having to cast here, check there and so on.

An interesting idea is using a user event passing a notifier refnum. The notifier has the latest data and a quick check of the current and last set of data allows the "slow event" problem to be rather easilt overcome (Where unwanted past events get queued and the system get's bogged down).

Quite often I even -gasp- have multiple event structures in one VI. It's do-able when you are aware of the things to avoid.

I use both queues and events and I think all have their merits (Events, Notifiers, Queues, Semaphores and Occurences). For inter-process communication I generally go with events though.

<Crazy idea mode>

What I would REALLY like would be able to wire up a Notifier/Queue/Semaphore/Occurrence refnum to an Event structure just like a registered event and handle the receiving of data from the event handler. (I think this is what was being referred to earlier in the thread) :thumbup:

What I woull ALSO really like would be an updated interface for the event structure. With user modules running via events, things get very messy very quickly. Adding Queues et. al to this would not necessarily be a good thing until the Event structure interface got a facelift.

</Crazy idea mode>

Just my 2c.

Shane.

Link to comment

QUOTE (Aristos Queue @ Apr 26 2009, 08:50 PM)

Let me assure you -- it really does go to sleep. There is no CPU load at all from a sleeping queue prim. There is no polling for data. Thread A executes and goes to sleep on a queue. Thread B runs free. When Thread B puts data into the queue, it wakes up thread A. In fact, it doesn't even put the data into the queue. It puts it directly into the output of Thread A and A wakes up and starts running as if it had just gotten the data out of the queue.

Shorter ones first...lol.

Even if there IS data in the queue but not for that "thread"?

And (just a point to fill my knowledge gap) Are you saying that 2 while loops (or 50 even) will run in their own separate threads?

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.