Почему исполнители simple_one_for_one могут иметь один и тот же идентификатор дочерней спецификации?

Я определяю рабочую спецификацию simple_one_for_one для одного руководителя с именем band_supervisor, а идентификатор дочерней спецификации — jam_musician:

  init([]) ->
    {ok, {{simple_one_for_one, 3, 60},
    [{jam_musician,
    {musicians, start_link, []},
    temporary, 1000, worker, [musicians]}
    ]}};

модуль музыкантов это:

-module(musicians).
-behaviour(gen_server).

-export([start_link/2, stop/1]).
-export([init/1, handle_call/3, handle_cast/2,
handle_info/2, code_change/3, terminate/2]).

-record(state, {name="", role, skill=good}).
-define(DELAY, 750).

start_link(Role, Skill) ->
  gen_server:start_link({local, Role}, ?MODULE, [Role, Skill], []).

stop(Role) -> gen_server:call(Role, stop).

и я могу создать много рабочих:

3> supervisor:start_child(band_supervisor, [drum, good]).
Musician Arnold Ramon, playing the drum entered the room
{ok,<0.696.0>}
3> supervisor:start_child(band_supervisor, [guitar, good]).
Musician Wanda Perlstein, playing the guitar entered the room
{ok,<0.698.0>}

Я заметил, что все рабочие имеют один и тот же идентификатор дочерней спецификации: jam_musician

Вы знаете, что другие рабочие типы должны иметь уникальный дочерний идентификатор, верно?


person why    schedule 02.04.2013    source источник
comment
Не могли бы вы опубликовать свой код для модуля musicians, пожалуйста? Похоже, вы регистрируете дочерние процессы с тем же именем.   -  person Isac    schedule 02.04.2013
comment
Да, ваш код, пожалуйста, и для модуля супервизора. Что-то не так, вы не можете получить already_started от руководителя simple_one_for_one.   -  person rvirding    schedule 02.04.2013
comment
@Isac обновился, идентификатор дочерней спецификации можно дублировать?   -  person why    schedule 03.04.2013


Ответы (2)


Идентификатор дочерней спецификации будет одинаковым для супервизоров simple_one_for_one, поскольку существует только один дочерний тип и множество дочерних экземпляров (воркеров) этого типа.

Из supervisorдокументов по поведению:

Обратите внимание, что при стратегии перезапуска simple_one_for_one список дочерних спецификаций должен быть списком только с одной дочерней спецификацией. (Идентификатор дочерней спецификации игнорируется.) В этом случае ни один дочерний процесс не запускается на этапе инициализации, но предполагается, что все дочерние процессы запускаются динамически с использованием start_child/2.

person Isac    schedule 03.04.2013

Скорее всего, вы написали функцию start_link дочернего процесса (я предполагаю, что это gen_server) как:

start_link() ->
    gen_server:start_link({local,Name}, ?MODULE, [], []).

Это не только вызывает функцию init/1, но также регистрирует процесс, используя имя атома.

Поэтому любой новый дочерний элемент, запущенный во второй момент, попытается зарегистрироваться внутри узла erlang, используя имя, уже занятое первым дочерним элементом.

Чтобы избежать такого конфликта имен, вы должны использовать что-то вроде:

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

Так что ни у одного ребенка не будет зарегистрированного имени, и у вас не будет конфликтов.

Если вам действительно нужно зарегистрировать каждого ребенка, вариант может заключаться в использовании gproc.

person user601836    schedule 02.04.2013
comment
Это приведет к ошибке, а не к возврату already_started. Вы только получите already_started, если будете выполнять restart_child/2 с не руководителем simple_one_for_one и попытаетесь запустить уже запущенный идентификатор. Вы не можете получить его с супервайзером simple_one_for_one, где идентификатор игнорируется. - person rvirding; 02.04.2013
comment
Мой последний вопрос: нужно ли сначала определить дочернюю спецификацию в функции обратного вызова init, если я хочу запустить дочернюю спецификацию позже? - person why; 03.04.2013
comment
Я больше не слежу за тобой. Я не понимаю, чего вы хотите добиться здесь - person user601836; 03.04.2013
comment
В simple_one_for_one вы должны определить дочернюю спецификацию, так как она используется для всех дочерних элементов, и вы не даете ее при запуске дочернего элемента. Во всех других случаях вам не нужно указывать его, так как вы должны явно указать дочернюю спецификацию при вызове supervisor:start_child/2. Супервизор автоматически запустит дочерние спецификации с дочерними спецификациями, возвращенными в обратном вызове init/1. Затем вы можете добавить детей, используя supervisor:start_child/2. - person rvirding; 03.04.2013