How to solve a race condition between function calls

I built a multiplayer game (more precisely, 4 players) using the erlang messaging construct. As an example, I followed the tictactoe game at the following link, but what really seems to be a message passing construct, as shown in the game:

Then I decided to launch this game on ejabberd Multi User Chatroom, I wrote an ejabberd hook for this. But if you look at NewGameState in the tictactoe.erl file from the link above, you will find that there is no way to get it in a variable.

So, I used mnesia and wrote every new gameplay generated in this mnesia table. Now inside my ejabberd hook I call my game function (that is, a series of modules is executed for each call β†’ "gen_server, game_modules, mnesia_modules") and inside the hook just below the game function call, which I read from the mnesia table for gamestate as follows (here the myMessage function is a function inside the ejabberd hook):

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

Now my problem is that the read operation gives me an empty table when the execution order

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

and when I insert a delay between these two lines as timer:sleep/1 , as shown below (a value of 200 is randomly selected after some testing with different values):

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

I get the correct GameState value, so I suggest that the read operation in the line

 GameState=mnesia_module:read(key), 

executed / executed before the string some_other_module:game_func(Args) (which is a series of modules β†’ "gen_server, game_modules, mnesia_modules") can execute mnesia modules and write GameState to the mnesia table.

How to solve this problem, because I do not want to use timer:sleep/1 , since this is not a reliable solution.

Can anyone suggest me a job here. What do I mean, can anyone suggest me a way to get the GameState inside the hook in any other ways than mnesia, so I don’t have a race condition at all.

Or is there some way that ejabberd provides some functions that I can use here?

Thanks in advance.

+5
source share
2 answers

I am trying to give a solution that worked for me. Hope this helps someone.

Here is what I did:

First I removed mnesia from the picture.

First, I registered the Pid of the base module as soon as it is created inside the start/2 function (you can imagine tactactoe.erl present in the link given in the question), and then I created the get_gs/0 function inside this module only to get the GameState as follows ( server is the alias I used to register Pid):

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

And then inside the loop() function, I have:

 { get_gs, From } -> From ! GameState, loop(FirstPlayer, SecondPlayer, CurrentPlayer, GameState) 

Then a module was created that implements the gen_server architecture and is called a function in the following order (where -> represents function calls, such as A-> B means From A and I call B):

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

And I got the current GameState.

Thanks @ Nathaniel Weissbrot for your valuable suggestion.

+1
source

The constant consistency of data between distributed nodes is a complex problem, and you will need to adapt the solution to your needs. You are not saying which transaction you are using with mnesia, so maybe this will solve your problems.

However, here is a simple solution that can help you think about the problem:

First, let one of your master nodes. On the main node, run gen_server, which processes the game state. Now anyone who wants to read or write a game state must make rpc:call/4 node master (if they are already there) in gen_server:call/2 . Now all interaction with the game state is synchronous.

If you update the state of the game no more than a few times per second, this solution should work very well for you. If the games are independent, then each game is a different gen_server.

+6
source

Source: https://habr.com/ru/post/1270771/


All Articles