Внедряване на State Machine

Търся някакъв генерал

  1. Оптимизация
  2. Коректност
  3. Разширяемост

съвет относно моето текущо внедряване на C++ Hierarchical State Machine.

проба

variable isMicOn = false
variable areSpeakersOn = false
variable stream = false
state recording
{
        //override block for state recording
        isMicOn = true //here, only isMicOn is true              
        //end override block for state recording
}
state playback
{
        //override block for state playback
        areSpeakersOn = true //here, only areSpeakersOn = true
        //end override block for state playback
        state alsoStreamToRemoteIp
        {
                //override block for state alsoStreamToRemoteIp
                stream = true //here, both areSpeakersOn = true and stream = true
                //end override block for state alsoStreamToRemoteIp
        }
}

goToState(recording)
goToState(playback)
goToState(playback.alsoStreamToRemoteIp)

Внедряване

Понастоящем HSM се изпълнява като дървовидна структура, където всяко състояние може да има променлив брой състояния като деца.

Всяко състояние съдържа променлив брой блокове за "замяна" (в std::map), които заменят базовите стойности. В основното състояние машината на състоянието има набор от променливи (функции, свойства...), инициализирани на някои стойности по подразбиране. Всеки път, когато влизаме в дъщерно състояние, списък с "замени" дефинира променлива и стойности, които трябва да заменят променливите и стойностите със същото име в родителското състояние. Актуализиран оригинал за яснота.

Рефериране на променливи

По време на изпълнение текущите състояния се съхраняват в стек.

Всеки път, когато се препраща към променлива, се извършва низходящ стек в търсене на най-високата отмяна или в случай на липса на отмяна, стойността по подразбиране.

Превключване на състояния

Всеки път, когато се превключи към рамка на едно състояние, състоянието се избутва в стека.

Всеки път, когато се превключи към състояние, аз проследявам низходящо дърво, което ме отвежда от текущото състояние до основното състояние. След това правя дървовидно слизане от целевото състояние до основното състояние, докато видя, че текущата следа съвпада с предишната. Декларирам пресечна точка, където се срещат тези 2 следи. След това, за да превключа към целевото състояние, се спускам от източника, изваждайки рамки на състоянието от стека, докато стигна до пресечната точка. След това се изкачвам до целевия възел и избутвам рамки на състоянието върху стека.

Така че за примерния код по-горе

Проследяване на изпълнение за превключване на състояние

  • Състояние на източника = запис
  • Целево състояние = alsoStreamToRemoteIp

  • спускане от източник = запис->корен (следа = [корен])

  • слизане от target = alsoStreamToRemoteIp->playback->root (trace = [playback, root])

  • Пресича се в корена.

За да превключите от запис към също StreamToRemoteIp,

  1. Извадете "запис" от стека (и извикайте неговата функция за изход... не е дефинирана тук).
  2. Натиснете "възпроизвеждане" върху стека (и извикайте функцията за въвеждане).
  3. Натиснете "alsoStreamToRemoteIp" в стека (и извикайте функцията enter).

person jameszhao00    schedule 11.09.2009    source източник
comment
свързани: stackoverflow.com/questions/1647631/c-state-machine- дизайн   -  person jldupont    schedule 14.11.2009


Отговори (2)


Две неща:

1: В повечето случаи просто представяйте състоянието на вашата програма като модел и взаимодействайте с нея директно или чрез MVC шаблона.

2: Ако наистина се нуждаете от FSM, т.е. искате произволно да направите куп действия към вашия модел, само някои от които са разрешени в определени моменти. Тогава....

Все още запазвайте състоянието на вашата програма в модел (или множество модели в зависимост от разлагането и сложността) и представяйте състояния и преходи като.

class State:
   def __init__(self):
      self.neighbors = {}

Където съседи съдържа речник на {Action: State}, така че можете да направите нещо подобно

someAction.execute() # Actions manipulate the model (use classes or lambdas)
currentState = currentState.neighbors[someAction]

Или още по-готино, имайте безкраен цикъл, произволно избиращ действие от съседите, изпълнявайки го и премествайки състоянието за неопределено време. Това е чудесен начин да тествате вашата програма.

person DevDevDev    schedule 11.09.2009
comment
Как биха подходили съседите към справяне с вложени състояния? т.е. за преминаване от състояние A:B:C към A:E:F:G:H как ще разбере каква разходка по дървото да предприеме? - person jameszhao00; 12.09.2009
comment
Можете просто да стартирате BFS. Ако имате нужда от всички пътища, ще трябва леко да промените BFS. - person DevDevDev; 12.09.2009
comment
Потърсете BFS, ако не го знаете, но основно ще ви даде път от A -› D, приложете действията за всяко състояние в пътя и ще стигнете до D. - person DevDevDev; 12.09.2009
comment
Да, наясно съм как да го приложа. Само че BFS има по-лоша характеристика на производителност в сравнение с моето пресичане на низходящо дърво, описано по-горе. - person jameszhao00; 12.09.2009

Не съм сигурен, че следвам всички подробности тук. Изглежда обаче, че описвате изпълнение на FSM (крайна машина), където имате множество държавни машини. Понякога, когато определено събитие (E1) се случи в определено състояние (S1) на FSM F1, трябва да въведете нов FSM (наречете го F2), за да опростите обработката като цяло).

Ако случаят е такъв, тогава когато E1 се появи в S1, трябва да извикате рутина за действие, която поема четенето на събитието и прилага F2 FSM. Когато бъде извикан, той започва обработка в началното състояние на F2 и обработва съответните подсъбития. Когато достигне крайното си състояние, интерпретаторът за F2 завършва. Може да върне някаква информация към рутината за действие на F1, която е била спряна, докато F2 е работил, и следващото състояние във F1 може да бъде засегнато от това.

Останалата част от описанието ви - неща като "заменящи блокове" - няма да има много смисъл за хората без достъп до вашата реализация.

person Jonathan Leffler    schedule 11.09.2009
comment
В основното състояние машината на състоянието има набор от променливи (функции, свойства...), инициализирани на някои стойности по подразбиране. Всеки път, когато влизаме в дъщерно състояние, списък със замени определя променлива и стойности, които трябва да заменят променливите и стойностите със същото име в родителското състояние. Актуализиран оригинал за яснота. - person jameszhao00; 11.09.2009