gpt4 book ai didi

multithreading - 如何在没有竞争条件的情况下在 Erlang 中按需启动 gen_server 或 gen_fsm?

转载 作者:行者123 更新时间:2023-12-04 08:26:37 24 4
gpt4 key购买 nike

我需要根据需要生成相同 gen_fsm 的几个独立实例,然后能够将调用路由到正确的实例。

Gproc library 似乎是一种用任意名称注册进程的好方法。它有一个功能 gproc:reg_or_locate/3用于在没有竞争条件的情况下按需生成东西。这样我什至不需要主管 - 如果他们崩溃,他们将再次按需生成。但是我不知道如何申请gproc:reg_or_locate/3生成 gen_fsm 或 gen_server。

到目前为止我尝试过的:

我只是通过该函数调用 gen_server:start() ,它将创建一个中间进程,为中间进程命名,中间进程将产生一个 gen_server 并终止,最后我得到一个无名的 gen_server。

gen_server 和 gen_fsm 都导出 enter_loop如果我将它提供给 gproc:reg_or_locate/3,它似乎可以满足我的需求,但文档内容如下:

The process must have been started using one of the start functions in proc_lib, see proc_lib(3).



以及 gproc:reg_or_locate/3 的文档不要提到他们通过 proc_lib 做任何事情。

或者,我可以让中间进程获取名称,然后以原子方式将其传输到它生成的 gen_server 或 gen_fsm,但这会产生竞争条件:中间进程将具有 gen_fsm 的名称,并且任何用于 gen_fsm 的消息都将发送到中间进程过程并迷路。

我觉得我在这里错过了一些简单的东西。这不是一种罕见的模式,所以应该有一个很好的方法来做到这一点。我错过了什么?

最佳答案

为了您的目的,我不认为 gproc:reg_or_locate/3真的给你任何有用的东西。如果它返回一个 PID(由于产生一个新进程,或定位一个现有进程)该进程仍然可能在你向它发送消息之前死亡,所以除非你在基本的 Erlang 消息传递之上有一个机制,否则你永远不会知道这没有发生。即使在您发送消息时服务器还活着,服务器也可能在收到消息之前就死了,或者在处理它之前就死了,所以如果您表达了对消息丢失的担忧,那么解决方案的一个组成部分必须是可靠的消息机制。明智且现成的解决方案是 gen_server:callgen_fsm:sync_send_event在您的情况下,而不仅仅是发送消息。

这消除了消息从您想要实现的任何生成解决方案中丢失的问题。也就是说,您将知道消息丢失或失败,然后您可以采取任何适当的措施。

现在,对于服务器的实际生成,总会存在竞争条件,无论您如何实现,多个进程可能会尝试生成相同的服务器(具有给定名称的服务器);在您执行其他任何操作之前,您要查找名称的任何内容(例如 erlang:whereis/1 )都可能已过时(它可能会返回一个 PID,但该 PID 可能会在您发送消息之前死亡,或者它可能会返回 undefined 但其他一些过程可能会在您尝试之前注册名称),因此比赛获胜(或失败)的唯一时刻是 erlang:register/2叫做。

你知道可能会有一场比赛,但最多只能有一个赢家。可能不是你,其他一些进程可能会打败你,但由于你正在命名无关紧要的进程,你可以简单地产生你的 gen_server,给它一个名称来注册自己,然后通过姓名:

gen_server:start({local, Name}, ?MODULE, [], []),
gen_server:call(Name, Message)

谁赢得了比赛并不重要( gen_server:start/4 调用可能会返回 {error,{already_started, Pid}} )但那又怎样,重要的是有人应该赢了,然后调用 gen_server:call之后就有成功的机会。

显然,您确实需要确保调用返回了合适的成功结果,从技术上讲,您可以检查 noproc异常并尝试再次生成它,但是您必须确保这不会成为无限循环。

老实说,虽然你不在乎监督,但无论如何我可能会监督它。在这种情况下,一个 simple_one_to_one将重启策略设置为 temporary 的主管所以它不适合重生。然后你的服务器将被收集在一个地方,而不仅仅是漂浮在边缘,你会得到主管报告,这不会是一件坏事。遗憾的是,您不会得到失控的重启保护,因为这里没有重启,所以您仍然需要担心(除非您将 temporary 更改为 transient )。您的有效仲裁点将是 supervisor:start_child/2您可以将所需的进程名称作为参数传递。

关于multithreading - 如何在没有竞争条件的情况下在 Erlang 中按需启动 gen_server 或 gen_fsm?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35258965/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com