如您所知,在 erlang 中实现流程有一个通用模式:
loop( State ) ->
receive
Message ->
NewState = process( Message, State ),
loop( NewState )
end.
在每个 quant 时间过程中都有一个State
. 因此,如果您想从当前“分叉”某些流程 - 您必须为其传递特定消息。进程必须识别该消息并在生成的进程中使用其当前状态的副本生成新进程。
我创建了示例,以说明上面的文字:
-module( test ).
-export( [ fork/1, get_state/1, change_state/2 ] ).
-export( [ loop/1 ] ).
loop( State ) ->
receive
{ fork, Sender } ->
%%
%% if you want to link with child process
%% call spawn_link instead of spawn
%%
ClonePid = spawn( ?MODULE, loop, [ State ] ),
responseTo( Sender, ClonePid ),
loop( State );
{ get_state, Sender } ->
responseTo( Sender, { curr_state, State } ),
loop( State );
{ change_state, Data, Sender } ->
{ Response, NewState } = processData( Data, State ),
responseTo( Sender, Response ),
loop( NewState )
end.
fork( Pid ) ->
Ref = make_ref(),
Pid ! { fork, { Ref, self() } },
get_response( Ref ).
get_state( Pid ) ->
Ref = make_ref(),
Pid ! { get_state, { Ref, self() } },
get_response( Ref ).
change_state( Pid, Data ) ->
Ref = make_ref(),
Pid ! { change_state, Data, { Ref, self() } },
get_response( Ref ).
get_response( Ref ) ->
receive
{ Ref, Message } -> Message
end.
responseTo( { Ref, Pid }, Mes ) ->
Pid ! { Ref, Mes }.
processData( Data, State ) ->
%%
%% here comes logic of processing data
%% and changing process state
%%
NewState = Data,
Response = { { old_state, State }, { new_state, NewState } },
{ Response, NewState }.
让我们在 erlang shell 中测试它:
1> c(test).
{ok,test}
创建具有初始状态的父进程first_state
2> ParentPid = spawn( test, loop, [ first_state ] ).
<0.38.0>
3> test:get_state( ParentPid ).
{curr_state,first_state}
4>
让我们将父进程的状态更改为second_state
:
4> test:change_state( ParentPid, second_state ).
{{old_state,first_state},{new_state,second_state}}
从父进程分叉新进程:
5> ChildPid = test:fork( ParentPid ).
<0.42.0>
检查分叉进程的状态(与父进程相同):
6> test:get_state( ChildPid ).
{curr_state,second_state}