代码如下所示
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错误