5

我建立了一个多玩家游戏使用二郎神的消息传递结构(准确的说,4名选手)。以下链接中的tictactoe游戏为例,但真正类似于游戏中显示的消息传递构造:如何解决竞争条件之间的函数调用

然后我选择在ejabberd多用户聊天室上运行此游戏,这是一个ejabberd钩子。 但是,如果你在上面的链接上的文件tictactoe.erl看NewGameState,你会发现,没有检索的方式,在一个变量 出来。

所以我用的Mnesia并写了产生这种Mnesia表上的每一个新的游戏状态。 现在在我的ejabberd钩我把我的游戏功能(即每次通话的一系列模块 - >“gen_server,game_modules,mnesia_modules”执行) 和挂钩只是游戏功能的调用下面里面我从Mnesia表上的读数为如下的游戏状态(这里的功能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), 

当我插入这两行之间的延迟为timer:sleep/1为b

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

我正在游戏状态的正确值从而表明我,在线的读操作

GameState=mnesia_module:read(key), 

是越来越执行:elow(该值200被一些尝试使用不同的值后随机选择的) /在行some_other_module:game_func(Args)(它是一系列模块 - >“gen_server,game_modules,mnesia_modules”)之前执行的/能够执行mnesia模块并将GameState写入mnesia表。

我怎样才能解决这个问题,因为我不希望使用timer:sleep/1,因为它是不可靠的解决方案。

任何人都可以给我一个工作在这里。我的意思是任何人都可以建议我通过除mnesia以外的任何其他方式检索挂钩内的GameState,所以我根本没有竞争条件。

或其中有一些方式,ejabberd提供了一些功能,我可以使用吗?

在此先感谢。

+0

你使用mnesia:dirty_ *函数吗? – Pouriya

+0

no @Pririya我正在使用mnesia:写入/ 1来写入数据,而some_other_module:game_func(Args)正在运行,而mnesia:read/3函数读取数据时GameState = mnesia_module:read(key)被调用。 –

+0

你可以显示代码吗? – Pouriya

回答

1

我想给我的解决方案。希望它能帮助别人。

这是我做的:

首先我从图片中删除了mnesia。

我首先在start/2函数(你可以想到问题提供的链接中存在tictactoe.erl)内创建基本模块的Pid,然后我在该模块中创建了get_gs/0函数仅检索游戏状态如下(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是指从我称之为B):

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

而且我得到的当前游戏状态。

谢谢@Nathaniel Waisbrot您的宝贵意见。

+0

看起来不错!当你觉得复杂性更高一些时,我强烈建议使用OTP构造(supervisor,gen_server,gen_statem)。需要一段时间才能掌握它们,但它们是非常强大的工具,您将使用_constantly_。 (相反,Mnesia学习起来也很复杂,但仅在特定情况下才有用。) –

+0

是的,我肯定会研究OTP结构。感谢您的帮助。 –

6

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

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

首先,让我们打电话给你的节点master之一。在主节点上,启动一个处理游戏状态的gen_server。现在,任何想读取或写入游戏状态的人都需要向主节点(除非他们已经在那里)制作rpc:call/4gen_server:call/2。现在所有与游戏状态的交互都是同步的。

如果您每秒更新游戏状态不超过几次,该解决方案对您而言应该会很好。如果游戏是独立的,那么每个游戏都是不同的gen_server。