2016-09-10 29 views
5

gen_server dokumentację Module:terminate zwrotnego mówi:Nienadzorowany gen_server nie wymaga wypowiedzenia, gdy odbiera sygnał EXIT

Nawet jeśli proces gen_server nie jest częścią drzewa nadzoru, to funkcja jest wywoływana w przypadku otrzymania Wiadomość "EXIT" od rodzica. Powód jest taki sam jak w komunikacie "WYJŚCIE".

Oto moja handle_info i terminate funkcja:

handle_info(UnknownMessage, State) -> 
    io:format("Got unknown message: ~p~n", [UnknownMessage]), 
    {noreply, State}. 

terminate(Reason, State) -> 
    io:format("Terminating with reason: ~p~n", [Reason]). 

zacznę ten serwer przy użyciu gen_server:start. Zakładam, że gdy zadzwonię pod numer erlang:exit(Pid, fuckoff), powinien zadzwonić pod numer terminate. Ale pokazuje:

Got unknown message: {'EXIT',<0.33.0>,fuckoff} 

Co oznacza, że ​​dzwoni handle_info. Ale kiedy zadzwonię pod numer gen_server:stop, wszystko działa zgodnie z dokumentacją. Dzwonię pod numer gen_server z powłoki. Czy mógłbyś to wyjaśnić?

[Update]

Here jest kod źródłowy decode_msg funkcji wewnątrz gen_server. Jeśli nie otrzyma żadnej wiadomości „exit” powinien zadzwonić terminate funkcję:

decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) -> 
    case Msg of 
    {system, From, Req} -> 
     sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug, 
        [Name, State, Mod, Time], Hib); 
    {'EXIT', Parent, Reason} -> 
     terminate(Reason, Name, Msg, Mod, State, Debug); 
    _Msg when Debug =:= [] -> 
     handle_msg(Msg, Parent, Name, State, Mod); 
    _Msg -> 
     Debug1 = sys:handle_debug(Debug, fun print_event/3, 
         Name, {in, Msg}), 
     handle_msg(Msg, Parent, Name, State, Mod, Debug1) 
end. 

W moim przypadku nie wymaga terminate funkcję.

[UPDATE]

Kiedy zacznę gen_server użyciu gen_server:start_link(), wysyłając sygnał wyjściowy używając erlang:exit(Pid, Reason) spowoduje wywołanie terminate oddzwonię funkcję, która jest oczekiwane zachowanie. Wydaje się, że istnieje różnica w interpretacji sygnału wyjściowego, niezależnie od tego, czy proces jest powiązany z rodzicem czy nie.

+0

Czy ustawiłeś flagę 'trap_exit' procesu na' true' gdzieś w kodzie? –

+0

Tak. Wewnątrz funkcji 'init'. –

Odpowiedz

2

Krótka odpowiedź:

Jeśli zadzwonisz funkcja exit/2 z wnętrza gen_server aktor zachowuje się zgodnie z oczekiwaniami na podstawie dokumentacji i terminate/2 zwrotna zostanie wywołana.

odpowiedź Long:

Po wysłaniu wiadomości wyjścia ze skorupy, wartość Parent wyprowadzenia krotki jest ustawiony na identyfikator procesu powłoki, natomiast po uruchomieniu formularza gen_server proces powłoki jego Parent wartość jest ustawiona na własny identyfikator procesu, a nie na identyfikator procesu powłoki, dlatego gdy otrzyma komunikat wyjścia, nie pasuje do drugiej klauzuli bloku odbioru w funkcji decode_msg/8, więc funkcja terminate/6 nie jest wywoływana, a na końcu kolejna klauzula jest dopasowany, który wywołuje funkcję handle_msg/5.

Zalecenie:

Dla uzyskania terminate/3 zwrotnego nazwie nawet wysyłając wiadomość wyjścia do procesu gen_server, można pułapka komunikat zjazd w handle_info/2 a następnie powrót z przystanku krotki następująco:

init([]) -> 
    process_flag(trap_exit, true), 
    {ok, #state{}}. 

handle_info({'EXIT', _From, Reason}, State) -> 
    io:format("Got exit message: ~p~n", []), 
    {stop, Reason, State}. 

terminate(Reason, State) -> 
    io:format("Terminating with reason: ~p~n", [Reason]), 
    %% do cleanup ... 
    ok. 
+0

Mam to. Widzę to w "obserwatorze". Dlaczego rodzic jest ustawiony na swój własny identyfikator procesu, kiedy uruchamiam proces w powłoce? Jakieś specjalne powody? –

+1

@MajidAzimi: W oparciu o kod, 'gen: get_parent/0', który jest odpowiedzialny za znalezienie elementu nadrzędnego' gen_server', szuka pierwszego elementu klucza '$ ancestors' w słowniku procesu. Ponieważ proces 'gen_server' jest procesem OTP, który rozpoczyna się od' proc_lib', powinien mieć identyfikator procesu aktora wywołującego w słowniku '$ antenc'', który jest w tym przypadku identyfikatorem procesu powłoki i ustawić go jako nadrzędny, ale nie działa zgodnie z oczekiwaniami. Potrzebuję więcej czasu, aby dowiedzieć się, czy to błąd, czy coś innego. –

+1

O ile mogę sprawdzić, kiedy uruchamiam proces OTP za pomocą 'gen _ *: start', pid macierzysty jest ustawiony na nowo utworzony sam proces. Rozpoczynając od 'gen _ *: start_link' ustawia się go na pierwszy element' $ przodków'. Nie ma znaczenia, czy rzeczywistym rodzicem jest powłoka, czy inny gen_ *. W obu przypadkach '$ ancestors' zawiera wszystkich rodziców aż do root'a. 'gen _ *: start_link' używa pierwszego elementu' $ ancestors', aby uzyskać obiekt nadrzędny (co jest oczekiwanym zachowaniem), ale z jakiegoś powodu 'gen _ *: start' używa własnego pid jako parent. –

0

Po uruchomieniu, jego prosty proces, więc, erlang:exit/1 lub erlang:exit/2 pracy oczekuje.

  • Jeśli Pid nie zatrzymując wyjść sama Pid wyjście z wyjściem Reason Reason.
  • Jeśli Pid blokuje wyjścia, sygnał wyjściowy zostaje przekształcony w komunikat {'EXIT', From, Reason} i dostarczony do kolejki komunikatów Pid.

Tak, obecnie swoją pułapka kod 'EXIT' ponieważ sygnał ten jest jak każdy inny wysyłać wiadomości do skrzynki pocztowej i mecz handle_info/2 wieloznacznym wzorca.

Jeśli chcesz uzyskać więcej informacji na ten temat, przeczytaj kod źródłowy gen_server i zobacz, jak to działa. W tym kodzie można również znaleźć kod your problem.

+0

Pozwól mi zadać pytanie w ten sposób: 'gen_server: stop' również wysyła sygnał wyjścia. Zostanie przekonwertowany na komunikat "EXIT". Jak 'gen_server' odróżnia tę wiadomość od mojego komunikatu 'EXIT' (który pochodzi z' exit') –

+0

'gen_server: handle_info/2' jest obecnie używany do przechwytywania każdego sygnału (nawet specjalnego). Tak więc, jeśli chcesz odróżnić sygnał "EXIT" od innego sygnału, twoja definicja 'handle_info' musi być inna (modyfikowanie dopasowywania wzorca, dodawanie wartowników ...). Aby być czystym, sygnał "EXIT" jest raczej konwencją niż standardem w Erlangu, ponieważ jest to tylko prosta wiadomość. –

+0

Zobacz aktualizację: dodałem kod źródłowy. –