06-16-2022 07:13 PM
I have a VI with 2 while loops running in parallel (Loop1 & Loop2). I would like to have Loop1 set/clear a flag and Loop2 check that flag and act upon its value. I suspect there are more than one way to accomplish this.
Excuse my ignorance but can I create a Boolean indicator (Bool1) that Loop1 can set/clear and have Loop2 check the value of a Reference or Local Variable based on Bool1?
I also read that Channel Wires are a feature that can help achieve this.
Thanks
AJ
06-16-2022 08:19 PM
Local Variables and References (as well as Global Variables) are, indeed, ways to ignore the Principles of Data Flow. Prior to the "official" release of Channel Wires in LabVIEW 2016, a variety of other mec hanisms (found on the Synchronization sub-Palette), such as Queues and Notifiers.
One of the (significant!) differences between "Synchronizers" (for example, Queues) and Local/Global Variables and References is what I might call a "Cause and Effect" relationship. Take the example of two While Loops with one Stop Button in Loop 1 and a Local Variable of the Stop Button in Loop 2. Start the Loops running at the same time. Will they stop at the same time? You can't tell -- did Loop 1 set the Stop before or after Loop 2 read its value?
So that's one virtue to, say, using a Queue to "synchronize" the exit from two While Loops. The Stop button in Loop 1 goes to the Loop 1 "Stop" indicator, and also into a Queue that gets De-Queues in Loop 2, where it goes to the Loop 2 "Stop" indicator. Loop 2 cannot exit before Loop 1 puts "Stop" into Queue -- since everything goes into "Wires" (counting the Queue as a "kind of wire"), and you can keep these wires (temporally) "short" and next to their respective "targets",
Asynchronous Channel Wires provide (in my humble opinion) a better metaphor (and also a better implementation) for asynchronous communication (which, paradoxically, you need to "synchronize" loops) because the "Channel Wire" goes "out" from the right end of the Writer, and "in" to the left end of the Reader, the same direction that data flows in every other LabVIEW structures. For Queues and Notifiers, the connecting "wire" comes out the left end of both "Enqueue" and "Dequeue", which makes it appear that data "flows backwards" from the Enqueue function. [I won't go into why this is only "confusing" ...].
In any case, if your goal is to have loops end at the same time, you want to use some kind of Synchronizer, whether from the Synchronization sub-Palette or Asynchronous Channel Wires.
Bob Schor
06-17-2022 08:16 AM
@AJ3D wrote:
Excuse my ignorance but can I create a Boolean indicator (Bool1) that Loop1 can set/clear and have Loop2 check the value of a Reference or Local Variable based on Bool1?
I also read that Channel Wires are a feature that can help achieve this.
You can, but it's not good form, as mentioned.
What you probably want is a Queue, Notifier or as you said, a Channel Wire.
06-17-2022 08:41 AM
@Bob_Schor wrote:
For Queues and Notifiers, the connecting "wire" comes out the left end of both "Enqueue" and "Dequeue", which makes it appear that data "flows backwards" from the Enqueue function. [I won't go into why this is only "confusing" ...].
Bob Schor
Can you explain further what you mean? When I Enqueue something the data goes in on the left. When I dequeue something the data comes out on the right. Is the queue reference confusing? I understand that the queue reference doesn't come out from the enqueue and go to the dequeue (well, I guess it could, but then what would be the point of the queue, lol). Is that what you are referring to? I never thought of the data as flowing through the reference wire. I'm just curious as I've seen others talk about queues being confusing and I always found them to be very straightforward. Channel wires to me seem to be more confusing since they are wires that break dataflow.
06-17-2022 11:42 AM - edited 06-17-2022 11:44 AM
@johntrich1971 wrote:
@Bob_Schor wrote:
For Queues and Notifiers, the connecting "wire" comes out the left end of both "Enqueue" and "Dequeue", which makes it appear that data "flows backwards" from the Enqueue function. [I won't go into why this is only "confusing" ...].
Bob Schor
Can you explain further what you mean? When I Enqueue something the data goes in on the left. When I dequeue something the data comes out on the right. Is the queue reference confusing? I understand that the queue reference doesn't come out from the enqueue and go to the dequeue (well, I guess it could, but then what would be the point of the queue, lol). Is that what you are referring to? I never thought of the data as flowing through the reference wire. I'm just curious as I 've seen others talk about queues being confusing and I always found them to be very straightforward. Channel wires to me seem to be more confusing since they are wires that break dataflow.
Everything that can synchronize two parallel processes DOES "Break Dataflow." What that really means is that some data communication must exist between multiple running sections of code. All of them can be confusing if the only thing you think about is "Dataflow" where each node only starts when all inputs are ready and only ends when all outputs are computed.
The "Best" choice for your needs always requires two answers:
Other factors can come into play as well. Like, is the source really an "Event" like an alarm or a User Choice? Or is it maybe a large set of shared Data that should avoid copies and a DVR would be better.
When you look at the communication path from those positions you can chose from the available Language Elements.
In what you described I would raise a User Event based on the condition that changes the value of the Boolean. Others would use something else.
06-17-2022 11:59 AM
@JÞB wrote:
@johntrich1971 wrote:
@Bob_Schor wrote:
For Queues and Notifiers, the connecting "wire" comes out the left end of both "Enqueue" and "Dequeue", which makes it appear that data "flows backwards" from the Enqueue function. [I won't go into why this is only "confusing" ...].
Bob Schor
Can you explain further what you mean? When I Enqueue something the data goes in on the left. When I dequeue something the data comes out on the right. Is the queue reference confusing? I understand that the queue reference doesn't come out from the enqueue and go to the dequeue (well, I guess it could, but then what would be the point of the queue, lol). Is that what you are referring to? I never thought of the data as flowing through the reference wire. I'm just curious as I 've seen others talk about queues being confusing and I always found them to be very straightforward. Channel wires to me seem to be more confusing since they are wires that break dataflow.
Everything that can synchronize two parallel processes DOES "Break Dataflow." What that really means is that some data communication must exist between multiple running sections of code. All of them can be confusing if the only thing you think about is "Dataflow" where each node only starts when all inputs are ready and only ends when all outputs are computed.
Oh, I realize this. I was just curious about Bob's reasoning as to me the break in data flow is more apparent in queues and notifiers than it is in channel wires. All of the approaches suggested here are valid, and depending on precise use cases some may be better suited than others. For the generic use case given I think that the OP would be reasonable to use whichever of the proposed solutions he is most comfortable with.
06-17-2022 01:04 PM
Well let me explain the BS reason. Bob Schor likes Channels
Inspection shows both sections of the code do exactly the same thing both have unlimited (but limitable) elements that can be sent from loop to loop each will behave the same and except that the dice won't roll the same numbers they are two ways to do the exact same thing. The only difference is how the data appears to flow along the Queue Reference or Channel wires.
06-17-2022 03:05 PM
Yes, JÞB, that is exactly what I mean. With LabVIEW, we "go visual" and can "see" the data moving around in "wires", generally going Left-to-Right (I wonder if the flow is reversed where Hebrew or Arabic are the major written languages -- no, that's just silly ...).
And I do like Channels. Besides the "improved Metaphor" for Data Flow (going out the right side of the Writer and into the left side of the Reader), I also appreciate the built-in Sentinel in the Stream Channel (the LabVIEW 2019 Producer/Consumer Template still shows terminating the Queue by releasing it on the Consumer side, which generates a (deliberate?) error on the Consumer.
For those who are interested, the safer way to signal that a Queue can be terminated is to use a Sentinel. The Producer, which gets (or generates) the data first, and thus "knows" when no more data needs to be sent, sends one last "special" piece of data, the "Sentinel" to the Consumer, and then exits. It does not release the Queue, as it has no idea if the Consumer has finished processing the zillions of earlier Queue elements, so why run the risk of erroring out the Consumer?
One typical scenario (and "obvious" Sentinel) arises with Data-driven Producer/Consumers -- the Producer is something like a DAQmx Read that sends an Array of data (or some other data structure that has a non-zero size). When the Producer wants to quit, it sends an empty Array (of the appropriate type -- if you are using Waveforms, send a Waveform with Y being an empty Array). The Consumer simply looks at the data, and if it sees the special "This is the signal that you've processed all the data and can exit", it takes the Case Statement branch that does nothing except stop the enclosing While Loop, bringing the Queue Reference out of the Consumer Loop where it can safely be Released.
Bob Schor
06-20-2022 07:02 AM
@Bob_Schor wrote:
One typical scenario (and "obvious" Sentinel) arises with Data-driven Producer/Consumers -- the Producer is something like a DAQmx Read that sends an Array of data (or some other data structure that has a non-zero size). When the Producer wants to quit, it sends an empty Array (of the appropriate type -- if you are using Waveforms, send a Waveform with Y being an empty Array). The Consumer simply looks at the data, and if it sees the special "This is the signal that you've processed all the data and can exit", it takes the Case Statement branch that does nothing except stop the enclosing While Loop, bringing the Queue Reference out of the Consumer Loop where it can safely be Released.
This is a further argument to use the Streaming Channel Wire for a Producer/Consumer.
What if the producer has a recoverable error and therefore the waveform is empty due to the error instead of the sentinel actually being sent? A couple of options would be to not send the data if there was an error or to add the sentinel to the waveform data variant.
Now what if the producer has a non-recoverable error? You need to make sure that error does not interfere with the sending of the sentinel (the error wire cannot be directly wired to the Enqueue Element that sends the sentinel).
I think I have only created 1 Producer/Consumer since seriously considering Channel Wires, and I used the Streaming Channel. The built-in sentinel solves the above issues.