5

私は、erlangのMessage passing構造を使ってマルチプレイヤーゲーム(正確には4人のプレイヤー)を作りました。私は例として次のリンクのtictactoeゲームに従ってきましたが、本当に似ているのは、ゲームに表示されている通りのメッセージパッシング構造です:関数呼び出し間の競合状態に対処する方法

私はこのゲームをejabberdで実行することを選択しました。これのためのejabberdフック。 上記のリンクのtictactoe.erlファイルのNewGameStateを見ると、変数に を取り出す方法がないことがわかります。

だから、私はmnesiaを使い、この記憶媒体テーブルに生成された新しいgamestateを書きました。 私のejabberdフックの中で、私は自分のゲーム関数を呼び出します(つまり、各呼び出しで、 "gen_server、game_modules、mnesia_modules"が実行されます) そしてゲーム機能の呼び出しの直ぐ下のフックの中で私はmnesiaテーブル次のようにgamestateのために(ここでは、関数myMessageはejabberdフックの内部関数です):

myMessage({#message = Msg, C2SState})-> 
    some_other_module:game_func(Args), 
    State=mnesia_module:read(key), 

    {Msg, C2SState}; 
myMessage(Acc) -> 
    Acc. 

今私の問題は、実行の順序は

some_other_module:game_func(Args), 
GameState=mnesia_module:read(key), 
ときに読み出し動作が私に空のテーブルを与えているということです

と、この2つの行の間に遅延を挿入すると、timer:sleep/1がb

some_other_module:game_func(Args), 
timer:sleep(200) 
GameState=mnesia_module:read(key), 

私はラインでの読み取り動作が

GameState=mnesia_module:read(key), 

が行われつつあることを私に示唆のでGameStateの正しい値を取得しています:ELOW(値200は、異なる値を持ついくつかの試行後にランダムに選択されます) /一連のモジュール - > "gen_server、game_modules、mnesia_modules")の行の前に実行されると、mnesiaモジュールを実行し、GameStateをmnesiaテーブルに書き込むことができます。

timer:sleep/1は信頼できる解決法ではないため、この問題を解決するにはどうすればよいですか。

誰でも私の周りの仕事を提案することはできますか?誰かが私に競技状態を持たないように、何か他の手段でゲームステートを取り戻す方法を提案できますか?

また、ejabberdがここで使用できる機能をいくつか提供していますか?

ありがとうございます。

+0

mnesia:dirty_ * functionsを使用していますか? – Pouriya

+0

いいえ@Pouriya私はmnesiaを使用しています:some_other_module:game_func(Args)が実行され、mnesia:GameState = mnesia_module:read(key)が呼び出されたときにデータを読み込むread/3関数。 –

+0

コードを表示できますか? – Pouriya

答えて

1

私は私のために働く解決策を提供しようとしています。誰かを助けることを願っています。

ここに私がしたことがあります:

最初に私は画像からmnesiaを削除しました。

私が最初のようにすぐにそれがstart/2関数内で作成されるように、ベースモジュールのPIDを登録(あなたが質問に提供されたリンク上に存在tictactoe.erlの考えることができる)、その後、私はそのモジュール内get_gs/0機能を作成しました

get_gs()-> 
    server ! {get_gs, self()}, 
    receive 
     GameState -> 
      GameState 
    end. 

そして、私が持っているloop()機能インサイド:

{ get_gs, From } -> 
      From ! GameState, 

      loop(FirstPlayer, SecondPlayer, CurrentPlayer, GameState) 

のみ(server私はPIDが登録に使用しているエイリアスです)、次のようにGameStateを取得しますそして、gen_serverアーキテクチャを実装するモジュールを作成し、関数を呼び出し、次の順序(->は、A-> B iはBを呼び出すAから意味のような関数呼び出し表す)で:

My custom hook on ejabberd->gen_server based module->gameclient:get_gs/0->gameserver:get_gs/0->tictactoe:get_gs/0 

そして私は、現在のGameStateを得ました。

ありがとうございます@Nathaniel Waisbrotご意見をお寄せください。

+0

いいね!もう少し複雑になったら、OTPコンストラクト(supervisor、gen_server、gen_statem)の使用を強くお勧めします。あなたの周りに頭を浮かべるにはしばらく時間がかかりますが、あなたは驚くほど強力なツールを使います。 (これとは対照的に、Mnesiaは学習するのも複雑ですが、特定の状況でのみ役に立ちます) –

+0

はい私はOTP構造を調べます。助けてくれてありがとう。 –

6

分散ノード間のリアルタイムのデータ整合性は難しい問題であり、ニーズに合わせてソリューションを調整する必要があります。あなたは、どのような種類の取引を通院症に使用しているのかは言わないので、おそらくそれがあなたの問題を解決するでしょう。

しかし、ここで問題について考えるのを助けることが簡単なソリューションです:

まずは、あなたのノードmasterのいずれかを呼び出してみましょう。マスターノードで、ゲーム状態を処理するgen_serverを開始します。ここで、ゲーム状態を読み書きしたい人は、rpc:call/4をマスターノードに追加する必要があります(まだ存在していない場合)。gen_server:call/2にする必要があります。現在、ゲーム状態とのすべての対話は同期しています。

ゲームの状態を1秒に数回しか更新しない場合、この解決法は非常にうまくいくはずです。ゲームが独立している場合、各ゲームは異なるgen_serverです。

関連する問題