如何在Erlang中分叉/克隆进程

时间:2012-09-06 14:42:05

标签: process erlang fork

如何在Erlang中分叉/克隆进程,如Unix中的fork

我经常搜索但却一无所获。

也许用法如下:

case fork() of
  {parent, Pid} ->
    in_parent_process_now();
  {child, Pid} ->
    in_child_process_now();
  {error, Msg} ->
    report_fork_error(Msg)
end.

有什么想法吗?

编辑:

为了更好地解释我的观点,请以下面的C代码为例:

f();
fork();
g();

此处忽略fork()的返回值,因此父进程和子进程的后续步骤相同,即执行g()

我能在Erlang中实现吗?

3 个答案:

答案 0 :(得分:4)

(这个问题是also answered in the erlang-questions mailing list。)

Erlang没有'fork'操作。它有一个spawn操作:

parent_process() ->
  will_be_executed_by_parent_process(),
  spawn(fun() -> will_be_executed_by_child_process() end),
  will_also_be_executed_by_parent_process().

...函数名称显示在什么上下文中它们将被执行。请注意,传递给子进程的任何数据都将复制到新进程的堆中。

答案 1 :(得分:1)

Erlang中没有fork。但是你可以使用spawn / 1,spawn / 2,spawn / 3,spawn / 4(参见spawn_link)中的一个作为erlang see erlang module的BIF。

所以,例如:

-module(mymodule).
-export([parent_fun/0]).

parent_fun() ->
    io:format("this is the parent with pid: ~p~n", [self()]),
    spawn(fun() -> child_fun() end),
    io:format("still in parent process: ~p~n", [self()]).

child_fun() ->
    io:format("this is child process with pid: ~p~n", [self()]).

在erlang shell中执行:

mymodule:parent_fun().

请注意,父进程和子进程具有不同的pid。

我强烈建议您阅读:http://learnyousomeerlang.com/the-hitchhikers-guide-to-concurrency

答案 2 :(得分:1)

如您所知,在erlang中实现进程有通用模式:

loop( State ) ->
   receive
      Message ->
         NewState = process( Message, State ),
         loop( NewState )
   end.

在每个时间量程中,过程都有一个State。所以,如果你想要" fork"从当前的一些过程 - 你必须传递特定的消息。进程必须识别该消息并在生成的进程中生成具有其当前状态副本的新进程。

我已创建示例,以说明上述文字:

-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}