Erlang中的错误处理

1.定义
2.当进程终止的时候退出信号被送出
3.进程退出信号通过链接(进程之间的关系)传播
4.进程能够捕捉退出信号
5.复杂的退出信号传播
6.通过分层构建健壮系统
7.用于信号处理的基本概念
8.构建一个健壮的服务器
9.带有错误恢复的分配器
10.分配器

1.定义

Link - 退出信号的双向传递路径,链接(Link)的两个进程,任何一个退出后,将发送退出信号给对方
Exit Signal - 传递进程终止(崩溃)的消息
Error trapping - 当退出信号发送给另一个进程时,另一个进程处理退出信号的能力

2.当进程终止的时候退出信号被送出

当进程因错误而退出(例如,调用BIF错误或匹配错误),退出信号将会发送给该进程所有的链接进程。



3.进程退出信号通过链接(进程之间的关系)传播

假设我们某些进程链接在一起,如下图,进程A链接进程B,进程B链接进程C(链接如下箭头所指),现在如果进程A退出-退出信号通过链接进程进行广播如下。


退出信号最终到达所有链接的进程。

传播错误信号的规则是:如果进程接收到因错误而导致的退出信号,如果进程没有设置捕捉该信号,这个时候该因错误进程退出,并发送退出信号给所有链接的进程。

4.进程能够捕捉退出信号

下面图中P1链接P2,P2链接P3,如果P1发生错误,错误将传播到P2,如果P2捕捉错误信号,那么信号将不再传播到P3.


P2 代码如下:


receive
    {'EXIT', P1, Why} ->
... exit signals ...
    {P3, Msg} ->
... normal messages ...
end


5.复杂的退出信号传播

假设我们有下面的进程链接关系:


标识为双环的进程是可捕捉错误。


如果错误在A、B和C当中任何一个发生,通过传播错误,所有链接的进程将会死去,因C捕捉了信号,所以D进程不受影响。

退出信号传递规则:

 - 当一个进程终止将发送退出信号,信号分为正常退出信号和非正常退出信号,该信号将会发送给链接的进程。
 - 如果一个进程没有设置捕捉进程退出信号,当该进程接收到一个非正常终止的其它进程退出信号,该进程将退出,向其链接的进程发送非正常终止的退出信号。
 - 当一个进程设置了捕捉信号后,当链接进程的退出信号到达后,该退出信号将会转变为普通的进行接收的消息,可以通过receive语句接收该退出信号。
 - 当进程调用内建函数(BIF)或模式匹配错误发生时,将自动的发送退出信号给其链接的进程。

6. 通过分层构建健壮系统

通过分层的方式可以建立一个健壮的系统。Level1用于捕捉和更正Level2发生的错误,Level2用于捕捉和更正应用层的错误。
总而言之,系统设计时对于应用层的程序员不安排些错误处理的代码,原因是所有错误处理将会被送到更深一层的系统当中。


7.用于信号处理的基本概念

link(Pid) - 建立一个双向的链接位于当前进程和Pid标识的进程之间
process_flag(trap_exit, true) - 设置当前进程将达到的退出信号转化为退出消息,通过receive语言可以接收这些消息。
exit(Reason) - 终止进程并产生退出信号,Reason中是进程的退出信息。

下面是实际发生的:每个进程有一个关联的邮箱 -Pid ! Msg 语句为发送消息Msg到Pid进程关联的邮箱。通过 receive ... end结构试图将当前进程mailbox中的消息删除。退出信号到达一个进程时,要么导致进程终止(如果进程没有设置退出信号)或退出信号当做普通的消息置于进程的邮箱当中(如果进程设置了捕捉信号)。退出信号被隐式(例如BIF错误)或显示(调用EXIT(Pid,Reason)或exit(Reason))的。

如果退出原因(Reason)是原子normal - 接收的进程将忽略该信号(在没有设置捕捉退出信号情况时),当进程退出的时候,在没有发送错误信号给链接的进程时,它将会发送normal退出信息给链接的进程。

8.构建一个健壮的服务器

下面服务器假设客户进程将发送请求分配资源的消息给服务器,然后发送一个释放资源消息告诉服务器释放资源。当客户申请资源后,释放资源前崩溃了,造成了系统的不稳定。

top(Free, Allocated) ->
    receive
	{Pid, alloc} ->
	    top_alloc(Free, Allocated, Pid);
	{Pid ,{release, Resource}} ->
	    Allocated1 = delete({Resource,Pid},�Allocated),
    	    top([Resource|Free], Allocated1)
    end.

top_alloc([], Allocated, Pid) ->
    Pid ! no,
    top([], Allocated);

top_alloc([Resource|Free], Allocated, Pid) ->
    Pid ! {yes, Resource},
    top(Free, [{Resource,Pid}|Allocated]).

top循环是无错误恢复的循环分配器。Free是未分配资源的列表,Allocated是分配资源的列表,由 {Resource, Pid}元组构成-表明资源被分配的进程 

9.带有错误恢复的分配器

下面是可靠的服务器。如果客户在释放资源之前崩溃后,服务器将自动释放其资源。在客户被分配到资源后,服务器进程与客户进程建立了链接,当来自客户退出消息后,服务器自动将客户占用的资源释放掉。

top_recover_alloc([], Allocated, Pid) ->
    Pid ! no,
    top_recover([], Allocated);

top_recover_alloc([Resource|Free], Allocated, Pid) ->
    %% No need to unlink.
    Pid ! {yes, Resource},
    link(Pid),
    top_recover(Free, [{Resource,Pid}|Allocated]).

top_recover(Free, Allocated) ->
    receive
	{Pid , alloc}�->
	    top_recover_alloc(Free, Allocated, Pid);
	{Pid, {release, Resource}}�->
	    unlink(Pid),
 	    Allocated1 = delete({Resource, Pid}, Allocated),
	    top_recover([Resource|Free], Allocated1);
	{'EXIT', Pid, Reason}�->
	    %% No need to unlink.
	    Resource = lookup(Pid, Allocated),
	    Allocated1 = delete({Resource, Pid}, Allocated),
	    top_recover([Resource|Free], Allocated1)
    end.


不能完成的是 -- 当同一个进程被分配了多个资源
例如在unlink(Pid)进程时,需要检查改进是否被分配了多个资源。

10.分配器

%%删除列表中的H
delete(H, [H|T]) ->
    T;
delete(X, [H|T]) ->
    [H|delete(X, T)].

%%找到Pid被分配的资源
lookup(Pid, [{Resource,Pid}|_]) ->
    Resource;
lookup(Pid, [_|Allocated]) ->
    lookup(Pid, Allocated).


阅读更多
个人分类: erlang
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭