0

私はいくつかの一般的なものを探しています

  1. 最適化
  2. 正しさ
  3. 拡張性

現在のC++階層ステートマシンの実装に関するアドバイス。

サンプル

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

  • ソースからの降順=記録->ルート(トレース= [ルート])

  • ターゲットからの降順=alsoStreamToRemoteIp->playingback-> root(trace = [playback、root])

  • ルートで交差します。

記録からalsoStreamToRemoteIpに切り替えるには、

  1. スタックから「記録」をポップします(そしてその終了関数を呼び出します...ここでは定義されていません)。
  2. 「再生」をスタックにプッシュします(そしてenter関数を呼び出します)。
  3. 「alsoStreamToRemoteIp」をスタックにプッシュします(そしてenter関数を呼び出します)。
4

2 に答える 2

1

ここですべての詳細に従っているかどうかはわかりません。ただし、複数のステート マシンを持つ FSM (有限ステート マシン) の実装について説明しているようです。場合によっては、特定のイベント (E1) が FSM F1 の特定の状態 (S1) で発生すると、処理全体を簡素化するために新しい FSM (F2 と呼びます) を入力する必要があります)。

その場合、S1 で E1 が発生したときに、イベントの読み取りを引き継いで F2 FSM を実装するアクション ルーチンを呼び出す必要があります。呼び出されると、F2 の開始状態で処理を開始し、関連するサブイベントを処理します。終了状態に達すると、F2 のインタープリターが終了します。F2 の実行中に中断された F1 アクション ルーチンに何らかの情報が返される可能性があり、F1 の次の状態が影響を受ける可能性があります。

あなたの説明の残りの部分 (「オーバーライド ブロック」など) は、実装にアクセスできない人にはあまり意味がありません。

于 2009-09-11T05:32:18.687 に答える