[IGSTK-Developers] State machine questions

David Gobbi dgobbi at atamai.com
Wed Aug 24 16:27:52 EDT 2005


Kevin Gary wrote:

> David,
>
> Thanks for your response. I did have a lapse and not
> realize we were already in the ProcessInputs loop that
> walks the queue. That information and the Wiki page
> cleaned up a lot of stuff. IMHO though, with
> ProcessInputBoolean being public on the SM, assuming
> that it is only called from within the ProcessInputs
> loop via the function pointer is both dicey and overly
> complex. It would seems the object shouldn't have
> to know the state of the queue and where it is being
> called from. And couldn't an input validation problem
> like the SOR use PushInputBoolean with a condition
> on a validation function? (though I guess it would then
> have to know to call ProcessInputs itself I suppose...).

The "Boolean" method was added fairly late in the game.
That's why many of the classes don't use it.  But yes, it
can be used for input validation, as long as ProcessInputs()
is called immediately after, it should work just fine.

> Yeah, the "Attempt" stuff we need to noodle on, it
> may make error-handling easier...
>
> Kevin
>
>
>
> David Gobbi wrote:
>
>> Kevin Gary wrote:
>>
>>> Hi all,
>>>
>>> I was looking at some of the state machine code to get
>>> refreshed on the topic, and as often happens when I look
>>> at code, I got confused ;).
>>
>>
>>
>> Confusion is to be applauded.  It is a sure sign that lots
>> of critical thought is being applied ;)
>>
>>> In looking at SerialCommunication and base Tracker
>>> classes, the sequence of calls for the Open methods
>>> will first push an input to the SM and then process it.
>>> In StateMachine::ProcessInputs, the function pointer is
>>> traversed (toward the bottom of the method), and the
>>> ensuing private method on the original object called.
>>> The result of traversing the transition should leave
>>> us in an "AttemptingToDoSomething" state. The private
>>> method invoked (SerialCommunication::AttemptToOpenPort
>>> or Tracker:: AttemptToOpen) then does a PushInputBoolean
>>> based on the result of a virtual "InternalXXX" method call.
>>>
>>> Some questions:
>>>
>>> 1. I do not see a call to StateMachine::ProcessInput(s)
>>> anywhere after the PushInputBoolean (which queues an input
>>> to the SM based on the outcome of the Internal method).
>>> When is the queued input processed? Subsequent call to
>>> the SM on the next request?
>>
>>
>>
>> At the time when PushInputBoolean() is called, we are already
>> inside ProcessInputs().
>>
>> The process is as follows: someone pushes a "DoSomethingInput",
>> and then calls ProccessInputs().  Then ProcessInputs() calls
>> the AttemptToDoSomething() method, which calls
>> PushInputBoolean() to push the next input (a success or failure input).
>> When the AttemptToDoSomething() method returns, ProcessInputs()
>> will set the state to the AttemptToDoSomething() state, and will then
>> proceed to process the "success" or "failure" inputs that have been
>> added to the input queue.
>>
>> If that sounds convoluted to you, you will probably be glad to hear
>> that it sounds convoluted to me, too.  I am hoping that the state
>> machine processing can be simplified, and I hint at this at the
>> end of the "Exceptions and State Machines" section of the
>> "State Machines" wiki page.
>>
>>> 2. At the end of StateMachine::ProcessInput, the last 2
>>> things done are 1) an execution of the transition, i.e.
>>> the function pointer, and 2) setting the state of the
>>> SM itself to the endpoint of the transition. If the
>>> invocation of the function pointer itself leads to a
>>> transition, then the call sequence will in fact "nest"
>>> the invocation, meaning you will not end up in the
>>> correct state. For example, in my hand-trace, it would
>>> seem the SerialCommunication object would end up in the
>>> "AttemptingToOpen" state and not one of the "m_IdleState"
>>> (on failure) or "m_PortOpenState" on success. Of course,
>>> question #1 may make this moot as I do not see when we
>>> would ever traverse the 2nd transition (it seems to me
>>> the only reason it works is because the Internal method
>>> does the actual work *before* the PushInputBoolean call,
>>> e.g. not under the guide of the StateMachine).
>>
>>
>>
>> The current state machine design will break if ProcessInput()
>> is ever called from within itself, for exactly the reason you
>> cite.
>> The reason things are working right now is hopefully
>> addressed in my answer to your first question.
>>
>>> 3. I am not sure of the utility of multiple queued inputs
>>> to our StateMachines. As each input is mapped onto a single
>>> transition in a given state, and the processing of a single
>>> input should lead to a new target state, it seems that
>>> a sequence of inputs queued on the basis of being in some
>>> state will find the SM will not be in that source state
>>> when the input is actually processed! For example, assume
>>> I have a SM with 3 states, S1-S4, and 3 inputs I1-I3. S1
>>> accepts inputs I1 and I2. I1 leads to a transition to S2,
>>> I2 leads to a transition to S3. If I queue I1 and I2 and
>>> then call ProcessInputs, I will have queued I2 believing
>>> my object was in S1, when in fact it will be in S2 when
>>> I2 is processed???
>>
>>
>>
>> I think that the only reason for the queued inputs was to
>> get around the problem you described in question 1
>> (that is, so that we wouldn't set a new input before
>> we had reached the state where we could process
>> that input).
>>
>>> 4. I am not sure of the utility of having the StateMachine
>>> traverse two transitions and go through two states in this
>>> call pattern. As we are assumed single-threaded (right?)
>>> and these are private calls where the result of the original
>>> client method invocation will never seemingly result in
>>> being in the "AttemptingXXX" state...why introduce the
>>> complexity? I'm not sure I see the benefit?
>>
>>
>>
>> You are correct, the state machine will both enter and leave
>> the "attempting" state within a single invocation of an
>> interface function.
>>
>>> I also looked at the ImageSpatialObjectRepresentation, and
>>> it does not do the "Attempting" type pattern, and so these
>>> questions disappear (though it does validate input up
>>> front to determine the input to push, instead of doing the
>>> PushInputBoolean thing).
>>
>>
>>
>> There is a difference between validating an input, and
>> validating a result.  With the former, you do the check
>> before you do any processing, with the latter, you need
>> to do some processing first before you know what
>> the next step is.
>>
>> The way things work now, is that a state machine input
>> will cause an Attempt() function to be called, which
>> will then do some processing and then set the next
>> input.
>>
>> You are asking why we can't just call the Attempt()
>> method directly, an hence eliminate both the
>> Attempt input and the Attempt state.
>>
>> I'll have to think about this, but you might be right,
>> maybe we can eliminate them.  Also, if we eliminate
>> the Attempt states then we no longer need to set
>> Success inputs.  We can just call the input that will
>> cascade us up into whatever state we're supposed
>> to get to if we are successful.
>>
>> But then, if we need to do processing in order to
>> get into that next state, and an error occurs during
>> that processing... I'll need to think a bit more.
>>
>> Obviously the "AttemptState" approach works.
>> The big question, though, is whether there is a
>> better way to do things.
>>
>>> Sorry for the long narrative, it is involved code to trace
>>> through by hand. I'm sure I am missing something...
>>
>>
>>
>> The narrative is very much appreciated. You make
>> some excellent points.  I hope that I managed to
>> answer at least some of your questions.
>>
>> - David
>>
>>> Hope everyone has been well...
>>
>>
>>
>>>
>>> K2
>>>
>>>
>>>
>>> _______________________________________________
>>> IGSTK-Developers mailing list
>>> IGSTK-Developers at public.kitware.com
>>> http://public.kitware.com/cgi-bin/mailman/listinfo/igstk-developers
>>>
>>
>
>




More information about the IGSTK-Developers mailing list