Jump to content

Aristos Queue

Members
  • Posts

    3,183
  • Joined

  • Last visited

  • Days Won

    203

Posts posted by Aristos Queue

  1. The easiest way to count the button presses is to use the Event Structure, like this:

    post-5877-0-63364000-1319773428.png

    Every time the button gets pressed, the value in the shift register gets incremented by one. Look at some example files (use Help >> Find Examples... in the menus) of usages of the Event Structure.

    You probably also want to combine this with a basic state machine pattern. You essentially have 3 states: "Draw the two colors", "wait for button to be pressed", "Evaluate results". You can code that up like this:

    post-5877-0-34412800-1319773956_thumb.pn

    In the "Wait For Buttons" case, put the Event Structure.

    In each case, you decide which frame you want to happen next. Sometimes it will be a fixed constant, sometimes there will be some decision about which frame to go to next.

    This is the state machine pattern and there are lots of good examples of it, also, in the Example Finder.

    Good luck.

    • Like 1
  2. PS> haven't been keeping up the score; it's a low two digit number to a mere 3.5 unicorns.

    A bit of history here... when the icon FP Terminals were first added, I didn't like them and asked they be removed because all they did was reflect a few FP controls/indicators. Those who do the usability testing on LV said that it benefited newbies to recognize the association between the thing they dropped on the panel and the thing they dropped on the diagram. I sighed and said, well, if we're going to have icons, they might as well be *useful* icons, so I made the VI Refnum reflect conpane, made the other refnum types show something other than just the folded corner of paper, made the typedefs show their control icon, and made LV classes show their type icon (originally they were all cubes). And then, as time went by, they started growing on me.

    Maybe it's just prisoner syndrome and I've started identifying with my captors.

  3. I am sorry... I still don't grasp what you're asking for. I am guessing that English is not your native language and you're using translation tools to post. Something is being lost in mechanical translation. Could you try posting your question in your native language... there may be someone on the forums that can provide a better translation.

  4. Here's a better example of the use of the Occurrences. Here it is used to implement efficient dequeue from multiple queues. It was built using the instructions: "Build the system with polling first, then add the occurrences to avoid polling."

    Note that you shouldn't actually use this example directly if you are going to wait on multiple queues because there's a starvation issue -- if the first queue gets heavy with elements, the consumer loop will never get around to dequeuing from the second queue. You'd need to put some fairness into the consumer's behavior to make sure it checked each queue equally as often for elements, maybe by rotating the queue array on every iteration of the consumer while loop, or something like that. Left as an exercise to the reader... this post is just about Occurrences.

    post-5877-0-36942600-1319344603.png

    What's that you say? There are times when the loop will execute a poll when there's nothing to do? There's an extra iteration after every dequeued element just to prove that the queues are empty? Yes, you're correct. That's how the occurrences work. They are not the signal that there *is* data waiting. They are the signal that there *might* be data waiting and it's a good time to go check. This is their intended design because they are deliberately as lightweight as possible so as to be the atomic unit of locking in LabVIEW. Consider what would happen if the two producer loops both did "Set Occurrence" at the same time without the consumer getting an iteration in between, something that will happen every once in a while. Handling that case is why the consumer loop has to do its own secondary polling. The intention is that occurrences are used to write higher level APIs, and those higher APIs give the calelr the illusion of "I'll actually wait until data is available". And this is why occurrences are almost never used by LabVIEW customers -- those higher level APIs already generally exist.

    Here's the VI, saved in LV 2011:

    Wait For Multiple Queues.vi

    • Like 1
  5. I don't think lossy vs. lossless is one of the defining characteristics of slaves or consumers. I suspect the template uses notifiers simply because they allow easy 1-to-many communication. I use queues instead because most of the time I want lossless master/slave communication.
    I don't think that's true. Note that although the template today uses primitives that I wrote, older versions of the template existed before I started at NI, so I can't be certain of the intent -- I don't even know where they originated -- but to me, the master/slave pattern is useful because the master may change its mind about the next direction. The slave carries out some order. In the interim, the master may change the next order several times. This occurs during navigation type operations, where additional data is coming in all the time about road hazards, so the information sent to the slave is the master's "best guess for next action", which may be changed frequently. It needs to be sent and updated continuously because the master has no idea when the slave is going to get around to asking for the next instruction. Day trading applications use this pattern, with a master system evaluating the market and multiple slaves responding to "buy this" or "sell that" orders, orders that might be redacted before they are actually acted on.
    Now I thought I understood the differences between queues and notifiers, but maybe there's something I'm missing. As far as I know these two master/slave implementations are functionally equivalent. Is there an edge condition I'm not aware of that makes them behave differently?

    You're missing something bit: Notifiers have an implicit message ID system. The "Preview Queue Element" node will copy the front element of the queue (assuming the queue is not empty) every time the loop repeats. The "Wait For Notification" node will copy the element of the Notifier ONLY if this particular Wait node has not seen this particular notification before. That means that the Notifiers are not only a broadcast mechanism that wakes everyone up when a notification is sent... they are a mechanism that guarantees that each listener is woken up at most one time for that notification.

    This is covered in the documentation of Notifiers and various other places on the 'net if you want more details.

    Short version: You cannot effectively build a Notifier out of the Queue primitives without introducing some reentrant wrapper VIs that store state so that each Wait call can remember what message ID it saw last. Even more, you cannot build "Wait For Multiple Notifiers" at all without turning to some sort of polling mechanism inside those reentrant VIs or reaching for the very low level Occurrences and using the less-than-intuitive canonical correct usage pattern for Occurrences that I posted last week.

    [Later] I went ahead and built the "wait for multiple queues" example because it was such a good example of the purpose of Occurrences. You can see it here.

    • Like 1
  6. I also brought up the Actor framework because while even more abstracted from a traditional LV architecture, it seems to me that the actors are simply waiting for messages as well.
    Although it is true that the loop that handles messages does wait for the next message, each Actor may have one or more additional control loops in its Actor Core.vi. I suggest that the reason you don't see anything like what you suggest in the Actor Framework is the existence of these separate control loops. If I needed any "do this until you hear otherwise" behavior in one of my actors, I would encode it in the control loop. An example of that is in this Actor Framework demo in the Temperature Sensor class, where the sensor polls for the current sensor value every five seconds in the absence of any other message.
  7. I'm fine using this where needed, but I'd love to have a native implementation in the OpenG LabVIEW Data Tools Library.

    I'm confused. Please define "native implementation". That VI is doing exactly what LV does under the hood in the C++ code. I'm not sure how much more native you can get.

    And, to answer Yair's question, no, there's no flattening of the variant involved.

  8. I know the conversation earlier had comments about other ways to make this work, but none of them highlighted that the current way didn't work. I just don't want anyone who Googles this site to think that the Network Queue implementation here is fully functional. For non-timeout cases, it works, but it has some nasty lurking bugs.

  9. I stand correct4ed (when did they add that then?)

    As long as the primitive has existed to the best of my knowledge, but I couldn't check any earlier than 5.0 today... didn't feel like digging out older installers.
    I guess I'm left thinking they're okay for simple cases--such as Tim posted--where the occurrence will only fire once telling the receiving loop to stop. But at the same time I can't think of any reason (outside of interacting with external code) I'd want to bother with them. Notifiers and queues have the same functionality, provide more options for expansion, and the overhead is insignificant.
    If you ever undertake to write the queues or notifiers completely in G, you'd need the occurrences. It can be done, and the main reason it isn't done today is the polymorphism of primitive nodes. You wouldn't use the occurrences as the keys for looking up data for a particular refnum, but you'd use them for triggering various interactivity between read and write VIs and the timeout mechanisms.
  10. There's no way in scripting to get a runtime value from a wire or a raw terminal because they don't have values -- they all share values through the inplaceness algorithm and the memory address that is used for any given terminal/wire is not unique to that term/wire. You can ask a control or indicator for its value, although opening that control reference will have a performance impact on your code since now a copy of the value will be made to the UI layer when your VI runs (just as if you had the front panel sitting open).

  11. I had a conversation with our chief architect whose been working on LV since version 0.1 and who created the occurrences long long ago. Here is THE correct way to use occurrences:

    First build a system which polls busily for whatever it is the occurrence will signal. You need to be able to determine the state of things without an occurrence. This creates a correct, but inefficient busy waiting implementation. Once that works, add an occurrence to alleviate the inefficient waiting. Do not remove the actual polling. In other words, use the occurrence only to indicate that "it is probably a good time to check on that thing...".

    [Later Edit] I added a much better example of the usage of occurrences a few days later in this thread. Read it here.

    In other words, start with this:

    post-5877-0-78906900-1318019474.png

    and then go to this:

    post-5877-0-31239600-1318019479.png

    As I understand it, occurrences don't have thread safety on their state because they are the building blocks by which thread safety for state in higher level APIs is built.

    • Like 1
  12. There are multiple serious bugs in this API having to do with timeout and connection dropped behaviors.

    Suppose client calls Dequeue. It sends a message to the server saying, "I want data." The server dequeues data from the local queue and then tries to send it back to the client.

    Problem 1: Suppose that in between saying "I want data" and getting that data, the client hits its timeout and stops waiting for the data. The data gets sent anyway -- and is sitting in the TCP connection the next time the client does a TCP Read. Now the client gets around to calling Dequeue again --- the client is going to get the data that was sent the previous time. Each time thereafter, the client is one message behind.

    Problem 2: A worse version of problem 1... after timing out on a Dequeue, the client does any other operation. The data that was supposed to be the last sent message will be the reply. In other words, the client times out on a first Dequeue, then does two Preview Queue calls in a row and gets different data.

    Problem 3: Suppose that the client TCP connection actually does go dead. The server times out trying to send the data back to the client. The dequeued element is not put back onto the end of the queue, so it gets dropped. Now you have a message that was enqueued that no client has ever handled.

    I'm pretty sure that if you have an unstable connection or use timeout a lot that there are other lurking bugs in here.

  13. The only thing I'm left wondering is when I would use the default implementation of an override method (ie call parent method), it doesn't seem to be any use apart from as a placeholder.
    In a huge number of cases, is is just a placeholder. But often it is not. When it is not, it is either
    • a place where you put the initial code where each of the children add additional functionality. For example, the parent might define a "set value.vi"... the child might override to add range limits to that value before calling the parent version to actually set the value.
    • OR it serves as the default when a child doesn't need to do any overriding.

  14. Let me fix that for you...

    > I'd hazard a guess that notifiers occurrences aren't recommended due to their behavior being

    > different than the other sync objects. The behavior is a little odd, but once understood they are perfectly usable.

    With my amendments, yes, you're correct

    It is very hard for most folks I've worked with to understand how and why occurrences work. The Notifier wrapper (it uses occurrences under the hood, as does all sleep/wake behavior of LV) generally makes things clearer.

    I'd probably throw in a release primitive in there for good practice, but otherwise all good I'd say.

    Yeah, that should be added since he's probably calling this as a subVI repeatedly.

  15. Someone at work was building a dialog for a load progress bar. If the load process took more than N milliseconds, the panel should display. If the load process finished first, the panel should not open. Here's what I wrote for him. Anyone have any improvements to suggest?

    [LATER EDIT] Thanks to mje who posted a fully correct solution with all the comments from this thread. You can find the correct solution here.

    post-5877-0-21875700-1317418800.png

    • Like 1
×
×
  • Create New...

Important Information

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