您的位置:首页 > 移动开发

Erlang入门:构建application练习4(进程link的作用)

2015-01-16 17:40 507 查看

1、示例项目(bank)简介



bank_server.erl是为客户服务的进程回调模块

bank_center.erl是为银行服务中心的进程回调模块

客户(bank_server)每年都要扣除年费

所有年费都交给银行服务中心(bank_center)

客户服务使用示例:

创建用户:bank_server:create_account(myname, 100).

用户存钱:myname ! {deposit, 10}.

用户取钱:myname ! {cash1, 20}.

myname ! {cash2, 30}.

查询余额:myname ! check.

银行服务中心使用示例:

查询收到的年费总额:bank_center ! check.

2、启动bank_center

2.1、bank_center里有3个启动API

%% 此处?MODULE为bank_center

start()->
%% gen_server:start/3
%% 无link,无注册
{ok, Pid} = gen_server:start(?MODULE, [], []),
%% 自行注册
erlang:register(?MODULE, Pid).

start2()->
%% gen_server:start/4
%% 无link,注册为本地进程,名称为?MODULE
gen_server:start({local, ?MODULE}, ?MODULE, [], []).

start_link()->
%% gen_server:start_link/4
%% 有link,有注册
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).


用start/0或start2/0是无link的,start_link/0是有link的。

2.2、在bank_app里启动bank_center

-module(bank_app).
-behaviour(application).
-export([start/2, stop/1]).

-include("common.hrl").

start(_Type, _Args) ->
?I("Start ~p ...", [?MODULE]),
% bank_center:start(),
% bank_center:start2(),
bank_center:start_link(),
{ok, self()}.

stop(_State) ->
?I("Stop ~p!", [?MODULE]),
ok.


在上面start/2里调用bank_center:start/0或bank_center:start2/0启动后,

执行appmon:start()查看bank进程,如下:



在上面start/2里调用bank_center:start_link/0启动后,

执行appmon:start()查看bank进程,如下:



3、创建客户进程后,和bank_center进行link

bank_server.erl中的init/1
init([Money]) ->
%% 与银行服务中心进行关联
link(whereis(bank_center)),
{ok, Money}.

4、link实验

4.1、测试link的作用

link方式启动bank_center并且创建一个客户:
bank_server:create_account(myname1, 100).
whereis(bank_center)查看bank_center进程ID,返回不为undefined说明bank_center进程存在

向客户进程发送一个错误:
myname1 ! error.
此时myname1异常退出,whereis(bank_center)和whereis(myname1)都返回undefined,说明这两个进程都已经终止。
Eshell V5.10.4 (abort with ^G)
1> bank_server:create_account(myname1, 100).
true
2> whereis(bank_center).
<0.37.0>
3> myname1 ! error.
##[<0.38.0>bank_server:141] terminate: {bad_return_value,{ok,80}}
error
4>
=ERROR REPORT==== 16-Jan-2015::16:54:58 ===
** Generic server <0.38.0> terminating
** Last message in was error
** When Server state == 80
** Reason for termination ==
** {bad_return_value,{ok,80}}

4> whereis(bank_center).
undefined
5> whereis(myname1).
undefined
小结:用link进行关联的进程组中,只要其中一个进程终止,其他也会同时终止。

4.2、设置bank_center为系统进程,并且能监控客户进程的退出

设置bank_center为系统进程:

bank_center.erl中的init/1
init(_) ->
%% 把系统进程设置为系统进程
process_flag(trap_exit, true),
?I("Start ~p ...", [?MODULE]),
{ok, 0}.
演示过程如下:
Eshell V5.10.4 (abort with ^G)
1> bank_server:create_account(myname1, 100).
true
2>
2> myname1 ! error.
##[<0.38.0>bank_server:141] terminate: {bad_return_value,{ok,100}}
##[<0.37.0>bank_center:81] handle_info: {'EXIT',<0.38.0>,
{bad_return_value,{ok,100}}}
error
3>
=ERROR REPORT==== 16-Jan-2015::17:12:34 ===
** Generic server <0.38.0> terminating
** Last message in was error
** When Server state == 100
** Reason for termination ==
** {bad_return_value,{ok,100}}

3> whereis(bank_center).
<0.37.0>
4> whereis(myname1).
undefined
whereis(myname1).返回undefined说明已经终止。

whereis(bank_center)返回了PID,说明没有终止,并且收到了myname1的退出消息:
{'EXIT', <0.38.0>, {bad_return_value,{ok,100}}}
消息中指明了退出的PID及退出原因。

以上都是以异常的方式让进程退出的,现在测试一下正常退出的情况:
Eshell V5.10.4 (abort with ^G)
1> bank_server:create_account(myname1, 100).
true
2> myname1 ! stop2.
##[<0.38.0>bank_server:141] terminate: normal
##[<0.37.0>bank_center:81] handle_info: {'EXIT',<0.38.0>,normal}
stop2
正常退出不会报错,收到了正常退出消息:{'EXIT',<0.38.0>,normal}

小结:通过process_flag(trap_exit, true)将进程设置为系统,不但不会随着别的进程退出而退出,还能监控其他进程的退出情况。

问题:如果系统进程内部发生了错误而异常退出,将会出现什么情况?

5、完整演示代码下载

地址:http://download.csdn.net/detail/u011471961/8368973
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息