2016-09-10 19 views
5

gen_server belgeleri aldığında sona çağırmaz diyor ki: bir alırsaEğiticisiz gen_server o <code>Module:terminate</code> Geri aramada çıkış sinyalini

gen_server süreci denetim ağacının bir parçası değilse bile

, bu fonksiyon denir Ebeveyninden 'EXIT' mesajı. Sebep, 'EXIT' mesajındakiyle aynıdır. Ben gen_server:start kullanarak bu sunucuyu başlatmak

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]). 

:

İşte benim handle_info ve terminate fonksiyonudur. erlang:exit(Pid, fuckoff)'u aradığımda, terminate geri arama işlevini çağırmalıyım. Ama gösterir:

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

o handle_info çağırıyor demek oluyor. Ama ben gen_server:stop'u aradığımda, her şey belgelerinde belirtildiği gibi çalışır. gen_server telefonumu kabuktan arıyorum. Bunu açıklığa kavuşturur musun?

[UPDATE]

Heregen_server içinde decode_msg fonksiyonunun kaynak kodu. o terminate işlevini çağırmaz Benim durumumda

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. 

: o herhangi bir 'ÇIKIŞ' mesajı alırsa o terminate işlevini çağırmalıdır.

[GÜNCELLEME]

Ben gen_server beklenen bir davranıştır işlevi terminate çağrıyı geri çağırma neden olacaktır erlang:exit(Pid, Reason) kullanarak bir çıkış sinyali göndererek, gen_server:start_link() kullanmaya başlamak. Bir sürecin ebeveyne bağlı olup olmadığı bir çıkış sinyalini yorumlamada bir fark var gibi görünüyor.

+0

"trap_exit" işlem bayrağını kodda "true" olarak ayarladınız mı? –

+0

Evet. İç init işlevi. –

cevap

2

Kısa cevap: belgelere dayanarak beklendiği gibi Eğer gen_server aktör içinden exit/2 fonksiyon ararsanız

, bu terminate/2 geri arama adı verilecek davranır.

Uzun cevap: kabuktan çıkmak mesaj göndermek zaman gen_server işlem formu başlattığınızda, çıkış başlığın Parent değeri diğer taraftan, kabuk işlem kimliği olarak ayarlanır

kabuk onun Parent değeri, kabuk işlem kimliği değil, kendi işlem kimliğine ayarlanır, bu nedenle çıkış iletisini aldığında, decode_msg/8 işlevinde alma bloğunun ikinci tümceyi ile eşleşmez, böylece terminate/6 işlevi çağrılmaz ve son olarak sonraki madde handle_msg/5 işlevini çağıran eşleştirildi.

Öneri: hatta gen_server sürecine bir çıkış mesajı göndererek denilen terminate/3 geri arama almak için

yapabilirsiniz aşağıdaki gibi çıkış handle_info/2 mesaj ve ardından durma tuple ile dönmek tuzak:

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

Anladım. Bunu gözlemciye görebiliyorum. Kabukta bir işlem başlattığımda neden ebeveyn kendi işlem kimliğine ayarlandı? Herhangi bir özel sebep? –

+1

@MajidAzimi: "Gen_server" 'in ebeveyini bulmaktan sorumlu olan "gen: get_parent/0" koduna dayanarak, işlem sözlüğündeki '$ acestors' anahtarının ilk öğesini arar. 'Gen_server' süreci 'proc_lib' ile başlatılan bir OTP süreci olduğundan, bu durumda kabuk işlem kimliği olan ve bunu ebeveyn olarak ayarlayan,' $ ataları 'sözlüğünde çağrılan aktör işlem kimliğine sahip olmalıdır. beklendiği gibi çalışmıyor. Bir böcek mi yoksa başka bir şey mi olduğunu bulmak için daha fazla zamana ihtiyacım var. –

+1

Kontrol edebildiğim kadarıyla, “gen _ *: start” kullanarak bir OTP sürecini başlattığımda, ebeveyn pid yeni oluşturulmuş işlemin kendisine ayarlanmış. 'Gen _ *: start_link' ile başladığınızda, "$ atalarının" ilk elemanına ayarlanır. Asıl ebeveynin kabuk veya başka bir gen_ * olması fark etmez. Her iki durumda da '$ ataları' köküne kadar tüm ebeveynleri içerir. 'gen _ *: start_link', ebeveyni (beklenen davranış) almak için '$ atasının' ilk öğesini kullanıyor, ancak bir nedenden dolayı 'gen _ *: start' kendi pidini ebeveyn olarak kullanıyor. –

0

gen_server'u başlattığınızda, bu basit bir işlemdir, bu nedenle, erlang:exit/1 veya erlang:exit/2 çalışma bekleniyor. Pid çıkar yakalama değilse

  • , Pid kendisi çıkış nedeni Reason ile çıkar.
  • Pid çıkışları yakalarsa, çıkış sinyali {'EXIT', From, Reason} mesajına dönüştürülür ve Pid'in mesaj sırasına iletilir.

Yani, bu biridir şu anda kod tuzak 'EXIT' sinyal nedeniyle posta kutusuna ve maç handle_info/2 joker desen içine diğer mesajlar gibi gönderin.

Daha fazla bilgi edinmek isterseniz, gen_server kaynak kodunu okuyabilir ve nasıl çalıştığını görebilirsiniz. Bu kodda açıklanan your problem'u da bulabilirsiniz.

+0

Soruyu şu şekilde sorayım: 'gen_server: stop' da çıkış sinyali gönderir. 'EXIT' mesajına dönüştürülecek. Bu mesajı 'EXIT' mesajımdan ('çıkış' dan geliyor) ' –

+0

'gen_server: handle_info/2', bu sinyali her sinyali (hatta özel olanı) yakalamak için kullanmaktadır. Yani, '' EXIT '' sinyalini başka bir sinyalden ayırt etmek istiyorsanız, 'handle_info' tanımınızın farklı olması gerekir (desen eşleştirmesi, korumaların eklenmesi ...). Net olmak gerekirse, '' EXIT '' sinyali, Erlang'daki bir standarttan ziyade bir kongre gibidir, çünkü onun sadece basit bir mesajı vardır. –

+0

Güncellemeye bakın: Kaynak kodunu ekledim. –

İlgili konular