Download as pdf or txt
Download as pdf or txt
You are on page 1of 15

The Wayback Machine - https://web.archive.org/web/20130918185344/http://expressionflow.

com/2007/10/labview-queued-state-machine-architecture/

HOME DOWNLOADS ABOUT SUBSCRIBE

LOGIN

Login

Register

Oct LabVIEW Queued State Machine Architecture RECENT POSTS


01 by Anthony Lukindo, Oct 1, 2007 at 7:00 am
Presentation on LabVIEW
(56 votes, average: 4.54 out of 5) recursion
 Loading ...
Joining The JKI Dream Team
of LabVIEW Developers
Summary
100k visits
The Queued State Machine -Producer Consumer architecture; abbreviated in this article as QSM –PC, is one essential
Tweet Unlimited parallelism &
architecture that significantly facilitates programming mid-sized to advanced LabVIEW –based projects that constitute 100 concurrency with recursive
or more VIs. A common application for the QSM -PC architecture is in programming LabVIEW’s event structure to send commands for dataflow

asynchronous processing in a parallel loop so that event cases can exit code execution quickly and avoid GUI lockup. Another application Worker pool – a design pattern
for parallel task execution in
is in multiple parallel VI programming such as in parallel data acquisition, alarm monitoring, and results analysis, where this method
LabVIEW
empowers any parallel VI to send and receive commands and data across other parallel VIs with no data loss.
RECENT COMMENTS
In light of the intermediate to advanced nature of the objects that make up the QSM –PC architecture, taking full advantage of this
template requires detailed knowledge of the ‘why’ and ‘how’ of its various characteristic design aspects. This article defines, illustrates, Jared on Introduction to
and describes at length the various elements of the QSM –PC architecture and includes a LabVIEW example of this implementation with generic programming with type
parameters
detailed narrative comments.
Great Resource for Learning a
Note that you can access a queued state machine producer consumer design template that ships with LabVIEW from a VI, or a project Common Architecture for
LabVIEW Applications |
menu, by selecting: [File] >> [New...] and then from the ensuing dialog, and in the [Create New] treeview, choose [VI] >> [From Software Engineering for
Template] >> [Design Patterns] >> [Producer Consumer Design Pattern –Data] option. This article adds useful features to the LabVIEW on LabVIEW
Queued State Machine
template that ships with LabVIEW and presents a QSM-PC template that was arrived-at after the study and use of a number of other Architecture
similar templates. The template proposed here is therefore considered by the author as one of best of breed templates for QSM-PC Write better LabVIEW
architecture programs « birgitplays on
LabVIEW Queued State
Machine Architecture
Background
GKostikov on LabVIEW
Historically, the Queued State Machine programming method evolved from the LabVIEW developer community through articles in the Queued State Machine
Architecture
now discontinued publication: “LabVIEW Technical Resource Guide”. The subject was introduced by Jeff Parker (Winter, 1995) and
elaborated and modified by Greg Fowler (Spring, 1996) and Lance Butler (Winter, 1996). The National Instruments website hosts various LabBEAN1 on LabVIEW
Queued State Machine
knowledge-base articles and tutorials matching the key word: “Queued State Machine”. National Instruments’ Kevin Hogan produced a Architecture
useful presentation and web cast on this same subject matter that continues to be available as of this writing. NI LabVIEW courses from
TAGS
LabVIEW Basics II to the Advanced course all cover material on queued state machine architecture. Over the years, the queued state
machine has gained advocacy and widespread use in large LabVIEW-based applications in the developer community. In light of this active vi
anniversary
block
situation, an NI forum thread: ‘Please Don’t Do It‘, emerged in June 2006 that engages a lively discussion that questions QSM-PC diagram
Blog
bug
business
architecture suitability in certain LabVIEW coding scenarios. christmas
class
Concurrency
data type
Queued State Machine Producer Consumer Design Objects design pattern
DSL
endevo
Erlang
expressionflow
Generally, a queued state machine is a LabVIEW programming method that sends commands and other data from multiple source points game
inheritance
(i.e. producer points), such as from user events and from one or more parallel processes, and gets these handled in one state machine introduction
process (i.e. destination consumer point) in the order in which they were added to the queue. Figure 1 is the simplest high-level LabVIEW
labview
illustration of the QSM –PC design. Figure 2 adds detail to this illustration, and Figure 3 is the equivalent LabVIEW implementation. champion
merge
message
These illustrations will be used through-out this article to clarify the features and functions of the QSM-PC architecture. passing
Microsoft
MIT
ni
object
one-time store
OOP
OpenG
operating
system
parallel
recursion
Server
Source Code Control
svn
template
toolkit
tortoisesvn
upgrade
user interface
video
Virtualization
Visual
Programming
Windows
Yahoo!

ARCHIVES

March 2010

January 2010
December 2009

November 2009

October 2009

September 2009

February 2009

December 2008

November 2008

September 2008

July 2008

June 2008

May 2008

March 2008

February 2008

January 2008

December 2007
Figure 1. Shows four high-level objects of queued state machine producer consumer architecture. 1= Queue reference; 2 = User events
November 2007
object (producer of commands and data); 3 = Commands processor (consumer process that handles commands and data); 4 = Parallel
SubVI processes (producer of commands and data). October 2007

August 2007
 
July 2007

June 2007

May 2007

April 2007

March 2007

CATEGORIES

Bugs

Concurrency

database

Design Patterns

Domain Specific Language

Erlang

External Code

Games
Figure 2. Queued state machine producer consumer architecture showing data flow and objects inside the consumer process.
General
 
LabVIEW

National Instruments

Object-oriented programming
Introduction to OOP in
LabVIEW

OpenG

Programming Languages

Server

Source Code Control

studio

Toolkits

User Interface

Virtualization

Visual Programming

Windows

BLOG LINKS

Eyes on VIs

Inside LabVIEW

LabVIEW Artisan

LabVIEW Robotics
Figure 3. LabVIEW implementation of the queued state machine producer consumer architecture. Labeled objects 1 through 4 match
Large LabVIEW Application
those of the high level illustrations in Figure 1 and Figure 2. Development Blog

Thinking in G
A High Level Layout of QSM-PC Architecture
VI Road Show
A general layout of QSM-PC architecture comprises of the four objects annotated by the encircled numerals 1 to 4 shown in Figure 1.
VI Shots
These objects are namely: (1) Queue reference object; (2) User events object (optional for head-less embedded applications that require
no user interaction); (3) Main state machine object; (4) One or more parallel processes subVI objects. Note that label 1.1 in Figure 1, is a COMMUNITY LINKS
broken-line representation of the queue reference object. The broken-line is meant to show that the subVI processes are able to access
and interact with the queue from within the SubVI by referencing the queue by name without having to wire the queue reference to the LAVA
SubVIs. See the LabVIEW implementation of this illustration in Figure 3 and the QSM -PC LabVIEW Example included in this article. NI Discussion Forums
Queue reference access by name also allows a queue reference to be use by dynamically launched VIs by VI Server and is discussed
OpenG
further under the section: Item (1) Queue Reference Object.

Items (2) and (4) are the multiple producer processes responsible for sourcing commands and data and adding them to the queue. Item
(3) is the single consumer process which removes commands and data from the queue name: ‘Main Queue’ and acts on these in the
order added to the queue. One important rule is that, for any one queue reference, you should only have one consumer process while
there can be one or more producer processes. This rule ensures that the consumer process is the central command processing center
where each and every command added to the queue reference gets handled. In the LabVIEW QSM-PC layout of Figure 3 the consumer
process is part of the open top level block diagram, rather than a subVI. This is to facilitate manipulation of controls, indicators and
properties of front panel objects in the main program. The discussion that follows elaborates further on items 1 through 4 and shows their
ADVERTISE
LabVIEW implementation examples. HERE!

Item (1) The Queue Reference

The queue reference in the QSM-PC architecture emulates a command and data messaging pipe-line where the queue accepts data
packets added by one or more producer objects and releases these data packets to one consumer object. Figure 2 elaborates on the
queue reference message communication function by showing data packet migration through the queue originating from producer objects
and ending at the main consumer object. The consumer object loop in item 3, Figure 2, includes queue management VIs. These VIs are
from LabVIEW’s queue palette VI shown in Figure 4 which are used to accomplish various functions such as creating the queue, adding
data to the queue, and releasing data from it.

Figure 4. LabVIEW’s queue palette VIs used in the queued state machine producer consumer programming method.

Creating The Queue Reference or Grabing Existing Queue Reference:

The LabVIEW queue implementation shown in Figure 3 creates a queue reference of the name: ‘Main Queue’ using the Obtain Queue VI
from LabVIEW’s queue palette; see LabVIEW implementation code in Figure 5. Subsequent and repeated implementation of this same
code will grab an existing queue reference of the specified name. This is typically done to give access of queue reference to subVIs
which also avoids the need to wire a queue reference to the subVI.

Figure 5. LabVIEW code for creating a new queue reference for the queued state machine or grabbing an existing one.

Two inputs are essential for creating the queue: (a) The Queue Name: In this example the queue name is ‘Queue Main’; and (b) Data
Packet Definition:
Shown annotated in Figure 6 is a sample data packet recommended for the queued state machine discussed in this article. This data
packet constitutes a cluster containing two pieces of information: (i) A type def enumerated constant also known as a Function ‘STATE’
constant; and (ii) a variant ‘DATA’ item. This data packet definition means that the resulting queue reference can only carry data elements
that conform to this data packet.

Figure 6. Recommended data packet for queued state machine producer consumer architecture discussed in this article.

The typedef enumerated constant enlists your chosen names of the state machine cases in the consumer process. Each time a
command is added to the queue, the enum should be set to the machine’s STATE name which will handle or process the command.
Therefore, the type-def STATE items are like command names that designate which state name contains the relevant code for processing
the command. Typical function enum state names: ‘INITIALIZE’, ‘IDLE’, ‘ERROR’, and ‘EXIT’ should be included.

You must ensure that the enum constant is a copy of a typedef-based custom control so that you can add or remove command items
from the enum and have your changes propagated to all instances of the typedef constant throughout your LabVIEW code. See LabVIEW
literature on how to create typedef enum constants. Note that alternative queued state machine templates can also use string data
elements for commands in place of the typedef enum. However, string-based state machine cases require exact syntax spelling of state
names and are also case sensitive. Typed def enums help reduce programming errors because, once defined, you can only choose an
item from the available list of valid items.

The second item in the cluster is the variant data element which can carry any data. This data element allows you to package data along
with the command for use in processing. Sending data along with the command using the variant data element is optional. Note that
alternative queued state machine templates do not include the variant data element which means that only commands can be sent via
the queue. You would need to use functional globals or other means to send data to the processing loop. The variant data element
recommended in this QSM-PC architecture gives you a convenient and useful option to package your commands with any data.

Adding a Command and Data to the Queue Reference

You use the ‘Enqueue Element’ VI from LabVIEW queue palette to add data elements to the queue. The example in Figure 7 (a) is an
instance where a producer process adds a data element to the queue with the enum message set as STATE 1 but with an empty variant
data. Once the queue reference is wired to the enqueue VI, you should right click the input ‘element’ terminal and choose the ‘create
constant’ menu item to get a copy of the data packet conforming to the queue reference. This precludes the need to cut and past a copy
of the queue data element sample each time you need to use the LabVIEW enqueue VI. Figure 7(b) is where a producer process adds a
queue data element with enum set as STATE 4 and packaged with a data cluster bundled as variant data. The bundled data is intended
for processing by the consumer object under STATE 4. Any data type can be bundled as a variant data making this a flexible way of
sending any data in the queue pipeline. The state machine that will handle the data will have to decode the variant data inside the case
named STATE 4. This is elaborated under the section: Item(2) Consumer Object Stats Machine.

Figure 7 (a): Single data packet added to enqueue VI. STATE set as STATE 1 and with empty variant data. Note that once the queue
reference is wired, you can right-click the ‘element’ input terminal for the queue data packet, and choose the ‘create constant’ menu item
to get a sample data packet that conforms to the queue reference wired.

Figure 7(b): Single data packet added to VI. The STATE is set as STATE 4 and variant data packages a data cluster using the bundle by
name utility.

 
Figure 7(c): Multiple data packets added by building them into an array and using a ‘For Loop’ to add the data to the enqueue VI.Note
that you should remember to use the en-queue element at opposite end of queue VI, (available from LabVIEW’s queue palette) to add a
data element to the queue which needs priority handling. For example the exit and error state cases are typically added to the front of the
queue so that they can be handled immediately by the consumer object process.

Removing Data Element from Queue for Handling by Consumer Object

You use the ‘De-queue Element’ VI from LabVIEW’s queue palette to remove data elements from the queue for processing by the
consumer object. The de-queue process is annotated as item 1.2 in Figure 2. After de-queuing, the data packet is unbundled to reveal
the STATE name which is wired to the selector terminal of the State Machine. A case in the state machine which matches the packet’s
STATE name will handle the data packet that was input to selector terminal. The example in Figure 8(a) is a section of the consumer
dequeue process taken form Figure 2. A commented section of equivalent LabVIEW implementation code, taken from Figure 3, is given
in Figure 8(b).

After a dequeued data packet is unbundled to reveal the STATE name, the STATE name is compared with the STATE name ‘EXIT’.
Should the comparison be TRUE, the EXIT State will run and thereafter the consumer process loop will terminate executing. This
assumes that the STATE name: EXIT, is included in the enum list, and that this STATE name is intended to quit the LabVIEW program.

Figure 8(a) Consumer process deqeueue VI illustration; Figure 8(b) Dequeue VI LabVIEW implementation.

De-Queue VI Unwired Time-Out Input Terminal Defaults to (-1)

Notice that the de-queue VI’s ‘Time Out’ input terminal is unwired and will therefore default to -1. This means that the consumer dequeue
process will wait indefinitely or until an element is ready to be de-queued. A way to make the consumer process loop continuously is
described under this article’s section: ‘Consumer Object State Machine’.

The Queue Manager VI in the Consumer Loop

A Queue Manager VI is located right after execution of each individual case in the consumer’s state machine. See item 1.3 in Figure 2
and item 1.3 in Figure 3. Note that this VI is strategically placed so that errors and commands can be captured right after the completion
of execution of the individual state machine cases. The Queue Manager VI has three main purposes.
Figure 9. Queue manager VI executes right after a state finishes running in the consumer process. This VI handles errors, allows run-
time logic implementation, and monitors the need to exit.

(1) Handle Errors From State Cases

Note that the queue VIs are considered ‘mission critical’ VIs and are therefore not wired to the error line. This allows these VIs to continue
to work even when errors are captured by the queue manager VI. If such an error is captured, the ERROR state name is added to the
front of the queue, see Figure 9. This forces priority processing of the shift-registered error before other states can run. You must clear
the error in the error handler case.

(2) Implement Case-by-Case Run-time Logic

The Queue manager VI can accept an array of STATE commands from any case in the state machine. The array-type input allows a state
case to input no state (empty array), just one state (single element array), or multiple states. This avails the capability for consumer state
machine case to implement ‘as-needed’ run-time logic. Run-time logic is where a consumer state case behaves as a producer by adding
commands, as needed, to the queue for processing by the same consumer loop. For example, a consumer state case after processing
data from the queue can determine that an alarm condition needs to be raised. The state can then add the ALARM state name in the
front of the queue or it can pre-empt all elements in the queue, and in their place, just add the ALARM state name. The default is to add
data packets to the back of the queue.

(3) Monitor Global Exit

Monitoring the global EXIT condition only works if the consumer process is in constant polling mode. This can be achieved by forcing the
consumer VI to visit the idle case at specified wait intervals. By doing this the queue manager VI can poll for the boolean EXIT global to
determine if the consumer loop should terminate. If polling is not done, then the EXIT enum state must be input to the queue to instruct
the consumer loop to exit. Note that you could also make the de-queue VI come out of the wait state by closing the queue reference from
another process in the code see Figure 10. All VIs waiting on the queue will come-out of the wait state and produce error number 1122.
You can check for this error and terminate the consumer loop accordingly. However, this method of exiting from the queue VIs’ wait state
is not used in the QSM implementation of Figure 3.

 
Figure 10. You can STOP the consumer loop by destroying the queue reference which causes VIs waiting on the queue to come-out of
the wait state and generate a error #1122. An error state of TRUE from wait VI is used as a condition for exit.

Item (2) Consumer Object State Machine

Note that the consumer process is considered to be the owner of the queue named: ‘Main Queue’ because it is from only this consumer
process where queue elements are dequeued (removed) from the ‘Main Queue’ reference. Producer processes access or borrow the
queue reference from multiple points only to add elements to the queue. Once a data packet is removed from the queue, the consumer
process will execute the state case of the unbundled state name from the data packet. The code inside this designated case will then run
to process the command and accompanying data, if any. The consumer object state machine is labeled as item 3 in the Figures 1,
Figure 2, and Figure 3.

Other than the case names: INITIALIZE, IDLE, ERROR, and EXIT; you can add and name other state cases that will perform useful
functions based on your application’s needs. For example, you can designate four cases: (a) READ; (b) READ_STEP_1; (c)
READ_STEP_2; and (d) READ_STEP_3 and spread-out your READ code to run under these four sequential case steps. A producer
process will only need to add the enum case: READ, for the code to run all 4 read steps. This is especially useful if you want more space
to write your code rather than packaging all your code in one subVI. Furthermore, each step can execute run-time logic to exit the
consumer loop should this be required. Figure 11 shows the READ case with the other three cases added for immediate sequential
execution in the front of the queue.

Figure 11. Consumer process case executing the READ command in three additional READ steps that will execute immediately
thereafter by the addition of sequential READ steps to the front of the queue.

Consumer Process IDLE State Machine Case

Be sure to include the IDLE case in the consumer’s state machine if you want your consumer process to continue running while in
standby mode without necessarily visiting other state machine cases. You can loop through the idle case to poll for time-elapsed and to
adjust for wait times using the wait until next multiple timer VI. To accomplish continuous looping, include the IDLE enum case state when
initializing the consumer loop and keep adding the IDLE enum case state while inside the IDLE case. See Figure 12 and Figure 13.

Figure 12. Example of how to perform continuous loops via the IDLE case state.

 
 

Figure 13. Consumer process example showing how to code the IDLE case for continuous and constant loop cycle time. Note special
use of the ‘Wait till next ms multiple VI’ inside a sequence frame.

Decoding Data Packets Originating From Producer Processes

Producer processes send commands via the enum selector. Data of any type can be sent along with the commands by converting the
data to a variant data type and then bundling the variant data along with the enum command. However, for the consumer process to use
this data, the data packet must be appropriately decoded from the variant data type. Variant data decoding must be done in the
designated enum consumer case. Figure 14 shows variant data decoding in state machine case: STATE 4, of a data packet input to the
queue as was shown in Figure 7(b) and Figure 7(c).

Figure 14. Decoding variant data inside STATE 4 for data that was enqueued from the example in Figure 7(a) and Figure 7(b).

More on Run-Time Logic Implementation in Consumer Case

Each time a consumer state machine case finishes executing, there is opportunity for intervention of program flow by the addition of
enum state commands at the back or front of queue or even to replace the queue elements with new enum command instructions. This
feature, known as run-time logic programming, is an important advantage of the QSM architecture. Figure 15 shows use of a SubVI to
execute STATE 5. to detect emergency alarm conditions. Should an alarm be detected, the program will immediately pre-empt (replace)
all enum commands in the queue and execute the emergency shut down enum case instead.
Figure 15. Run time logic programming with option to pre-empt program flow via the queue manager VI of the consumer process queued
state machine.

Avail and Update Parameters and Variables in Any State Machine Case

Another feature worthy of note in the QSM architecture is the shift registered cluster data flow line that passes through all state machine
cases; see Figure 16 (not shown in Figure 3). This flow line avails and allows update of parameters and variables, as needed, inside
every state machine case. You use LabVIEW’s unbundled-by-name utility to access parameters and variables and use the bundle-by-
name utility to update the same. Figure 16 shows these operations within enum case: STATE 6 of the consumer loop.

Figure 16. Shift registered cluster of parameters and variables that can be accessed and updated within every case of the queued state
machine in the consumer process.

Item (4) Parallel Process SubVIs

SubVIs that run in parallel with the main consumer process complement and add useful functions to the QSM-PC architecture; see item 4
in Figure 1, Figure 2, and Figure 3. SubVIs that can be run in this manner are data communications VIs, data acquisition (DAQ) VIs,
results analysis VIs, and much more. These parellel subVIs primarily behave as producer processes and access the queue reference by
name, using the method described in Figure 5. This is the same queue reference that is shared with the consumer process. This method
of access to the queue reference precludes the need to wire the queue reference to SubVIs, as seen in the LabVIEW implementation of
Figure 3, which creates transparent routes of communication and simplifies the block diagram.

Building Both Multi-Consumer Functionality in LabVIEW Code

By creating multiple queue references of unique names you can have multiple consumer points in your LabVIEW code. Each consumer
point (i.e. at the dequeue VI) will own the respective queue reference of a unique name and will behave as the only destination point for
all packets sent via that queue reference. In this way you can implement a network of transparent data migration paths from multiple
producer points to predefined destination points in your code. The one important rule here is that to send data to a given consumer point,
you must use the queue reference owned by the respective consumer process. The LabVIEW code example included with this article
shows this type of implementation.

The example in Figure 17 shows a block diagram for SubVI 1 which behaves as a consumer process for the queue name: ‘Q1’ but which
also grabs queue references: ‘Main Queue’; Q2; and Q3. In this case, SubVI 1 can use queue reference Q1 to accept commands and
data from other producer points while and at the same time SubVI 1 can send commands and data to consumer processes that own the
other queue references.

Figure 17. Block diagram for a subVI that behaves as the consumer process for queue reference Q1, but is also the producer process for
queue references: (1) Main Queue; (2) Q2; and (3) Q3.

Summary

Design attributes, object features, and function of the QSM –PC architecture are covered in the forgoing discussion. The goal is to help
master the fundamentals in the applied use of this method to develop parallel process LabVIEW programs. Of special emphasis is the
strategic use of queue references as a network of communication pathways for commands and data transfer between multiple parallel
processes. The material discussed in this article is applicable to many other variations of the QSM -PC architecture. This article will
conclude with pertinent highlights covered in the discussion.

1. QSM-PC is a Parallel Process Enabler

The QSM –PC architecture establishes the use of queue references as data messaging pipelines that communicates information
between parallel processes in an as-needed and timely manner. This type of communication solves one of the serious challenges in
parallel process programming for data acquisition, alarm monitoring, and results analysis.

2. Multiple Producer and Single Consumer Points

In the QSM –PC architecture, queue data elements can be added from various points in the code known as producer points. However,
queue elements are taken out of the queue from only one destination point, called the consumer point. This consumer point is considered
to be the owner of the queue reference.

3. Global Access to the Queue via the Queue Name

Global access to a queue reference means that the queue can bee seen by SubVI processes without the need of wiring the SubVIs to a
queue reference. This creates transparent routes of communication and greatly simplifies the code.

4. Empowers Programs to Build Run Time Logic.

QSM –PC programs can implement logic to change the latest command sequence by adding commands to the front of the queue or by
emptying the queue to reset the program flow and add new commands thereafter.

5. Multi Consumer Queue References Creates a Network of Data Pathways

Parallel process SubVIs which themselves use the QSM-PC architecture create a network of communication pathways with multiple
producer and consumer points. This allows one parallel process to control multiple parallel process subVIs.

6. QSM -PC Queue VIs are Mission Critical VIs that Should not be Wired to Program Errors
LabVIEW queue VIs do not run if errors occur in the error input terminal. For this reason, these VIs should not be wired to the program
error data flow line to preclude them from failing to perform the mission critical function of moving commands and messages between
processes. Note that some of these commands could be alarms and emergency shut down instructions and the like that must be
processed even when other program errors occur.

Example included with This Article

A LabVIEW program is included with this article on QSM PC architecture implementation. The file QSM -PC Example.LLB contains a
main program and two subVIs that run in parallel. This example implements most of the QSM –PC command and data communication
features discussed in this article.

 
           

 Print This Post

( 26 ) Comments

26 Comments Make A Comment

Andy Hull Said:

October 1st, 2007 at 3:04 pm

Food for thought, with the introduction of classes how about replacing the variant data with a LV Class?

Bill VanArsdale Said:

October 1st, 2007 at 5:43 pm

Why do you use a shift register for the queue reference in your state machine loop (Fig. 3) but not in any other while loop inside
your library?

Anthony Lukindo Said:

October 1st, 2007 at 6:24 pm

Andy:

I have yet to use LV Classes myself and your suggestion is a good way to start using them. I will flesh this out with Tomi for a way to
proceed.

Thanks

Anthony L.

Anthony Lukindo Said:

October 1st, 2007 at 6:27 pm

Bill:

You are correct if you are assuming that the shift register is not required for the queue reference in while loops! The inconsistency
you see in the code is in error.

Anthony

Derek Price Said:

October 2nd, 2007 at 1:20 pm


Hi Anthony,

I really enjoyed the article and was looking for a more in depth explanation of the operation of the QSM – nice work! FYI – A couple
of your images printed a little blurry with black backgrounds for some reason (Figures 4, 5, 6, 7a, & 7b), but all the rest were fine.

Thanks,
Derek

Yen Said:

October 13th, 2007 at 9:22 pm

There are some more comments at


http://forums.ni.com/ni/board/message?board.id=170&message.id=276634#M276634

P.S. Great article.

styrum Said:

November 21st, 2007 at 6:10 pm

Nice article!

However, I found that if we keep separate notions for state, action, and event, think (and treat) the code in the cases of the
consumer loop as actions rather than states, maintain separate queues for events and actions, not only it allows creating a more
flexible and powerful architecture, but, most importantly, developing code on a higher level of abstraction (when in this state and this
event happens I need to do this, this and this action and switch to that state). Please see the following for further discussion and a
more advanced architecture:

http://forums.lavag.org/Simple-Event-Driven-Queued-State-Machine-with-Front-Panel-Events-and-a-Timer-t4687.html

Despite the pattern discussed there doesn’t support hierarchical states (for those implemented see labhsm.com) I found it much
more powerful and flexible (yet producing uniformly looking and easily modifiable/maintainable code) than the standard producer
consumer single queue QSM pattern.

chyatt Said:

April 23rd, 2008 at 8:00 pm

Very nice article. However, I can’t open the VI’s in the LLB because I have LV version 7.1, not 8.2 or greater. Is there a way I can
open the example, just to view the contents without running them, without purchasing the upgrade to version 8.5?

Anthony L. Said:

April 24th, 2008 at 7:05 am

Will upload LV 7.1 version to FTP server and will point you to address for downloading. Will write back soon.

Anthony

Great Resource for Learning a Common Architecture for LabVIEW Applications « Software Engineering for LabVIEW Said:

March 18th, 2009 at 7:33 pm

[...] Lukindo wrote an excellent article on expressionflow.com that explains how to utilize a queued state machine architecture with
[...]

Architecting an Application to Avoid Spaghetti « Software Engineering for LabVIEW Said:

April 3rd, 2009 at 4:11 pm

[...] also recommend visiting expressionflow.com. Anthony Lukindo wrote an excellent, indepth article on the QSM-PC (Queued
State Machine – Producer / Consumer) design pattern, which is a fairly common and very [...]

Peter Said:

October 27th, 2009 at 1:32 am

Hi folks,

I have successfully used this specific QSM architecture for a relatively large application and was mostly happy with how things
turned out.

Today I read the following comment from an NI employee about using User Events instead of QSMs. What do others think ? Does
the proposed alternative below have any downsides compared with QSMs ?

http://pasquarette.wordpress.com/2009/09/

“The powerful thing about User-Defined events is that a developer gets to dictate what information gets sent to that event via the
event’s internal terminals. A very simple example of this is: you can create an event called “save”, which has a path attribute. When
the event gets called, the path attribute can be accessed using that events terminals, and the application can save its state at the
path given. It is the caller of the event who would have gotten to specify what path to provide. Old and alternative ways of doing this
was to use a LabVIEW Queue, who’s elements would either be a cluster of the data you wanted to pass around, or a variant so that
anything could be passed. Both of these techniques have issues. One places a burden on the type of data that can be passed in the
cluster, the other places the burden on the receiver of the data to extract it from the variant. The event structure removes both of
these burdens by allowing each event type to have different data passed to them, and by giving direct access to that data within the
event case via the internal terminals.”

regards

Peter Badcock
Product Development
ResMed Ltd

harbenger Said:

December 23rd, 2009 at 4:07 am

This is a very interesting concept, and I’m definitely new to the game. My question is in regards to managing the state queue. Take,
for example, figure 13. An “idle” event was dequeued in order to get to the “idle” state. In the idle state, another “idle” queue is
added. If another state transition is added to the queue by the producer loop, we now have two entries in the queue. If, in the new
state, we enqueue another idle command, the queue will have two “idle” states. The current design doesn’t account for two
simultaneous idle entries.

All I’m trying to say is that I am concerned about poor queue management when the consumer loop creates next state logic. It is
very possible to create queue entries which will never be serviced.

Any thoughts?

Anthony Lukindo Said:

December 24th, 2009 at 4:16 am

Harbenger:

Just wanted to comment on the idle state case. Note that the idle event is added at the end of the array build node. This means that
any events added to the array build node, prior to the idle event, will run first.

Also, the idle event should only be added in the idle case to indicate an eventual return to that case for polling or looping purposes.
Alternatively you can omit adding the idle event to keep the program ‘silent’ so that it only wakes-up and acts when some new event
is added to queue.

Finally, take note that as you add events to the queue in other cases you have the option of adding them to the ‘front of the queue’
so that they get executed immediately. This means that the event will be jumping the queue and will be immediately de-queued for
execution.

I hope this further clarifies things

harbenger Said:

December 27th, 2009 at 4:59 am

I agree with everything you say. However, my concern was centered around the management of the queue. In order to completely
flush the queue, you either need to have states with no next-state enqueues (which will have a net loss in the queue size) or
manually flush the queue. The idle state has a zero net loss of the queue size.

Consider my example again. You have two idle-like loops which place default next-state commands into the queue. Likewise, you
have two events which allow you to switch between loops. Each state by itself will not change the size of your queue. However, your
queue will continue to fill up with unserviced next-state requests as you switch between states. This is true because the event loop
is the primary producer of queue elements and the consumer loop has a net zero loss.

You can confirm this by adding queue status VI’s either in-loop or as a separate loop.

I was able to fix this by adding more functionality to your Q Manager.vi. I’m not completely sold on it being complete, but the idea is
as follows: Define a ‘default’ next state transition as a boolean input. Only add the default next-state element to the queue if your
queue is empty. Otherwise, don’t add it. This will fix the always increasing queue size problem.

LabBEAN Said:

January 6th, 2010 at 8:42 pm

As I mentioned here:
http://decibel.ni.com/content/message/11700#11700

Regarding the implementation of enqueueing on opposite end (front of the queue): When you enqueue multiple items on the
opposite end to another loop which is waiting to dequeue elements [where execution order is critical (e.g. State 1, State 2, State 3,
State 4)], the waiting loop will dequeue and run State 4 first. Here’s why: Before enqueueing the 4 states on the opposite end, you
must first reverse their order. When another loop is waiting to dequeue, it grabs the first item you enqueue (e.g. State 4). It’s not a
concern that it grab subsequent items, regardless of execution speed, since all loops share the same non-reentrant Queue
Manager, and the only instance of the Queue Manager is busy enqueueing the next three states (in this example). Therefore, you
could end up with an execution order of State 4, State 1, State 2, State 3. So, I would suggest enqueueing a dummy state before
enqueueing on opposite end your states in reverse order.

Else, odd behaviour can occur (e.g. Stop state occurs before Power Supply Off state *ouch*).

Anthony Lukindo Said:

January 11th, 2010 at 5:26 am

Hi LabBEAN:

The need to reverse the order of multiple events added to the front of the queue is correct. This is implemented in Figure 9 of the
article. Notice the ‘Reverse 1D array node.’ Thus events are always reversed by the queue manager subVI when added to the front
of the queue.

LabBEAN Said:

January 12th, 2010 at 11:20 pm

Hi Anthony,

Let’s say one of the producers (see the red “4.1″ in Figure 2 above) enqueues states on the opposite end to the consumer (see the
red “3″ in Figure 2 above). When the first state is enqueued, then the consumer will immediately dequeue it because the consumer
is waiting to dequeue an element. If you enqueue the elements in reverse order (which I agree *of course* that reversing the order
first is necessary since they are each being enqueued on opposite end), then the elements will run in the order “last”, “first”,
“second”, “third”, “…”, “next to last”. You need to enqueue a dummy element on opposite end first.

Note: This is not the case when enqueueing within the same consumer (because of data flow) or for any future elements after the
first element enqueued on opposite end when enqueueing from producer to consumer (as long as the Q MGR [see red "1.5" in
Figure 2] is non-reentrant).

Please reread my previous post.

Take care,
Jason

YuvalYohai Said:

June 21st, 2010 at 11:31 am

Hi Anthony,
Beautiful article.
I’ve been using my own LV state machine architecture for a long time. Your architecture is the last leap I needed in order to make
them more robust.
Thanks very much.

good luck,
Yuval Yohai

durnek60 Said:

November 19th, 2010 at 6:10 am

Very nice job! Thanks for sharing!

Aum-LabVIEW Said:

April 4th, 2011 at 6:25 pm

Although ‘Queue State Machine’ is the most popular architecture following industry standards, no other article on QSM using
LabVIEW till date is even closely as exhaustive, to the point and explanative.
Takes care of the LabVIEW execution system threads as well.
Great blog & great article.

Tekie Said:

December 7th, 2011 at 12:03 am

@LabBEAN:
I see the behaviour you explain, when you dont use an IDLE-state which add itself again. With the idle state it didnt happen,
because the Consumer will be at least always working on the IDLE-state and adding it again in the same While-iteration.

But I am not sure, whether it can happen, that the Idle-state-Consumer-iteration just ends and you add D right before the next
iteration of the consumer starts. You want to add DCBA with the producer at the beginning of the queue, to get an ABCD-queue.
Now the consumer works on the Idle state, but RIGHT after the idlestate iteration ends and BEFORE the new iteration starts, you
add the D state. The chances for that to happen, should be ultra low, but perhaps it can happen.

To have no problem with that, you could add only A with the producer and let A add DCB within the queue manager. Or like you
said, by using a dummy-state. Or you could use 2 queues: One connecting the Producer with the queue-manager. And one
connecting the queue-manager with the consumer. This could even solve problems like this: “i added Stop state S at the beginning,
while state A was working. Now A is finished and adds B at the beginning, which results in a BQ-queue.”

LabBEAN1 Said:

December 14th, 2011 at 12:11 am

@Tekie:
I do not use the IDLE case in my own architecture, which is why this bit me a few years ago. As you said, theoretically even with the
IDLE state there is still the risk that states run in the wrong order without adding one of the workarounds you mentioned. If you set
up the architecture to allow all loops to enqueue to each other, you sort of need only one queue per loop (rather than the 2 queue
model you mentioned). That said, you can setup the Queue Manager to dynamically skip (etc.) the enqueue function if it detects a
Stop (etc.) case in the queue. Notes: Good idea to avoid enqueueing on opposite end unless highly necessary AND do not enqueue
states on opposite end that could take a while to run.

I like the idea of having the Event Structure outside the main while loop and of having multiple producer and producer/consumer
loops (some of which live in task specific subVIs) the way the article describes. One of the main advantages of putting the Event
Structure outside the main loop above is that it keeps the main loop from free-wheeling just to handle the event structure, which
makes debug much easier. Including an IDLE state defeats this advantage. The only reason for IDLE is to facilitate stopping all the
loops via global Boolean. Instead, I just enqueue SHUTDOWN to all the loops. If you don’t know how many loops you have before
run time (i.e. you are spawning other loops dynamically), this is still easy to do by tracking the queues you’ve created.

BTW, thanks for taking time to understand what I wrote.

@Peter
Consider using User Event architectures in combination with Queued architectures. User Event architectures cause all loops to
respond to all messages, which introduces unnecessary complexity (and free-wheeling) in most cases. The important thing is to
understand the tools and pull out the right one when necessary. So, enqueue directly to the destination you want and, when
necessary, broadcast to all processes via the User Event framework. (Yes, you could just enqueue the same state to everybody as
well.)

@String-State-Machine-Folks
I know you favor the use of type definitions elsewhere, so why not take advantage of them and make the switch to enum-based-
state-machines (like I did several years ago).

-If you update the name of a state, all case structures and constants update too!
-Stop trying to remember what you called something…. or, worse, stop maintaining lists of state names so you can remember what
you called something while declaring that maintaining an enum is too much work. When you have multiple loops and 100+ states, I
don’t see how anyone tolerates strings.
-Can the LabVIEW run-time engine switch states (cases) as quickly on a string as it can on a U32? (doubtful)
-Delete that “whoops you mispelled the state name” default state from all your loops.
-Passing data with the state you are enqueueing guarantees another state doesn’t overwrite data you put on the main shift register
(yes, some string folks add a “state data” variant or string as well, but most don’t).
-Use a string where it’s really valuable: target to target communication (e.g. PC to cRIO). I don’t advocate using the same type
defined enum for multiple targets since each gets it’s own base code. But, enjoy the enum when you’re within the same target.
Then, convert the enum to string when sending over TCP/IP, Shared Variable, etc. and back to enum on the other side.

*LabBEAN1 = LabBEAN … forgot password for LabBEAN and cannot receive emails where I created that account.

GKostikov Said:

June 4th, 2012 at 1:24 pm

Dear Anthony.
I have trying to replicate this architecture for my application and I have thousand of questions. Why do I have Error 1 (some invalid
simbols) when program get to Event Structure “Exit” cace.
And very same thing happend some times with your program.
Thanks.

Write better LabVIEW programs « birgitplays Said:

September 30th, 2012 at 11:35 am


[...] Queued state machines. (My favorite pattern, btw – and what we’re going to use for this project. A bit complicated for their level,
but we’ll deal with it.) [...]

Great Resource for Learning a Common Architecture for LabVIEW Applications | Software Engineering for LabVIEW Said:

October 15th, 2012 at 10:18 pm

[...] Lukindo wrote an excellent article on expressionflow.com that explains how to utilize a queued state machine architecture with
[...]

Comments RSS Feed  


TrackBack URL

Leave a comment
You must be logged in to post a comment.

© 2007-2010 Tomi Maila. All Rights Reserved.

You might also like