LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Queued State Machine skipping states?

Hi,

 

I started out writing my application using a simple state machine but I realized it was necessary to make the application more interactive and prevent the UI from freezing when interupted. For example, I want the user to be able to abort the test by clicking the stop button or a reset button that sends the state machine sequential flow to the reset state.

I implemented the my QSM by looking at the example in the link below.

https://decibel.ni.com/content/docs/DOC-14169

 

However, the problem now is that the state machine no longer runs sequentially as in my initial simple state machine. Sometimes a state is repeated and at other times a state is skipped. By skipped, I meant it didn't follow the order I tried to implement in my code. I flush the queue before any new user input so I don't know what's causing this behavior in my application.  Has anyone experienced this type of problem before? If so how can it be fixed.

 

Thanks

0 Kudos
Message 1 of 9
(3,079 Views)

sounds like a dataflow problem or race condition. Can you attach a simplified version of your VI that shows the problem?

0 Kudos
Message 2 of 9
(3,077 Views)

Flushing may be the problem.

 

Typically when requesting a switch to a higher priority state there is no need to flush the queue.  Just use Enqueue Element at Opposite End. That makes the new element the first one dequeued.

 

As althenbach suggested, please post some code.

 

Lynn

0 Kudos
Message 3 of 9
(3,070 Views)

Hi

I'm still trying to find a solution to this problem. I was able apply a temporay remedy in an earlier application but in my current application, I'd have to find a permant fix to it.  This problem is described in comment number 4 of the community example code link below. I tried to apply the recommended solution but it didn't work. Perhaps, I was doing it the wrong way. How will the example code be modified to fix the problem described in the comment? I will appreciate any suggestions.  Thanks

 

 

https://decibel.ni.com/content/docs/DOC-14169 

 

Comment4

 

This pattern has a potential risk of get cycled or get into unwanted states. Let me explain it. When you click on button, an event occurs and typically an element is enqueued to the queue. But in the lower loop another element is enqueued (in this case Report or Process). So when you for example want to go to idle state by clicking on the Stop button, you go to idle state but then you go to report or process state because the element was enqueued behind the idle element as explained above. The solution is to check if the queue is empty before enqueuing the element in the lower loop:

 

If the queue is empty, it is safe to enqueue element in lower loop:

enque0.png

 

If it is not empty (this occurs when an element is enqueued in the upper loop due to event occurence), the element will not be enqueued:

enque1.png

0 Kudos
Message 4 of 9
(2,912 Views)

Link broken. target does not exist. Did you make it public?

0 Kudos
Message 5 of 9
(2,901 Views)

The proposed solution absolutely doesn't fix the problem, because checking if the queue is empty and enqueueing a state are separate actions. It is quite possible for the state of the queue to change after checking if it's empty.

 

I think this is a poor architectural design. I would restrict the queue to handling communication between the user interface and the lower loop. I would maintain the current/next state in a shift register, so that there is no access to it outside that loop. On each loop iteration, you check the queue to see if there's an action from the user interface and if so take the correct action (aborting the test, etc); otherwise, proceed with the state from the shift register.

0 Kudos
Message 6 of 9
(2,900 Views)

@altenbach wrote:

Link broken. target does not exist. Did you make it public?


There's just a couple extra characters accidentally added to the end of the URL. Try the link from the first post.

0 Kudos
Message 7 of 9
(2,899 Views)

Ah, first link from a few years ago works. Seems the last link has a nonbreaking space at the end of the URL.

0 Kudos
Message 8 of 9
(2,898 Views)

nathand wrote:

I think this is a poor architectural design. I would restrict the queue to handling communication between the user interface and the lower loop. I would maintain the current/next state in a shift register, so that there is no access to it outside that loop. On each loop iteration, you check the queue to see if there's an action from the user interface and if so take the correct action (aborting the test, etc); otherwise, proceed with the state from the shift register.


I also think this is a poor architecture.  There is no really good reason to have two loops.  You can do it all in a single state machine using the queue to keep track of which states to call.  You just have an "Idle" state that you need to check every so often.  In that Idle state is where your checking for GUI events goes.  This avoids all kinds of interesting race conditions and can make things simpler.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
0 Kudos
Message 9 of 9
(2,840 Views)