How to run gen_server or gen_fsm on demand in Erlang without race conditions?

I need to create several independent instances of the same gen_fsm upon request, and then be able to route calls to the correct instance.

The gproc library is a great way to register processes with arbitrary names. It has a gproc: reg_or_locate / 3 function for spawning things on demand without race conditions. That way, I don’t even need a supervisor - if they fail, they will reappear upon request again. But I can’t understand how to apply gproc:reg_or_locate/3gen_fsm or gen_server to generate.

What I have tried so far:

I just call gen_server: start () through this function, it will create an intermediate process, give a name to the intermediate process, the intermediate process will spawn gen_server and terminate, and I get an unnamed gen_server.

Both gen_server and gen_fsm export the enter_loop function , which seems to do what I need if I pass it to gproc:reg_or_locate/3, but the documentation says:

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

And the docs for gproc:reg_or_locate/3not mentioning that they are doing something through proc_lib.

, gen_server gen_fsm, , : gen_fsm, , gen_fsm, .

, - . , . ?

+4
3

, gproc:reg_or_locate/3 - . PID (- ), , , , Erlang, . , , , , , , , . - gen_server:call gen_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, .

+3

, .

{via,Module,ViaName} gen_server:start_link , atoms. . : http://erlang.org/doc/man/gen_server.html#start_link-4

, gproc

gen_server:start_link({via, gproc, {n, l, {?MODULE, Name}}, ?MODULE, [], []).

{via, gproc, ...} gen_server, Name:

gen_server:call({via, gproc, {n, l, {?MODULE, Name}}, {execute_command, Command}). 

via :

-define(SERVER(Name), {via, gproc, {n, l, {?MODULE, Name}}}).

:

gen_server:start_link(?SERVER("Testing"), ?MODULE, [], []).
gen_server:call(?SERVER("Testing"), {execute_command, Command}).

simple_one_for_one temporary, :

-module(my_cool_sup).

-behaviour(supervisor).

%% API
-export([start_link/1, start_child/1]).    
%% Supervisor callbacks
-export([init/1]).

-define(SERVER, ?MODULE).

%% Helper macro for declaring children of supervisor
-define(CHILD(ChildName, Type, Args), {ChildName, {ChildName, start_link, Args}, temporary, 5000, Type, [ChildName]}).

%%====================================================================
%% API functions
%%====================================================================

start_link() ->
    supervisor:start_link({local, ?SERVER}, ?MODULE, []).

start_child(Name) ->
    supervisor:start_child(?SERVER, [Name]).

%%====================================================================
%% Supervisor callbacks
%%====================================================================

init([]) ->
    RestartStrategy = {simple_one_for_one, 1, 5},

    Children = [?CHILD(my_cool_server, worker, [])],

    {ok, { RestartStrategy, Children} }.

gen_server

-module(my_cool_server).

-behavior(gen_server).

%% API
-export([start_link/3, execute_command/3]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
     terminate/2, code_change/3]).

-define(SERVER(Name), {via, gproc, {n, l, {?MODULE, Name}}}).

%%%===================================================================
%%% API
%%%===================================================================

start_link(Name) ->
    gen_server:start_link(?SERVER(Name), ?MODULE, [], []).

execute_command(Name, Command) ->
    gen_server:call(?SERVER(Name), {execute_command, Command}). 

%%%===================================================================
%%% gen_server callbacks
%%%===================================================================

%% Your normal gen_server callbacks here...

my_cool_sup:start_child("My cool name")., . , , already_started, .

start_child : http://erlang.org/doc/man/supervisor.html#start_child-2

+1

My preferred way to solve this problem is to use the gen_tracker library. It provides a common supervisor that matches the behavior of the OTP supervisor with an integrated local process registry.

It definitely does not cover all possible cases, but is suitable for use in not too complicated cases.

0
source

Source: https://habr.com/ru/post/1627691/


All Articles