LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Flush Channel Messages

Solved!
Go to solution

I'm using the Channeled Message Handler (CMH) template for an application. I have one of my parallel While loops (call it "Loop A") sending itself a message each iteration, to define its next message case (e.g. "initialize" --> "do something" --> "do something" --> "do something"...). I'd like my Event Handling Loop to send a "stop" message to Loop A that breaks the "do something" chain of messages WITHOUT completely exiting Loop A. That way, I can eventually restart the "do something" chain without having to restart the application.

 

The problem I encounter is that there's always at least one more "do something" message waiting after my "stop" message executes in Loop A. So unless I exit the While loop completely, Loop A continues running "do something" after it processes the EHL's "stop" message.

 

Is there something like a Flush Queue VI, but for Channels instead of Queues? What's the best practice for handling this?

0 Kudos
Message 1 of 12
(3,166 Views)

There isn't a "flush" option that I am aware of, but when you create a reader or writer there should be a "With abort" option.  If you use that on the reader and writer, you could get essentially the same effect if you check for the "Abort" output on the reader before proceeding.

 

I've only got 2018 installed here so I can't look at your code to confirm it should work for you, and I can't be sure the interface looks the same in your version.  But when you create an endpoint it hopefully has a dialog like this allowing you the choice:

Kyle97330_0-1646346915607.png

Edit:  On reading your message closer it looks like this might not be good enough since you want to resume later and there's not really an option to turn off the Abort signal.

 

Perhaps instead you'll have to change the channel wire to send a cluster instead of a single value and the cluster has extra commands available that you could use as a signal to do things differently.

 

If you want to mimic a "flush queue", you could probably get pretty close by setting the timeout to zero instead of the default -1 infinite wait, and put it in a while loop that only terminates when it gets the timeout signal.

0 Kudos
Message 2 of 12
(3,156 Views)

Thanks for the suggestions, Kyle97330. I've saved the project for LabVIEW 2018, so feel free to take a look at that if you want to confirm anything / test it out. I do have the same options for adding an "Abort" but you're right that that's undesired because it would end the loop.

 

Interesting thought on the timeout, perhaps I'll give that a try... if not, I agree we'll probably have to use some more detailed message data to change the way things are handled in Loop A.

 

Note: I didn't rename the MHL in the template to "Loop A", but they're the same thing in this example.

0 Kudos
Message 3 of 12
(3,143 Views)

When I first encountered the Queued Message Handler Template, I spent several days studying it, and still was baffled by its complexity.  So I wrote my own, very simple, fast, and "intuitive".

 

Then in 2015, I "discovered" Asynchronous Channel Wires (as they were then called).  About a year or so later, all of my code using Queued Message Handlers were replaced with Channel Message Handlers (I'm not sure, but I may have "invented" this term), and have used it ever since.  My CMH is very simple.  The Send Message just bundles an Enum (which I call the "State") and a Variant (which I call "Data", usually blank) into a Type I called a "Message" (all Types are in TypeDefs) and outputs a Messenger Channel.  Receive Message does the opposite -- accepts a Messenger Channel, unbundles, and outputs "State" and "Data".

 

Here is a little 4-State example, as a Snippet.  It is so trivial that you should be able to recreate it from this description (and a "Picture", in case you don't have LabVIEW 2021).

CMH Example.png

There are two Controls that are handled by the Event Loop.  "Next", as shown, puts the "New Data" State into the CMH, while "Stop" (not shown) puts "Exit Data" (with the Stop control wired to the Event While Loop to stop it, letting the Exit Data case in the Message Loop stop the lower loop).

 

The first two States, Init Show and Init View (not shown), simply wire the current State (from the Case Statement Selector) over to the "Next Show State" (or "Next Message") VI, making these two Cases simply repeat themselves, over and over (at the rate of 1 Hz, so you can see it happening).  How do you break out of this endless loop?  You "Flush" the Channel, as shown in the illustrated New Data case.  All you need to do is to read, and discard (or decide if you really want to discard) the "old" State, and substitute a New State.

 

This is a very simple example I cooked up to illustrate one way to solve this question.  I've been happily Using and Abusing Channel Wires since their invention, and consider them one of my favorite LabVIEW features.

 

Bob "Channel Wire" Schor

0 Kudos
Message 4 of 12
(3,117 Views)

Thanks Bob, this is a simple and effective solution! I tested it out in my own code ("solution - flush one message (2018).zip", attached) and can successfully stop and restart Loop A now.

 

I also implemented a version that flushes all remaining messages after the stop button is pressed ("solution - flush all messages (2018).zip", attached). The functionality can be verified by pressing the "Restart Loop A" button multiple times before pressing the stop button: it still reads the messages FIFO-style, but once it reaches the stop message, it flushes all remaining messages by using another While loop (a timeout of 5ms indicates there are no remaining messages and stops the While loop).

0 Kudos
Message 5 of 12
(3,089 Views)

You're sure it's "safe" to ignore the rest of the data in the channel?  It's not data that you need?  So far I've seen solutions to flushing the channel data, but is that really what you want to do?  Normally data left in the channel is data that came in before you attempted to stop the channel.  You could be missing data and not even know it.  Instead of flushing the channel, maybe you want to add a message at the end to say "stop processing" so you know all the data has been gathered and/or processed?

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 6 of 12
(3,042 Views)
Solution
Accepted by topic author jrdwight

@jrdwight wrote:

I have one of my parallel While loops (call it "Loop A") sending itself a message each iteration, to define its next message case (e.g. "initialize" --> "do something" --> "do something" --> "do something"...). I'd like my Event Handling Loop to send a "stop" message to Loop A that breaks the "do something" chain of messages WITHOUT completely exiting Loop A. That way, I can eventually restart the "do something" chain without having to restart the application.

...

 

What's the best practice for handling this?


The best practice for this is to NOT use the design of sending a message to yourself to implement periodic behavior.  That is an all-too-common poor practice.  Leads immediately to problems like the one you have, which lead to "solutions" that can introduce rare race conditions, like flushing an important message.

 

Added: I looked at your solution and tried the common User error of double-clicking the Restart button, then double clicking the Stop button: it did not stop.   Two Restarts queued up two "Do Something" messages, then the first "Stop" flushed the second "Stop".  Hit "Stop" again: still didn't stop (as there were still two "DO Something" messages circling).  

 

You can keep on duct-taping the new problems you create with your previous fixes, or you can revisit your original design. 

 

Here I have modified your solution to use the timeout case and a timeout in a shift register.   No Flush and no sending a "Do Something" message.  This has none of the race conditions caused by over-eager button pressing.

 

 

0 Kudos
Message 7 of 12
(3,032 Views)

Fair point. In my specific application, it's safe to ignore the rest of the data, but I can see why this wouldn't be appropriate for all applications. More on this below...

0 Kudos
Message 8 of 12
(2,978 Views)

drjdpowell, I see how your solution avoids race conditions. How would this be modified to perform some task repetitively (e.g. reading data from a DAQ)? Should the case structure for the iterative task contain an internal while loop, with a separate Tag channel that can be used to stop that while loop?

0 Kudos
Message 9 of 12
(2,975 Views)

That solution already is doing things repetitively.  As long as the timeout is zero, it is behaving just like the "send-message-to-self" design you had, just without race conditions on start and stop. 

 

0 Kudos
Message 10 of 12
(2,965 Views)