Jump to content

How to open front panel after N milliseconds unless the operation is done


Recommended Posts

On the surface it seems like that should work, but there's a subtle race condition. Because the WoO has a timeout it is possible for loop B to read the stop button, exit, and reset before loop A has an opportunity to read it. With an infinite timeout that will never happen. I suppose you could put the button reset in a sequence structure and wire outputs from both loop A and B to it, but that feels kind of klunky to me. The other alternative is to set the timeout longer than the time between occurrences, so it will only timeout once the occurrences have stopped being generated. That doesn't seem like a very robust solution.

Just OR the =0 with the stop and it will work without an extra occurrence and without a timeout..It is a sequencing issue rather than a race condition-as with AQs version.

Edited by ShaunR
Link to comment

Just OR the =0 with the stop...

Maybe I misunderstand. OR'ing =0 with STOP in loop A terminates that loop on the first occurrence. (The purpose of this example to demonstrate how to issue continuous occurrences.)

However, I propose another solution to the race condition: don't reset the local after Loop B completes, reset it before passing the occurrence into Loops A and B at the start.

Weren't you ever a boyscout? Leave it better than you found it! ;)

That works too if you don't mind bringing in a sequence structure again. It's even a little cleaner than a seq struct at the end because you just have to wrap it around the Generate Occurence function.

Link to comment

Weren't you ever a boyscout? Leave it better than you found it! ;)

That works too if you don't mind bringing in a sequence structure again. It's even a little cleaner than a seq struct at the end because you just have to wrap it around the Generate Occurence function.

I was, actually, but I stopped after reaching First Class - they must have started making connection to programming in Life and beyond ;) It doesn't have to use a sequence structure, the reinitialize to defaults method would work as well ... but then you'd have to wire the error to both loops. So a little messier, maybe

Link to comment

I understand now... I think my brain is on autopilot.

That does eliminate the trailing Set Sequence, but the functionality doesn't change--it still makes loop B execute one "extra" time.

You are changing the requirements now :P

I started wondering how to prevent the extra occurrence, so I added a timeout and removed the tailing Set Occurrence

Link to comment

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.
Link to comment

If you ever undertake to write the queues or notifiers completely in G...

Not likely, since NI already provides a nice set of queue and notifier functions that fit my needs.

(Although it would be an interesting exercise... I wonder if reimplementing queues for LapDog would give a performance increase?)

Link to comment

post-5877-0-21875700-1317418800.png

Getting back to the topic at hand, upon closer examination I noticed problems with the original code relating to error propagation.

If whatever code you replace the placeholder with returns an error, the notifier will not signal, meaning when an error occurs the VI will always wait the delay before returning even if the error occurs immediately. Consider wiring either the notifier refnum or the boolean from the sequence frame to force execution order instead of the error cluster. Similarly you probably always want the FP to be closed, so the error should not propagate to the invoke node:

post-11742-0-27604400-1318605368.png

  • Like 2
Link to comment

If whatever code you replace the placeholder with returns an error, the notifier will not signal, meaning when an error occurs the VI will always wait the delay before returning even if the error occurs immediately.

Nice catch! (And another illustration of how the common practice of connecting all the error terminals can introduce subtle bugs.)

To extend your thought, if he follows your first suggestion and adds a Release Notifier function, which I think he said he would do, the effects of an error are a little different. (See top bd.) Releasing the notifier cancels the Wait On Notification function and returns an error. Unfortunately it also returns False, meaning the progress bar will open and immediately close. It's possible to add logic to eliminate that effect (bottom bd) but overall I like your implementation better. I think it more clearly communicates the intent of the code.

post-7603-0-58129400-1318807296_thumb.pn

Link to comment

Nice catch! (And another illustration of how the common practice of connecting all the error terminals can introduce subtle bugs.)

And you've also fallen foul of (reintroduced) the "close" property node being wired. An error on the wire means the dialog will not close (notice in Mje's example it is not wired)

Edited by ShaunR
Link to comment

Yes, a dirty little secret of mine is still even after 15 years, I find bugs in my code relating to "blindly" wiring error clusters through without thinking about it. Seems many of us are guilty of that in this thread. I find one of the most overlooked things when designing an application framework, no matter how simple the application, is at what level(s) the errors are handled.

I never thought of looking to see if the notifier was destroyed or not to check between a real timeout versus a notifier being destroyed. Alternatively, you could use the error status to signal the boolean (and also force execution order).

Edit: Withdrew a snippet I posted, problem with it.

  • Like 1
Link to comment

Alright, I'm too tired to code this up, but basically you don't even need to ever send the notification. When the placeholder code returns, just destroy the notifier. Meanwhile the FP will only be opened on the condition of a timeout AND no error returning from the wait primitive. Should satisfy the problem of the dialog flashing if the placeholder executes too fast for whatever reason (error or not). And of course make sure the invoke nodes have no error in terminals wired.

Link to comment

And you've also fallen foul of (reintroduced) the "close" property node being wired.

That was intentional because I was basing it off of AQ's original code with only the release function added.

Alright, I'm too tired to code this up, but basically you don't even need to ever send the notification.

Personally I still prefer your ealier implementation. I think explicitly sending the notification requires less thinking than boolean combinations of the WoN outputs.

Link to comment

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
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.