如何解决函数调用之间的竞争条件

how to tackle a race condition between function calls

我使用 erlang 的消息传递构造构建了一个多人游戏(准确地说是 4 个玩家)。我以下面 link 中的 tictactoe 游戏为例,但真正相似的是游戏中显示的消息传递结构:link

然后我选择 运行 在 ejabberd 多用户聊天室上玩这个游戏,我为此编写了一个 ejabberd 挂钩。 但是如果你在上面link上查看文件tictactoe.erl中的NewGameState,你会发现没有办法找回它 在一个变量中。

所以我使用 mnesia 并将生成的每个新游戏状态写入此 mnesia table。 现在在我的 ejabberd 钩子中我调用我的游戏函数(即每次调用一系列模块 -> "gen_server, game_modules,mnesia_modules" 被执行) 在游戏函数调用下方的钩子内,我正在从 mnesia table 中读取游戏状态,如下所示(这里函数 myMessage 是 ejabberd 钩子内的函数):

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

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

现在我的问题是,当执行顺序为

时,读取操作给我一个空的 table
some_other_module:game_func(Args),
 GameState=mnesia_module:read(key),

当我在这两行之间插入延迟时 timer:sleep/1 如下(值 200 是在使用不同值进行一些试验后随机选择的):

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

我得到了 GameState 的正确值,因此提示我行中的读取操作

GameState=mnesia_module:read(key),

some_other_module:game_func(Args) 行(这是一系列模块 -> "gen_server, game_modules,mnesia_modules")能够执行 mnesia 模块并将 GameState 写入 mnesia table.

我不想使用 timer:sleep/1,我该如何解决这个问题,因为它不是可靠的解决方案。

任何人都可以建议我解决 here.What 我的意思是任何人都可以建议我通过 mnesia 以外的任何其他方式检索挂钩内的 GameState 的方法所以我根本没有竞争条件.

或者 ejabberd 提供了一些我可以在这里使用的功能?

提前致谢。

分布式节点之间数据的实时一致性是一个难题,您需要根据自己的需要定制解决方案。你没有说你正在使用 mnesia 的哪种交易,所以也许这会解决你的问题。

但是,这里有一个简单的解决方案可以帮助您思考问题:

首先,让我们调用您的一个节点 master。在主节点上,启动一个 gen_server 来处理游戏状态。现在,任何想要读取或写入游戏状态的人都需要将主节点的 rpc:call/4(除非他们已经存在)转换为 gen_server:call/2。现在所有与游戏状态的交互都是同步的。

如果您每秒更新游戏状态的次数不超过几次,那么此解决方案应该非常适合您。如果游戏是独立的,那么每个游戏都是不同的gen_server。

我正在尝试提供适合我的解决方案。希望对大家有帮助。

这是我所做的:

首先我把图片去掉了失忆症

我首先在 start/2 函数中创建基本模块的 Pid(你可以想到问题中提供的 link 上出现的 tictactoe.erl ) 然后我在该模块内创建了一个 get_gs/0 函数,仅用于检索 GameState 如下(server 是我用来注册 Pid 的别名):

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

然后在 loop() 函数中我有:

{ get_gs, From } ->
           From ! GameState,

           loop(FirstPlayer, SecondPlayer, CurrentPlayer, GameState)

然后创建了一个实现gen_server架构的模块,并按以下顺序调用函数(其中->表示函数调用,如A->B表示From A i call B):

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

我得到了当前的 GameState。

感谢@Nathaniel Waisbrot 的宝贵建议。