04-26-2019 02:36 PM
Hello,
I've been playing around with the queue event state machine notion combined with a functional global variable, and can't seem to get passed a certain bug (I've searched but no results came up with the same problem).
I've attached a simple VI and subvi. The main VI consists of a producer and consumer loop, event structure in the producer loop, case structure in the consumer loop to handle processes
The problem I am facing is that the consumer loop goes through an extra iteration upon stopping the producer loop and releasing the queue. Further, during this extra iteration the dequeue element spits out an extra item that I can not track down. The queue should be empty, so where does this extra element, which is always 0 ("Initialize") in this case, come from? I've tried adding a "Read" to the stop event, which does enqueue a "Read", but the extra (last) element is always 0 ("Initialize").
Solved! Go to Solution.
04-26-2019 02:51 PM
You are stopping your loop by destroying the queue reference. When you destroy the queue reference, the dequeue operation dequeues the "default" value of the queue data type, which for your case is 0.
You can avoid writing to your FGV by wiring a error case structure if you want to keep the same structure.
See below.
mcduff
04-26-2019 03:24 PM - edited 04-26-2019 03:34 PM
Thanks for the quick reply! Did not know that the queue releases the data type itself at the default value after the reference is destroyed.
In this case, to maintain the same structure would I implicitly stop the consumer loop instead of wiring the error out of the dequeue to stop?
edit: attached my alternative that maintains structure.
04-26-2019 03:34 PM
@srv535 wrote:
Thanks for the quick reply! Did not know that the queue releases the data type itself at the default value after the reference is destroyed.
In this case, to maintain the same structure would I implicitly stop the consumer loop instead of wiring the error out of the dequeue to stop?
If you are referring to adding a stop or using a local variable, I would recommend against it.
Add an "Exit/Stop" State to you Enum, then stop your consumer when it gets the command. See below. Also make your enum a type-def. Then destroy your queue from the consumer loop.
mcduff
04-26-2019 03:40 PM - edited 04-26-2019 03:42 PM
From the examples I've seen, users always seem to release queues upon stopping their producer loop. Is it better practice to release queue when stopping the consumer loop?
04-26-2019 03:45 PM
That is up to you.
Consider your producer is much faster than your consumer, if you destroy the queue when the producer is finished (the consumer is still working) you will lose data. Does your application depend on this data, I do not know, that is why I said it is up to you. But you will lose data/states etc, if you destroy the queue before the consumer is finished.
mcduff
04-26-2019 04:49 PM - edited 04-26-2019 04:51 PM
@srv535 wrote:
From the examples I've seen, users always seem to release queues upon stopping their producer loop. Is it better practice to release queue when stopping the consumer loop?
Yes!! (IMHO). Think about it --
Bob Schor
P.S. -- I learned about Sentinels (and their use in Queues) a few years ago in a book on "Advanced Fortran Programming" (that's not the title, but a description of the content).
04-26-2019 05:27 PM
I do remember using the queue producer/consumer structure for simply recording and processing data on one project as the processing was much slower than recording (placing the data acquisition and processing in one loop was extremely slow). I was under the impression that the consumer loop continued even after the producer loop stopped until the queue was empty. This is why I placed Flush Queue before Release Queue in this example so that we empty the queue before releasing, thus stopping the consumer loop immediately.
04-26-2019 05:38 PM
@srv535 wrote:
I do remember using the queue producer/consumer structure for simply recording and processing data on one project as the processing was much slower than recording (placing the data acquisition and processing in one loop was extremely slow). I was under the impression that the consumer loop continued even after the producer loop stopped until the queue was empty. This is why I placed Flush Queue before Release Queue in this example so that we empty the queue before releasing, thus stopping the consumer loop immediately.
The "flush" occurs at that function, all the elements in the queue are released there. You can check by wiring up an array to that output by the queue. Once flushed the data is gone, your dequeue will not see it. (You would flush your Exit/stop command, so your bottom loop would not stop unless it was to stop on error.)
mcduff
04-26-2019 05:44 PM
Its "One of those things" computer science academics an esoteric programmers disagree on.
Purists will rant that releasing the queue in the producer is technically better practice. I won't argue that point but, always use an exit message myself and dump the queue after both loops finish. Practical mysticism that may make the compiler's job a bit harder costing a few nanoseconds of CPU time. Or not... certainly not impacting anything that I am likely to use LabVIEW for.