【发布时间】:2012-11-11 07:48:36
【问题描述】:
在我的 Erlang/OTP 应用程序中,我有一个 one_for_all 主管 (sup) 和几个孩子。其中一个孩子(child1 具有gen_server 行为)应该能够向另一个孩子(child2 具有supervisor 行为)发送消息。当然,我可以注册它,但是用多余的名称堵塞全局范围似乎不是一个好主意。
因此,使这种交互成为可能的唯一方法是为 child1 提供 child2 的 pid。说到做到。有具有适当功能的supervisor:wich_children/1 呼叫。只需将 sup 的 pid 作为参数传递给 chidl1,在 child1:init 中调用 which_children,然后……就会陷入僵局。 sup 正在等待 child1 开始,child1 正在等待 sup 以获取儿童描述:
init(SupPid) ->
Descriptions = supervisor:which_children(SupPid),
... .
这可以通过以下方法解决:
init(SupPid) ->
gen_server:cast(self(), initialize),
... .
handle_cast(initialize, State) ->
Descriptions = supervisor:which_children(SupPid),
... % Generating new state containing desired pid
{noreply, NewState}.
但是,我对这个解决方案并不满意。
问题是:根据 OTP 设计原则,监督树成员之间最常规的交互方式是什么?
【问题讨论】:
-
您能解释一下为什么您的解决方案不能让您满意吗?
-
如果你打算创建一个应用程序,每个VM只能运行一次,所以在你描述的情况下,我不认为使用本地注册的进程是一个不好的解决方案。
-
@Pascal,是的,我打算。但是这样的注册不仅会导致“应用程序”实例之间的名称冲突,而且还会增加与其他进程发生名称冲突的可能性。不过,看起来我应该考虑这个解决方案。
-
@evnu,这个解决方案看起来不太自然和清晰。我专门为在初始化阶段使用一次而创建了新消息。这条消息是通过进程发送给它自己的……奥卡姆在他的坟墓里转身 (en.wikipedia.org/wiki/Occam's_razor)。
-
为了避免名称冲突我通常选择模块名称作为进程名称,如果我没有模块名称冲突,那么我有它用于进程一的可能性很小。
标签: erlang erlang-otp