Реализация конечного автомата - PullRequest
0 голосов
/ 11 сентября 2009

Я ищу какой-то общий

  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 следа. Затем, чтобы переключиться в целевое состояние, я спускаюсь из источника, выталкивая кадры состояния из стека, пока не достигну точки пересечения. Затем я поднимаюсь на целевой узел и помещаю кадры состояния в стек.

Так что для примера кода выше

Трассировка выполнения для переключателя состояния

  • Состояние источника = запись
  • Целевое состояние = также StreamToRemoteIp

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

  • снижение от цели = такжеStreamToRemoteIp-> воспроизведение-> корень (трассировка = [воспроизведение, корень])

  • Пересекается в корне.

Чтобы переключиться с записи на StreamToRemoteIp,

  1. Вывести «запись» из стека (и вызвать ее функцию выхода ... здесь не определено).
  2. Вставьте «воспроизведение» в стек (и вызовите функцию ввода).
  3. Вставьте также «StreamToRemoteIp »в стек (и вызовите функцию ввода).

Ответы [ 2 ]

1 голос
/ 12 сентября 2009

Две вещи:

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]

Или даже круче, иметь бесконечный цикл, случайным образом выбирающий действие у соседей, выполняющий его и перемещающий состояние на неопределенное время. Это отличный способ проверить вашу программу.

1 голос
/ 11 сентября 2009

Я не уверен, что следую всем деталям здесь. Однако, похоже, что вы описываете реализацию FSM (конечного автомата), где у вас есть несколько конечных автоматов. Иногда, когда конкретное событие (E1) происходит в определенном состоянии (S1) FSM F1, необходимо ввести новый FSM (назовите его F2), чтобы упростить обработку в целом).

Если это так, то когда E1 возникает в S1, вам нужно вызвать процедуру действия, которая берет на себя чтение события и реализует F2 FSM. При вызове он начинает обработку в начальном состоянии F2 и обрабатывает соответствующие подэтапы. Когда он достигает своего конечного состояния, интерпретатор для F2 заканчивается. Он может вернуть некоторую информацию подпрограмме действия F1, которая была приостановлена ​​во время выполнения F2, и это может повлиять на следующее состояние в F1.

Оставшаяся часть вашего описания - например, «переопределить блоки» - не будет иметь большого смысла для людей без доступа к вашей реализации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...