04-10-2019 05:15 PM
Hi,
I would like to acquire data in a producer loop and afterwards process it in the consumer loop. I would like to stop the consumer loop when the producer loop is done. Therefore, I took a look at the notifiers available in LabVIEW. However, I was not able to prevent the consumer loop from crashing after I depopulated the queue. I attached a demo VI to this post. Do you have any idea what I am missing in my system design?
Thanks!
Peter
04-10-2019 05:23 PM - edited 04-10-2019 05:30 PM
The Destroy Queue belongs on the queue reference wire that would come out of the consumer loop, not the producer loop that you have now.
But then you'll find that your VI won't error out, but it still doesn't end the consumer.
The best way to do that is get rid of the notifier. Send a message through the queue after the producer loop stops that tells the consumer when to end. This is called "sentinel" value, value that would not occur in normal data, but is only sent when you want the program to stop. This might be an empty array if you are sending arrays (assuming an empty array doesn't occur during normal operation). In this case, you could enqueue a NaN value after the producer loop. When you detect the value in the consumer is NaN, then you send at true to the stop condition.
04-10-2019 05:25 PM
Simply enqueue an Exit (or whatever you want to name it) state to your queue. Have the corresponding state in the consumer exit the loop.
04-10-2019 05:28 PM - edited 04-10-2019 05:28 PM
@RavensFan wrote:
The Destroy Queue belongs on the queue reference wire that would come out of the consumer loop, not the producer loop that you have now.
I usually merge all my error wires coming from all my loops and put stuff like destroying queues after it. That way I know all my loops have completed before things are destroyed.
04-10-2019 06:55 PM
In simple cases you can stop it on error because releasing the queue will generate an error terminating the wait (you can even add a case structure so the consumer code is skipped when that occurs).
If you want to guaranteed that all remaining queue entries are processed, add a slow loop after the FOR loop but before the queue release that checks the queue status until it is empty.
04-10-2019 09:42 PM
You might also just want to use a channel wire if it is just a simple producer consumer. The stream channel handles the communication between the two loops as well as stopping only after all elements are consumed.
04-11-2019 07:39 AM - edited 04-11-2019 07:52 AM
Yes, the Stream Channel Wire has the "sentinel" (mention by RavensFan's initial reply to this Post) built-in. This is one reason I'm such a fan of Channel Wires, and have rarely used Queues since LabVIEW 2016 was released. The key step is to understand the direction of Information Flow, and to arrange the code so that the sender sends an "I'm all done, I won't be sending you any more information" signal, but does not do anything "destructive" to the communication "channel" (Queue, Channel Wire, Notifier, Global Variable, etc.), leaving that duty to the receiver after they detect the "all done" signal and handle it appropriately.
As RavensFan points out, with Queues, one can send a "unique" piece of data after all the "legitimate" data has been sent (I advocate doing this in a Producer/Consumer design after exiting from the Producer loop). When the Consumer detects this value, it knows it should exit, and can then safely release the communication path (or Release the Queue, in this case). For the Stream Channel Wire, this is built into the Writer and Reader -- after the Writer sets the "last element?" flag, which prevents the Stream from accepting any more data and sets a corresponding flat in the corresponding Reader that can be used by the Consumer to end its loop (the Stream Channel does not need to be explicitly "Obtain"ed or "Release"d).
Bob Schor
04-11-2019 10:05 AM
This is what Altenbach suggested in pictures and VIs. (I use something similar for debugging) Be careful of the last value. When you destroy the queue the last value with be the default value, not the last real value. See below.
As other have said channel wires are useful, or a sentinel value works. For example, after the for loop send a value of -1 instead of querying the status of the queue. Rather than stop on an error, stop the while loop if the value is less than 0.
mcduff
04-11-2019 12:28 PM
Can we all agree that, no matter what the communication paradigm between Producer and Consumer, that communication must be maintained until the Consumer reads the last valid data sent by the Producer? A "last element?" signal sent from Producer (who knows when it stops sending data) to the Consumer tells the Consumer when it can exit, and when it does, then both Consumer and Producer are finished communicating and the "pathway" can be abandoned/released/destroyed without generating "errors" or risking missing data. There are many ways to do this, but something that flows along with the data seems (to me) to be the simplest and most fool-proof.
Bob Schor
04-11-2019 12:36 PM
@Bob_Schor wrote:
Can we all agree that, no matter what the communication paradigm between Producer and Consumer, that communication must be maintained until the Consumer reads the last valid data sent by the Producer?
I actually disagree. The original requirement was to stop the consumer when the producer is done. It was not specified that all queued data needs to be processed. 🙂