• 用Erlang求解建环问题


     代码如下所示

      1 -module(ring).
      2 -behaviour(gen_server).
      3 -export([start/3, ring_item_init/1]).
      4 
      5 %% 行为模式gen_server的回调函数
      6 -export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
      7 
      8 -define(SERVER, ?MODULE).
      9 
     10 %% 环中各个节点进程的状态,id:标识,从1开始,next:下一个进程号
     11 -record(state, {id, next}).
     12 
     13 %% 监督进程的状态,process_counter:环中节点的数量
     14 -record(server_state, {process_counter}).
     15 
     16 %% 入口函数,M:循环发送消息的次数,N:环中节点的数量,Message:循环的消息内容
     17 start(M, N, Message) ->
     18     gen_server:start_link({local, ?SERVER}, ?MODULE, #server_state{process_counter=N}, []),
     19     create_ring(N),             % 创建环
     20     transmit_msg(Message, M),   % 在环中循环传递消息
     21     destroy_ring().             % 删除环
     22 
     23 create_ring(N) ->
     24     gen_server:call(?SERVER, {create_ring, N}).
     25 
     26 transmit_msg(Message, M) ->
     27     gen_server:call(?SERVER, {transmit_msg, Message, M}).
     28 
     29 destroy_ring() ->
     30     gen_server:call(?SERVER, destroy_ring).
     31 
     32 init(State) ->
     33     process_flag(trap_exit, true),
     34     {ok, State}.
     35 
     36 handle_call(Request, From, State) ->
     37     case Request of
     38         {create_ring, N} ->
     39             create_ring_impl(1, undefined, N);
     40         {transmit_msg, Message, M} ->
     41             transmit_msg_impl(Message, M * State#server_state.process_counter);
     42         destroy_ring ->
     43             header ! {quit, State#server_state.process_counter};
     44         _ -> ok
     45     end,
     46     {reply, From, State}.
     47 
     48 %% 创建环的算法实现 Id:新节点进程的标识,Pre:上一个进程的Pid,
     49 %% Max:环中节点的数量
     50 
     51 %% 创建头节点
     52 create_ring_impl(1, undefined, Max) ->
     53     Pid = spawn_link(?MODULE, ring_item_init, [#state{id=1}]),
     54     register(header, Pid),
     55     create_ring_impl(2, Pid, Max);
     56 %% 创建尾节点
     57 create_ring_impl(Id, Pre, Id) ->
     58     Pid = spawn_link(?MODULE, ring_item_init, [#state{id=Id}]),
     59     Pre ! {next, Pid},
     60     Pid ! {next, header};
     61 %% 创建中间节点
     62 create_ring_impl(Id, Pre, Max) ->
     63     Pid = spawn_link(?MODULE, ring_item_init, [#state{id=Id}]),
     64     Pre ! {next, Pid},
     65     create_ring_impl(Id+1, Pid, Max).
     66 
     67 transmit_msg_impl(Message, MsgTransmitCounter) ->
     68     header ! {msg, Message, MsgTransmitCounter},
     69     receive
     70         complete -> io:format("circle complete~n");
     71         _ -> ok
     72     end.
     73 
     74 %% 节点进程的初始化函数    
     75 ring_item_init(#state{id=Id}=State) ->
     76     io:format("process ~p is created~n", [Id]),
     77     loop(State),
     78     ok.
     79 
     80 %% 节点进程的循环处理函数
     81 loop(#state{id=Id}=State) ->
     82     receive
     83         {next, Next} ->        % 设置当前节点进程链接的下一节点 
     84             io:format("process ~p pid=~p , next is ~p~n", [Id, self(), Next]),
     85             loop(State#state{next=Next});
     86         {msg, Message, MsgTransmitCounter} ->     % 向下一节点传递消息
     87             io:format("process ~p receive ~p, MsgTransmitCounter:~p~n", [Id, Message, MsgTransmitCounter]),
     88             case MsgTransmitCounter-1 =:= 0 of
     89                 true -> 
     90                     ?SERVER ! complete,
     91                     loop(State);
     92                 false ->
     93                     State#state.next ! {msg, Message, MsgTransmitCounter-1},
     94                     loop(State)
     95             end;
     96         {quit, MsgTransmitCounter} ->        % 当前节点进程退出并向下一节点发送退出消息
     97             io:format("~p exit~n", [State#state.id]),
     98             case MsgTransmitCounter-1 =:= 0 of
     99                 true -> exit(normal);
    100                 false ->
    101                     State#state.next ! {quit, MsgTransmitCounter-1},
    102                     exit(normal)
    103             end
    104     end.
    105     
    106 handle_cast(Request, State) ->
    107     {noreply, State}.
    108 
    109 handle_info(Info, State) ->
    110     {noreply, State}.
    111 
    112 terminate(Reason, State) ->
    113     ok.
    114 
    115 code_change(OldVsn, State, Extra) ->
    116     {ok, State}.

    编程注意事项:进程名可注册为原子,其它进程可向该原子发送信息,但如果进程退出,向原子发送信息会弹出bagarg的exit错误

    上善若水
  • 相关阅读:
    RHEL5.8配置开机自动挂载磁盘
    RHEL5.8配置NFS服务
    Linux环境下Oracle数据库启动停止命令
    使用的组件:Layui
    使用的组件:Jcrop
    使用的组件:ckeditor
    使用的组件:Web Uploader
    WebSphere试用过期问题处理
    webpack学习笔记(一)
    如何用node命令和webpack命令传递参数 转载
  • 原文地址:https://www.cnblogs.com/netbuddy/p/2817762.html
Copyright © 2020-2023  润新知