From Friday, January 17th 11 PM CDT (January 18th 5 AM UTC) through Saturday, January 18th 11:30 AM CDT (January 18th 5:30 PM UTC), ni.com will undergo system upgrades that may result in temporary service interruption.

We appreciate your patience as we improve our online experience.

LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Semaphores and queue together. Is it necessary?

Standard State Machine (Producer Loop)

This is what Felix is talking about when he referred to Damien's posts.  Start with a Standard State Machine.  Add a producer loop with a message queue.  In the state machine (consumer) loop, add an Idle case that handles all message dequeuing.  This image illustrates the concept.

 

StandardStateMachine 2_BD.png

 

 

 


Hi Daklu,

 

Is there any reason why the queue above cannot pass the state machine enum instead of a string which is then used to find the enum?

------------------------------------------------------------------------------------------------------
"Everything should be made as simple as possible but no simpler"
0 Kudos
Message 21 of 41
(3,169 Views)

Lucither wrote:

 


Hi Daklu,

 

Is there any reason why the queue above cannot pass the state machine enum instead of a string which is then used to find the enum?


Yes - Laziness when creating the Queue Smiley Wink

CLD; LabVIEW since 8.0, Currently have LabVIEW 2015 SP1, 2018SP1 & 2020 installed
0 Kudos
Message 22 of 41
(3,167 Views)

Lucither wrote:

Is there any reason why the queue above cannot pass the state machine enum instead of a string which is then used to find the enum?


Not inherently.  However, passing the state enum directly can impose some limits on the flexibility and clarity of your code.  For a completely contrived example, suppose the app has a Save Data button on the UI.  Before actually attempting to save the data, we want to make sure the data is valid.  How do we implement that?

 

A common response to this problem is to add a CheckIfDataIsValid state and have the UI send that state instead of the SaveData state.  The CheckIfDataIsValid state can then trigger the SaveData state if it confirms the data is valid.  This solution certainly works.  I don't particularly like it.  It tends to lead to state explosion and function machines rather than state machines, which IMO are much more difficult to follow.

 

A better solution is to create a CheckIfDataIsValid sub vi and put it in the SaveData state, casing out the rest of the save process if there is no data to save.  This creates a situation where the SaveData state doesn't always save the data, which can compromise clarity and hinder future extension.  What happens if I have situations where I want to save the data regardless of its validity?

 

My preferred solution is to check if the data is valid before invoking the SaveData state.  I'd implement this by sending a "SaveButtonPressed" message to the state loop.  The SaveButtonPressed message handling case in the Idle state calls the CheckIfDataIsValid sub vi and invoke the SaveData state only if the data is valid.

 

Getting back to your question, I could send the SaveData enum and still do the same checking in the message handler before deciding if the SaveData state really should be invoked.  I think this just leads to confusion.  If the UI is sending a state to the state machine, there is an expectation that the state is invoked.  Sending the state directly also couples the UI to the state machine.  If I want to give the user an option to save data regardless of its validity I have to create another state, SaveInvalidData.  Now I have a SaveData state and a SaveInvalidData state, which essentially do the exact same thing.

 

The whole point of having a UI loop and a Processing loop is to decouple the UI from the execution.  The obvious benefit is that the UI will continue to be responsive while the process is executing.  The less obvious (and arguably greater) benefit is the developer can modify the UI and the state machine independently.  Using the state enum as the message itself eliminates that benefit.

 

Granted, a lot of this comes down to personal preference and how you decompose your problem.  I generally decompose problems in very modular terms.  To me, the state machine is an abstraction of the core functionality of the application--the engine.  Each state in the state machine is a public method exposed by the engine.  LoadTestConfiguration, SaveData, and ExecuteTest are examples of core functional components.  They should be states.  CheckIfDataIsValid is the responsibility of the application's supporting code, not the engine, and should not be a state.

Message Edited by Daklu on 04-20-2010 07:34 AM
Message 23 of 41
(3,152 Views)

Hi Daklu,

 

I understand where your coming from, nice clear response. Has given me something to think about as i have to admit that sometimes i fall into the trap of writing 'Function machines' as you have called it. Just another quick question though. Why do you use a string value. You could still implement what you are saying but by using a seperate enum typedef specifically for the queue. I always thought it was better to use an enum for attaching to a case selector then a string.

 

I hope you dont think i am just trying to catch you out on something, i am genuinly interested, in case i am missing something.

 

Rgs,

 

Lucither

Message Edited by Lucither on 04-20-2010 10:35 AM
------------------------------------------------------------------------------------------------------
"Everything should be made as simple as possible but no simpler"
0 Kudos
Message 24 of 41
(3,134 Views)

Lucither wrote:

Why do you use a string value. You could still implement what you are saying but by using a seperate enum typedef specifically for the queue. I always thought it was better to use an enum for attaching to a case selector then a string.


In the sample I posted I left the message as a string simply because it didn't affect what the sample was intended to illustrate.  If you're more comfortable passing an enum instead of a string that's fine--just make sure you have a message enum and a state enum.

 

Using an enum is safer in that you don't have to worry about misspelling one of the messages.  Whether or not it's better is a subjective evaluation.  Sometimes (for quick and dirty vis or examples) it's simply not worth it (to me) to set up a typedef specifically for message names.  In situations where other vis will be posting messages on the queue and you don't want to have to refer back to the case structure it makes more sense to code defensively and use a typedeffed enum.

 

Truth be told, when I set up a message queue for an application the message always has the ability to carry data with the it.  For small apps I'll create a message typedef that includes a message name field (string or enum) and a data field (variant or string.)  More commonly I'll have a message class and create subclasses for each kind of message that can be posted.

Message 25 of 41
(3,116 Views)