Erlang進程的Link機制

這篇文章還不是最終版,有時間時,我會再來補充完善。編程

Erlang程序基於進程建模,進程之間的交互機制有收發消息,link和monitor。其中,收發消息一般用於正常的進程間通信,而link和monitor多用於異常狀況處理,本文從應用的角度介紹和分析link機制。link是雙向全聯通的,用來將兩個或多個進程綁定在一塊兒,綁定在一塊兒以後,VM會保證在有進程退出時,對與其綁定在一塊兒的進程執行特定的操做。app

Two processes can be linked to each other. A link between two
processes Pid1 and Pid2 is created by Pid1 calling the BIF
link(Pid2)(or vice versa). There also exists a number a spawn_link
BIFs, which spawns and links to a process in one operation.框架

Links are bidirectional and there can only be one link between two
processes.Repeated calls to link(Pid) have no effect.less

A link can be removed bycalling the BIF unlink(Pid).ui

當有進程退出時

發送Exit Signal

When a process terminates, it will terminate with an exit reason as
explained in Process Termination above. This exit reason is emitted in
an exit signal to all linked processes.this

A process can also call the function exit(Pid,Reason). This will
result in an exit signal with exit reason Reason being emitted to Pid,
but does not affect the calling process.spa

Exit Signal的默認處理方式

The default behaviour when a process receives an exit signal with an
exit reason other than normal, is to terminate and in turn emit exit
signals with the same exit reason to its linked processes. An exit
signal with reason normal is ignoreddebug

將Exit Signal轉換爲普通的進程消息

A process can be set to trap exit signals by calling:rest

process_flag(trap_exit, true)code

When a process is trapping exits, it will not terminate when an exit
signal is received. Instead, the signal is transformed into a
message{'EXIT',FromPid,Reason} which is put into the mailbox of the
process just like a regular message.

An exception to the above is if the exit reason is kill, that is if
exit(Pid,kill) has been called. This will unconditionally terminate
the process, regardless of if it is trapping exit signals or not.

link與OTP的關係

OTP做爲Erlang官方的編程框架被普遍應用,在OTP的實現中,link機制被普遍的應用。

Erlang has a built-in feature for error handling between processes.
Terminating processes will emit exit signals to all linked processes,
which may terminate as well or handle the exit in some way. This
feature can be used to build hierarchical program structures where
some processes are supervising other processes, for example restarting
them if they terminate abnormally.

Refer to OTP Design Principles for more information about OTP
supervision trees, which uses this feature.

gen_server

假設存在a,b兩個進程,其中b是gen_server。咱們在進程a中調用b:start_link(),使兩個進程link在一塊兒,而後來討論一些異常狀況。

  • a進程正常退出 -> b進程正常運行
  • a進程異常退出 -> b進程退出
  • a進程正常退出, b進程中調用了process_flag(trap_exit, true) -> b進程不會收到exit msg,退出
  • a進程異常退出, b進程中調用了process_flag(trap_exit, true) -> b進程不會收到exit msg,退出
  • b進程正常退出 -> a進程正常運行
  • b進程異常退出 -> a進程退出
  • b進程正常退出, a進程中調用了process_flag(trap_exit, true) -> a進程收到{'EXIT',Pid_b,normal}
  • b進程異常退出, a進程中調用了process_flag(trap_exit, true) -> a進程收到{'EXIT',Pid_b,Reason}

看起來第3項和第4項不太正常,彷佛跟剛剛介紹的erlang link機制衝突了。出現這種現象的緣由,是gen_server不是普通進程,它在一個普通的進程上,添加一些默認的行爲,具體到這個問題,就是gen_server在收到來自父進程(>調用start_link>的進程)的{'EXIT',Pid_Parent,Reason}

decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
     case Msg of
         {system, From, get_state} ->
             sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
                                   {State, [Name, State, Mod, Time]}, Hib);
         {system, From, {replace_state, StateFun}} ->
             NState = try StateFun(State) catch _:_ -> State end,
             sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
                                   {NState, [Name, NState, Mod, Time]}, Hib);
         {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.

link與業務建模

待續

相關文章
相關標籤/搜索