Jump to content

Returning to state where you left off


Recommended Posts

I have an application where I am using the state pattern. I'm having an issue with ownership of a state which I may want to return to at a later point.

 

For example, I have a state (call it state1) that needs to do some arbitrary number of things. However, if certain events happen, that state will be interrupted. I go to another state which could go to another and then another etc, but at some point it may need to return to state1, where state1 left off. I can't just create a new instance of state1, I need to reuse the previous isntance.

 

So, my question is, where do I manage the life time of this state1 instance when it's not being used? I could set it in the private data of the next state (with a cast, obviously, because I cannot have a child class in a parent class's private data). But, if the next state doesn't use it, because it determines it needs to go to some other state, then I have to pass the state1 object into this next state...and so on and so on until I need to return to State1 at some point. Now, it seems I could be passing the management of this object from state to state, just in case some other state uses it. Feels ugly.

 

I have to assume there is a better way?

Link to comment

Is State a class, containing all the relevant context?

 

My first thought is a queue containing the State class, so that you can put any child state in it. That should make it easy to stack up states to which you might need to return, or to flush that list of states if you discover that you do not need to return to them. I don't know if this works in your architecture, though.

Link to comment

Basically, I have a base state class, and one of the child states is RunningTest, which sequences through a bunch of steps. I have an array of steps inside the RunningTest class private data. If I'm on step x of 100 and some limits go out of range, we go to another state which adjusts the analog outputs until things are operating normally again, and if this is successful, I need to return to the RunningTest State at step x and continue running.

Edited by for(imstuck)
Link to comment

Generally speaking, anything that affects all of your state transitions -- and this sort of "store a tidbit for later" action is a potential modifier rule for all of your state transitions -- has to go in the parent class of all your states. You might consider an array of states called "state stack", which you treat as a Push/Pop interface for states, and add a "Try Revert.vi" that you call on yourself periodically. 

 

If you have only one method that could trigger the reset, then the other option is to put state into one of your method VIs. This works only if you have a single instance of your Actor running ever because you'll have to make the method non-reentrant and give it state (i.e. an uninitialized shift register or uninitialized feedback node). Personally I don't like this option -- limits future flexibility of the class too much.

Link to comment

Consider making the State classes flyweight classes and maintaining state information (big s and little s, actually) in the Context.  (That is what we do; it works quite well, and I think it is the best way to implement the State Pattern.  My impression is this would be difficult to do with the Actor Framework, though.)

  • Like 1
Link to comment
Consider making the State classes flyweight classes and maintaining state information (big s and little s, actually) in the Context.  (That is what we do; it works quite well, and I think it is the best way to implement the State Pattern.  My impression is this would be difficult to do with the Actor Framework, though.)

I'll look into this. I'm not using AF so I should be able to adjust accordingly.

Link to comment
Consider making the State classes flyweight classes and maintaining state information (big s and little s, actually) in the Context.  (That is what we do; it works quite well, and I think it is the best way to implement the State Pattern.  My impression is this would be difficult to do with the Actor Framework, though.)

 

This is my default implementation for state machines. Works wonderfully.

Link to comment
This is my default implementation for state machines. Works wonderfully.

I pretty much understand the flyweight pattern, but as it relates to the state pattern I am a bit lost. Is the idea here that a list of states is stored in the context and if the state exists already, the existing state is returned, otherwise a new one is created? 

Link to comment

Perhaps. Many ways to skin the state machine.

 

My preferred implementation is a loop with two shift registers: one for the Context and one for the State. Each iteration of the loop calls the State:Act method, which has a dynamic dispatch in but static dispatch out, as well as a pair of Context in/out terminals. The goal of State:Act is to operate on the Context by whatever means makes sense for the State, and to return what State will be used on the next iteration. The fact that the output is static dispatch means the method is free to switch out any State on the output-- while an Act implementation may return the same State out as was passed in, it can also return any other state depending on whatever conditions apply.

 

For your situation, you'll likely be dealing with a stack of states. Store the stack where you like, the idea being at some time an Act implementation will decide that it's reached a terminal iteration and has no next state, where it may wish to operate on the stack, returning the State pushed from the top as the next State.

Link to comment

Exactly! (Well, we use the Factory Method Pattern to create State objects.)
I presented the essentials of our implementation at NI Week 2012. I should put this presentation on a server somewhere. ...
I think you are on a fruitful track. ...

 

Edit: Was replying to post #10.

Link to comment
Exactly! (Well, we use the Factory Method Pattern to create State objects.)

I presented the essentials of our implementation at NI Week 2012. I should put this presentation on a server somewhere. ...

I think you are on a fruitful track. ...

 

Edit: Was replying to post #10.

To follow up, here are some additional posts on this topic, most likely related to what Paul talked about in his NI Week presentation.

Link to comment
I've still been digging in parallel with implementing. Check it out, Paul...it already does exist on a server somewhere!

Again, thanks!

 

I have a couple notes to update the presentation:

1) On slide 23, I have a note about the representation of internal and recursive transitions.  I sent a feature request to Sparx Systems, and recent release notes indicate there may be a fix for that in a recent version of Enterprise Architect, but I have not confirmed that.

2) On slide 85 there is a bullet suggesting a slight change to facilitate the implementation of orthogonal regions (slide 94).  Shortly after the presentation I tried that and it worked great!

I should find a place to post the Powerpoint version, since then folks can read the slide notes, which I think are helpful in this case.

Link to comment

The Enum for the states is a strict typedef inside a project library (.lvlib) within the component.  Interacting components that need to know the state have access to the typedef so that they can interpret published State information (a U16 published via a network shared variable).  Since we only have one system, usage is by (obvious) convention.



All the typedefs in that particular .lvlib are for elements related to elements published for external availability.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.