如何解决函数调用之间的竞争条件
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 的宝贵建议。
我使用 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.
现在我的问题是,当执行顺序为
时,读取操作给我一个空的 tablesome_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 的宝贵建议。