浏览erlang应用程序的代码时,遇到了一个有趣的设计问题。让我描述一下这种情况,但是由于PIA的原因,我无法发布任何代码。

该代码被构造为OTP应用程序,其中两个gen_server模块负责分配某种资源。该应用程序可以在一段时间内完美运行,我们并没有遇到太大问题。

棘手的部分开始于第一个gen_server需要检查第二个是否剩余足够资源的地方。向第二个gen_server发出call,第二个gen_server本身称为实用程序库,实用程序库(在非常特殊的情况下)向第一个gen_server发出call

我对erlang还是比较陌生,但是我认为这种情况会使两个gen_server互相等待。

这可能是一个设计问题,但我只是想知道OTP内置的特殊机制是否可以防止这种“挂起”。

任何帮助,将不胜感激。

编辑:
总结一下答案:如果您遇到两个gen_server相互循环的情况,则最好在应用程序设计中花费更多的时间。

谢谢你的帮助 :)

最佳答案

这称为死锁,可以/应该在设计级别上避免。以下是一个可能的解决方法和一些主观要点,它们有望帮助您避免犯错。

尽管有多种方法可以解决您的问题,但“等待”正是call所做的。

一种可能的解决方法是从A内部生成一个调用B的进程,但不阻止A处理来自B的调用。此过程将直接回复调用方。

在服务器A中:

handle_call(do_spaghetti_call, From, State) ->
    spawn(fun() -> gen_server:reply(From, call_server_B(more_spaghetti)) end),
    {noreply, State};
handle_call(spaghetti_callback, _From, State) ->
    {reply, foobar, State}


在服务器B中:

handle_call(more_spaghetti, _From, State) ->
    {reply, gen_server:call(server_a, spaghetti_callback), State}


对我而言,这是非常复杂且难以推理的。我认为您甚至可以在不冒犯任何人的情况下将其称为意大利面条代码。

另一方面,尽管以上可能解决了您的问题,但您应该认真考虑这样的调用实际上意味着什么。例如,如果服务器A多次执行此调用会发生什么情况?如果在任何时候出现超时怎么办?您如何配置超时使其有意义? (最内部的调用必须比外部的调用具有更短的超时时间,等等)。

我将更改设计,即使这很痛苦,因为当您允许这种设计存在并解决它时,您的系统将变得非常难以推理。恕我直言,复杂性是万恶之源,应不惜一切代价避免。

关于erlang - 解决两个gen_tcp之间的死锁,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/6036969/

10-11 18:17