标签:
1 %% sington.erl 2 -module(singleton). 3 -author("Russell-X-Shanso"). 4 5 %% API 6 -export([ get_singleton/0 ]). 7 8 -define( SINGLETONNAME, singleton_example ). 9 10 %% 对外接口,获取单例进程 11 get_singleton( ) -> 12 case whereis( ?SINGLETONNAME ) of 13 undefined -> 14 Singleton = spawn( fun singleton_loop/0 ), 15 register( ?SINGLETONNAME, Singleton ), 16 Singleton; 17 Pid -> Pid; 18 end. 19 20 %% 单例实体循环 21 singleton_loop( ) -> 22 receive 23 Msg -> 24 do_msg( Msg ), 25 singleton_loop( ) 26 end. 27 28 %% 单例消息处理函数 29 do_msg( Msg ) -> 30 %% 执行所需动作 31 io:format( "Message:~p~n", [ Msg ]).
而在全局使用时,我们就可以:
1 %% sington_user.erl 2 -module(singleton_user). 3 -author("Russell-X-Shanso"). 4 5 %% API 6 -export([test/0]). 7 8 test( ) -> 9 Sington = singleton:get_singleton(), 10 Sington ! "This is test1!", 11 ok.
测试效果很简单:
以上的代码中,spawn( fun singleton_loop/0 )一行派生了一个进程,并在后面通过register方法进行注册形成全局唯一的实例;
我们结合OTP中的源码来看一下实际应用单例的情况,我们都知道gen_server等行为都是可以以命名方式来进行start或start_link,并且可以通过gen_server:call的方式根据命名进行调用的,这里是一处典型的单例模式:
gen_server的start中,涉及命名的启动方式会调用gen:start/6,见下面代码中start及start_link方法中带有Name参的部分:
%% gen_server.erl line 157-167 of erl_ver_17.3 start(Mod, Args, Options) -> gen:start(?MODULE, nolink, Mod, Args, Options). start(Name, Mod, Args, Options) -> gen:start(?MODULE, nolink, Name, Mod, Args, Options). start_link(Mod, Args, Options) -> gen:start(?MODULE, link, Mod, Args, Options). start_link(Name, Mod, Args, Options) -> gen:start(?MODULE, link, Name, Mod, Args, Options).
而在gen.erl的gen:start/6中:
%% gen.erl line 69-83 of erl_ver_17.3 -spec start(module(), linkage(), emgr_name(), module(), term(), options()) -> start_ret(). start(GenMod, LinkP, Name, Mod, Args, Options) -> case where(Name) of undefined -> do_spawn(GenMod, LinkP, Name, Mod, Args, Options); Pid -> {error, {already_started, Pid}} end.
%% gen.erl line 282-304 of erl_ver_17.3 where({global, Name}) -> global:whereis_name(Name); where({via, Module, Name}) -> Module:whereis_name(Name); where({local, Name}) -> whereis(Name). name_register({local, Name} = LN) -> try register(Name, self()) of true -> true catch error:_ -> {false, where(LN)} end; name_register({global, Name} = GN) -> case global:register_name(Name, self()) of yes -> true; no -> {false, where(GN)} end; name_register({via, Module, Name} = GN) -> case Module:register_name(Name, self()) of yes -> true; no -> {false, where(GN)} end.
1 %% prototype_server.erl 2 -module(prototype_server). 3 -author("Russell-X-Shanso"). 4 5 -behaviour(gen_server). 6 7 %% API 8 -export([start/1, clone/1]). 9 -export([get/1, set/2]). 10 11 %% gen_server callbacks 12 -export([init/1, 13 handle_call/3, 14 handle_cast/2, 15 handle_info/2, 16 terminate/2, 17 code_change/3]). 18 19 %% Server 启动 20 start( InitValue ) -> 21 gen_server:start( ?MODULE, InitValue, []). 22 23 %% 克隆方法 24 clone( OtherServer ) when is_pid( OtherServer ) -> 25 gen_server:start( ?MODULE, OtherServer, [] ); 26 clone( _OtherServer ) -> 27 { error, <<"It‘s not a prototype">> }. 28 29 %% 方便检验做的辅助接口 30 get( ServerPid ) when is_pid( ServerPid ) -> 31 gen_server:call( ServerPid, { get } ). 32 set( ServerPid, Value ) when is_pid( ServerPid ) andalso is_integer( Value ) -> 33 gen_server:call( ServerPid, { set, Value } ). 34 35 36 init( OtherServer ) when is_pid( OtherServer ) -> 37 %% 克隆核心数据,这里应根据需要实现全部克隆或部分克隆 38 CloneValue = gen_server:call( OtherServer, { get } ), 39 { ok, #{ test_value => CloneValue } }; 40 init(InitValue) -> 41 {ok, #{ test_value => InitValue }}. 42 43 handle_call( { get }, _From, State) -> 44 {reply, maps:get( test_value, State ), State }; 45 handle_call( { set, Value }, _From, State) -> 46 {reply, ok, State#{ test_value => Value } }; 47 handle_call(_Request, _From, State) -> 48 {reply, ok, State}. 49 50 51 handle_cast(_Request, State) -> 52 {noreply, State}. 53 54 handle_info(_Info, State) -> 55 {noreply, State}. 56 57 terminate(_Reason, _State) -> 58 ok. 59 60 code_change(_OldVsn, State, _Extra) -> 61 {ok, State}.
测试代码:
1 %% prototype_test.erl 2 -module(prototype_test). 3 -author("Russell-X-Shanso"). 4 5 %% API 6 -export([ test/0 ]). 7 8 9 test() -> 10 %% 启动 Server_A 11 { ok, Server_A } = prototype_server:start( 1 ), 12 %% 为 Server_A 的 State 赋新值 13 ok = prototype_server:set( Server_A, 2 ), 14 %% 根据 Server_A 克隆 Server_B, 实质为将ServerA中 State的值复制给ServerB 15 { ok, Server_B } = prototype_server:clone( Server_A ), 16 %% 获取ServerB的数值检验复制成功 17 ValueB1 = prototype_server:get( Server_B ), 18 %% 对Server再次赋值,分别检验ServerA与ServerB的值, 来验证两者的独立性 19 ok = prototype_server:set( Server_A, 3 ), 20 ok = prototype_server:set( Server_B, 4 ), 21 ValueA = prototype_server:get( Server_A ), 22 ValueB2 = prototype_server:get( Server_B ), 23 io:format( "ValueB1 = ~p~nValueA = ~p~nValueB2= ~p~n", [ ValueB1, ValueA, ValueB2 ] ).
测试效果:
标签:
原文地址:http://www.cnblogs.com/shanso/p/4761370.html