LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Queued Message Handler; Problems with Slave stopping the Master

Solved!
Go to solution

Hello Community,

 

after some research in different posts here with seemingly similar but as it turns out different problems, I find myself at a point where I can´t find a solution to the following Problem, so I hope for help from the community:

I am playing around with the queued message handler to get used to it´s possibilities for later implementation.

In my current program (see attached) I am simulating a possible error with a boolean switch during the initialisation of devices.

Apart from the occurance of an error, the program acts as espected (boolean switch = false) - the slave loop changes cases as the master commands and also stopping the program by clicking the stop button is no problem.

BUT: If the boolean switch says true (before starting the program), the program does not stop.

With the higlight executiion I could identify the master loop as the reason, which is waiting in the idle case for an event to happen wihtout changing to the stop case.

Why is that and how can I realize the program stop after an initialisation error? - the event structure is needed though, because of possible additional actions independent of the slave loop.

QMH_test.PNG

Two Versions of my program: for LV16 and for LV10...hope everyone interested to help can open it.

Download All
0 Kudos
Message 1 of 9
(3,827 Views)

The event structure starts waiting for a value signaling when it's executed. So that is after the queue element is received. You can change that with a dynamic event registration if you really want to (events are registered when registering the dynamic event). But I thing you're making things too complicated with two queues. You try to make a (producer\consumer)\(consumer\producer) construction. Both loops are producer and consumer. That's asking for deadlocks and\or livelocks. I thing you want to change the slave queue to a state, not a queue. Maybe a channel wire, set to 'tag' with an enum type def? I'd recommend an enum type def as queue data type as well. Strings are painful when you need to change them.

Message 2 of 9
(3,805 Views)
Solution
Accepted by topic author B1GB0SS

Please forgive me for wearing my Professor Hat, but every once in a while, there is Another Chance to Teach.  So I'm attaching my version of your Program, with lots of (minor) modifications, that I'll try to explain.  Note that this does not invalidate Wiebe's response -- I agree that a Dynamic Event is the "better" way to get certain kinds of data "injected" into an Event Loop, but I'm going to try to stick with simple Value Changed and Timeout Events.

 

The first thing is to realize that this is basically a Producer/Consumer design, with the "Master" (top) loop generating most of the "Messages" and the "Slave" (lower) loop both "consuming" and, in some instances, also "generating" them.  I confess that it wasn't until I started modifying your code that the "Aha!" light went on in my head -- I realized that at least part of the problem you had was the old "Stopping" Problem of how to get the Producer to stop when the Consumer encounters an Error.  This is often a slightly tricky problem, and the solution can look a little messy, but I hope to show you it's not too bad.

 

So let's dive in.  I'm going to put a Snippet here for reference, but will also attach the VI (2016) for you to really examine and test.

QMH BS (2016).png

  • The (single) Queue is unnamed.  Since there is only one queue and I'm always using the Queue explictly by attaching to its wire, I don't need named Queues.  This simplifies things a lot.  In particular, Queue data is (mostly) from Master to Slave, though there is occasional Slave-to-Slave messaging.
  • The Queue Reference does not require a Shift Register -- it is a static structure (only its contents change).  This is a minor point, but worth understanding.
  • I changed the Play and Media Stop buttons to their default "Latch until Release" Action (as this is designed for the Event Structure), and also added an Error! button to directly simulate an error in the Slave (which is, after all, what you want to test).  You'll see that the Error! button is in the Slave loop -- I left it as Latch until Release, which avoids generating endless Errors.
  • As you can see, I added a Timeout Event that fires 10 times a second, slow enough to not have any appreciable effect on the code, but fast enough that its purpose, to initialize the Master status indicator and the Abort indicator, get done when the program starts.
  • The Slave (Consumer) loop now has two "outer" guards -- one to allow you to generate an Error by pushing the Error! button (the False, "No Error Requested" case is illustrated here, as this is where the routine normally lives) and an inner Error Case that handles the Error generated when we do push the Error! button.  I'll talk about this later.
  • The main part of the Slave, the code shown in the No Error Case, is slightly modified from yours.  I put the 1 second timer outside the loop so that you can see the transitions from, say, Init to Idle, and from Abort to Stop, more easily.  I also pulled the Counter out so that it is always shown no matter the Message.
  • So let's talk about the "Error-free" behavior of this system, where we don't have to worry about Errors in the Slave.  The program starts with Init on the Queue, which is displayed on the Master State.  The Slave, getting Init, puts Idle on the Queue, which comes right back to the Slave and causes it to switch to Idle.  When Play is pushed, both Master and Slave show the Play state, and the Slave keeps putting Play on the Queue causing it to loop and the Counter to increment.  When Media Stop is pushed, the Master both enqueues Stop and exits its While loop, doing nothing else to the Queue, since we still need the Queue "alive" for the Slave.  When the Slave gets Stop, it stops itself, Releases the Queue (since it "knows" that the Master has stopped, so noone needs the Queue anymore, and exits.
  • So what happens when we push the Error! button?  The Slave actually generates an Error, 5002 (a User-defined Error).  That's all that happens in that loop.  The next time through, Error! is false (because I made it Latch when Released) and we fall through to the inner "Error Case" structure.  The Error Case (not shown here, but visible in the actual VI) does two things -- it clears the Error and sets the Abort indicator's Value Signaling Property to True.  This indicator does not have a Latching behavior, so we can safely use Value Signaling.  This, in turn, triggers a new Master Event that puts the new Abort message on the Message Queue and then, like the Stop Event, exits the Master Loop.  Finally, as illustrated, the Abort Event in the Slave calls the Stop Event (also in the Slave) to stop the Slave, and stop the Program.
  • Why have a separate Abort event?  This is "good practice", as you might want to execute additional code when you Abort before going on to final common code when the program Stops.
  • So what else?  Well, if I were coding this, I would not use Strings as my messages, but would create a State Enum having the values Init, Idle, Play, Abort, and Stop.  The Enum vs String Debate has pros and cons on both sides.  Here are some of my reasons for preferring Enums:
    1. I don't have to worry about "exact spelling and capitalization", i.e. "idle" vs "Idle" -- it's all in the Enum.
    2. My Case Statement can be initialized (during development) using "Add Case for Every Value" to remind me which Cases still need code.
    3. I don't need a Default case to catch mis-spellings or mis-capitalizations.
    4. If I decide to Add a State (or remove one), a plethora of Errors will result and clue me where I need to look at existing code.

Whew.  Hope that all makes sense and you find it useful.

 

Bob Schor

Message 3 of 9
(3,788 Views)

One thing Bob said can't be stressed enough. Do not name queues unless you have to. Naming queues has it's usefulness: when other threads need access to the queue. Therein lies the problem. You naming the queue tells others the queue is potentially accesses somewhere else. Also, other queues (in code made by others) might use the same name but be completely unrelated. Some use the vi name as queue name. This can cause the most obscure bugs... Don't name queues if you don't need to.

 

Also, give the data type of the queue a label and the context help will show that label. Useful when debugging if you have lots of queues.

Message 4 of 9
(3,767 Views)

Hey Bob,

 

thanks for your remarks so far.

The program you attached contained no changes.

I would like to work through your remarks along with your version of my program so it is easier for me to understand.

Could you upload the changed version?

 

 

Regards

0 Kudos
Message 5 of 9
(3,734 Views)

Hey wiebe,

 

I am not familliar with dynamic events but after reading the LabVIEW Help on this topic, I am wondering if it is possible to have the slave loop create the value change event for the media stop button,

Wiebe and/or Bob do you have an idea?

 

I am really thankfull for every helpfull advice.

Please waer all your "Professor hats". 🙂

 

 

Regards

0 Kudos
Message 6 of 9
(3,729 Views)

That's very odd!  I checked the file of that name on my PC, and it was, indeed, the file I showed in the Snippet.  But when I downloaded it, myself, it was your original file.  Weird.  I'm going to try again ...

 

Bob Schor

Message 7 of 9
(3,720 Views)

I just checked -- this time it is the right file.

 

Incidentally, do you know how to use Snippets (the "picture" in my earlier post)?  Open a blank VI, go to its Block Diagram, and drag the picture into it.  It should "automagically" transform into the LabVIEW VI that was used to create it.  This is a feature NI introduced a few years ago, and can be found on the Edit menu (Create VI Snippet from Selection).

 

BS

Message 8 of 9
(3,717 Views)

Bob,

 

after understanding what you have done in your version of my program, I got it working!

There are many (little) things I did not know so far so I learned a lot through your help.

For example I now used the Value (Signaling) Property Node for the first time, which was exactly what I needed.

Furthermore I was (again) reminded to keep things simple...just one Queue named only when needed with no state machine in the master loop.

 

Also thanks to wiebe for giving me a push into the direction of dynamic events...the example vi from NI where you can drag a picture is pretty nice.

 

I attached the working version so maybe people with a similar problem can have a look.

 

 

Regards

Message 9 of 9
(3,699 Views)