进程环指的是有n个进程,第1个进程往第2个进程发消息,第2个进程往第3个进程发消息,第n个进程往第1个进程发消息,这样就形成了一个环状结构。
在创建第i个进程的时候,需要知道第i+1个进程的Pid,这样进程i才知道把消息发往哪个进程。因此,可以先创建进程n,然后创建进程n-1,直到创建了进程1,把进程1注册为ring。在创建进程n的时候,把当前创建进程的进程Pid传递给进程n,因为进程n要发送消息至进程1,因此创建进程的进程须把进程n发送的消息转发给进程1。
这样,进程环就构成了一个闭路。当往ring发送一个消息时,会在进程间不断地流转,直到客户端停止消息的发送。
把进程环作为一个黑盒,其向外部提供的几个客户函数(Client Functions)为:
- ring:start(N)
-
ring:send_msg(Msg)
-
ring:stop()
start生成N个进程,进行相关初始化,如注册第一个进程为ring等。send_msg往进程环发送数据,然后该数据就会在进程环内部流转。最后,客户可以通过stop函数显式地停止进程。
完成的程序源代码如下:
-module(ring).
-export([start/1, send_msg/1, stop/0]).
-export([send/1, start_help/1, start_loop/0]).
start(N) -> call({start, N}).
send_msg(Msg) -> call({send_msg, Msg}).
stop() -> call(stop).
call({start, N}) ->
spawn(?MODULE, start_help, [N]);
call({send_msg, Msg}) ->
ring ! {ok, Msg};
call(stop) ->
ring ! stop.
start_help(N) ->
register(ring, create_processes(N, self())),
start_loop().
start_loop() ->
receive
{ok, Content} -> ring ! {ok, Content},
start_loop();
stop -> ok
end.
% `创建N,N-1,...,2进程,其中第N个进程指向当前进程Pid`
% `当创建完第1个进程后,就接收消息,并返回该进程的Pid`
create_processes(N, AfterPid) when N > 1->
CurrPid = spawn(?MODULE, send, [AfterPid]),
create_processes(N-1, CurrPid);
create_processes(1, AfterPid) ->
spawn(?MODULE, send, [AfterPid]).
send(Pid) ->
receive
{ok, Content} ->
Pid ! {ok, Content},
io:format("Pid:~p, Msg:~p~n", [self(), Content]),
send(Pid);
stop ->
Pid ! stop
end.
图 1为初始进程,而图 2为调用ring:start(3)之后创建的进程,可以看到最后创建的进程为第1个进程,而且注册成ring。
图 1
图 2
阅读(1922) | 评论(0) | 转发(0) |