F. Schubert wrote:
I also strongly recommend not to use any enqueue in the consumer.
Well I hope so--I believe it was you who suggested it to me in the first place. 🙂
battler. wrote:
If you don't recommend QSM structure, what structure do you recommend and why?
It depends entirely on project requirements and programmer's experience. For maximum flexibility and scalability my default starting point for applications is an MVC architecture that decouples the UI from the underlying functional code. Not everyone needs that level of flexibility or is comfortable with the additional complexity. If you're looking for a single vi to function as the application framework, as the OP appears to be doing here, there are several variations that implement essentially the same principle.
Producer/Consumer Design Pattern (Events)
This is one of the standard templates supplied with Labview. Structurally the QSM and Producer/Consumer patterns are very similar, the only difference being QSM consumer loops modify the queue directly. Some might view the difference as a minor semantic point. I believe the semantics are very important as it directly affects how you *think* about the two loops, which in turn influences how you decompose the problem and code your solution.
State machines, by their nature, contain the code necessary to determine what the next state should be. They are self-deterministic. When that state is controlled by a queue, it is natural to alter the contents of the queue. In a Producer/Consumer pattern one loop is clearly the producer. It, and only it, is allowed to put messages on the queue. It is not necessarily restricted to only enqueuing messages. It can and sometimes should execute its own logic to determine which messages to send. The other loop is clearly the consumer. It, and only it, is allowed to dequeue messages from the queue. If you think of your application as using the Producer/Consumer pattern you are more likely to design solutions that avoid the many pitfalls associated with the QSM.
(I'll note the diagrams posted by Dan are, in fact, Producer/Consumer. However, his terminology and the restriction he placed on the producer loop strongly suggested a QSM was in the making.)
Standard State Machine (Events)
The Standard State Machine is another template supplied with Labview. To make it work with events, add an "Idle" case and in that case put an event structure to handle front panel events. By removing the parallelism you've eliminated the need to worry about synchronization between the message sender and message receiver. This pattern does have the unfortunate side effect of making your UI unresponsive when the program is not in the Idle state.
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.
The fundamental principle all these implementations are enforcing is controlling when changes to the sequence of states can be made. Each of them complete all the steps necessary for a given message before checking to see if there are any more messages. The QSM convolutes the state sequence functionality with the message receiving functionality. This is why it ends up causing so many problems.
Final note - There is nothing inherently bad about the concept of a Queued State Machine. The problem is entirely in the implementation that has become commonly known as a QSM.