5

Zbudowałem grę dla wielu graczy (dokładnie dla 4 graczy) za pomocą konstrukcji przekazującej wiadomość erlang. Śledziłem grę tictactoe na poniższym linku jako przykład, ale to, co jest podobne, to konstrukcja przekazująca wiadomości, jak pokazano w grze:jak rozwiązać problem wyścigu między wywołaniami funkcji

Potem wybrałem tę grę na ejabberd Multi user Chatroom, napisałam hak ejabberd do tego. Ale jeśli spojrzysz na NewGameState w pliku tictactoe.erl na powyższym łączu, przekonasz się, że nie ma możliwości odzyskania go w zmiennej w postaci .

Więc użyłem mezji i napisałem każdy nowy gamestr wygenerowany do tego stołu mezji. Teraz Wewnątrz mojego haka ejabberd zgłoszę mojej funkcji gry (czyli na każdy wywołać szereg modułów -> „gen_server, game_modules, mnesia_modules” są wykonywane) i wewnątrz haka tuż pod wezwaniem funkcji gry Czytam z tabeli mnesia dla gamestate następująco (tu myMessage funkcją jest funkcja wewnątrz haka ejabberd):

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

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

teraz moim problemem jest to, że operacja odczytu daje mi pusty stolik, kiedy kolejność wykonywania jest

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

i kiedy wstawię opóźnienie między tymi dwoma wierszami jako timer:sleep/1 jako b elow (wartość 200 jest wybierany losowo po pewnym badaniu z różnymi wartościami):

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

jestem coraz poprawną wartość GameState co sugeruje mi, że operacja odczytu zgodne

GameState=mnesia_module:read(key), 

odbywa się coraz/wykonywane przed linią some_other_module:game_func(Args) (która jest serią modułów -> "gen_server, game_modules, mnesia_modules") jest w stanie wykonać moduły mnesia i zapisać GameState w tabeli mnesia.

Jak mogę rozwiązać ten problem, ponieważ nie chcę używać timer:sleep/1, ponieważ nie jest to niezawodne rozwiązanie.

Czy ktoś może zaproponować mi pracę tutaj. Co mam na myśli, to czy ktoś może zaproponować mi sposób na odzyskanie GameState wewnątrz haczyka w inny sposób niż mezji, więc nie mam w ogóle stanu wyścigu.

Albo jest jakiś sposób, że ejabberd zapewnia jakąś funkcjonalność, której mogę użyć tutaj?

Z góry dziękuję.

+0

Czy używasz mnesii: dirty_ * funkcji? – Pouriya

+0

no @Pouriya Używam mnesia: write/1 do zapisu danych, podczas gdy some_other_module: game_func (Args) jest uruchomiona, a mnesia: read/3 do odczytu danych po wywołaniu GameState = mnesia_module: read (key). –

+0

Czy możesz pokazać kod? – Pouriya

Odpowiedz

1

Próbuję dać rozwiązanie, które zadziałało dla mnie. Mam nadzieję, że to komuś pomaga.

Oto co zrobiłem:

pierwsze usunąłem mnesia z obrazka.

raz pierwszy zarejestrował PID Moduł bazowy tak szybko, jak to jest tworzone wewnątrz funkcji start/2 (można myśleć tictactoe.erl obecnych na link podany w pytaniu), a potem stworzył get_gs/0 funkcji wewnątrz tego modułu tylko do pobierania GameState następująco (server jest alias Użyłem zarejestrować PID):

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

a potem Wewnątrz funkcji loop() mam:

{ get_gs, From } -> 
      From ! GameState, 

      loop(FirstPlayer, SecondPlayer, CurrentPlayer, GameState) 

Następnie stworzył moduł wykonawczy architektury gen_server i nazywa funkcję w następującej kolejności (gdzie -> reprezentuje funkcja nazywa jak A-> B oznacza od A ja nazywam b):

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

I mam aktualny GameState.

Dziękuję @ Nataniel Waisbrot za cenne sugestie.

+0

Wygląda dobrze! Kiedy czujesz się gotowy na nieco więcej komplikacji, zdecydowanie polecam używanie OTP konstruktów (supervisor, gen_server, gen_statem). Trzeba trochę czasu, aby się nimi zaopiekować, ale są niesamowicie potężnymi narzędziami, których użyjesz _konstancująco_. (W przeciwieństwie do tego, Mnesia jest również trudna do nauczenia, ale jest przydatna tylko w określonych okolicznościach.) –

+0

Tak, z pewnością zajrzę do konstrukcji OTP. Dziękuję za pomoc. –

6

Realtime spójność danych pomiędzy rozproszonymi węzłami jest trudny problem i będziesz musiał dostosować swoje rozwiązania do swoich potrzeb. Nie mówisz, jakiego rodzaju transakcji używasz w mnesii, więc może to rozwiąże Twoje problemy.

Jednak tutaj jest proste rozwiązanie, które mogą pomóc Ci myśleć o problemie:

pierwsze, nazwijmy jeden z węzłów master. W węźle głównym uruchom serwer gen_, który obsługuje stan gry. Teraz każdy, kto chce czytać lub zapisywać stan gry, musi wykonać rpc:call/4 do węzła głównego (chyba, że ​​już tam jest) do gen_server:call/2. Teraz cała interakcja ze stanem gry jest synchroniczna.

Jeśli zaktualizujesz stan gry nie więcej niż kilka razy na sekundę, to rozwiązanie powinno działać całkiem nieźle. Jeśli gry są niezależne, każda gra jest innym serwerem.