Erlang Code理解

时间:2014-12-28 21:18:49

标签: erlang concurrent-programming

您好我正在通过了解一些基本的Erlang服务器模块来进行一些Erlang培训。但是我被困在这一个。在这个模块中,我应该告诉3个进程(父进程和2个进程)中每个进程可以打印的最低和最高可能值,因为根据特定的执行顺序,3个进程可以打印不同的值。 / p>

我执行了测试并为父级获得了2,为两个子进程获得了3,但我不知道他们是如何获得这些值的。有人可以专门向我解释这个过程吗?赞赏。

这是模块:

-module(p4).
-export([start/0, init/0, read/1, incr/1, reset/1, test/0]).

start()->
    spawn(fun() -> init() end).
init() -> loop(0).

loop(N) ->
    receive
   {read, Pid} ->
	    Pid ! {value, self(), N},
	    loop(N);
	{incr, Pid} ->
            Pid ! {incr_reply, self()},
	    loop(N+1);
	{reset, Pid} ->
            Pid ! {reset_reply, self()},    
	    loop(0)
   end.

read(Serv) ->
    Serv ! {read, self()},
    receive {value, Serv, N} -> N end.

incr(Serv)->
    Serv ! {incr, self()},
    receive{incr_reply, Serv} -> ok end.

reset(Serv) ->
    Serv ! {reset, self()},
    receive {reset_reply, Serv} -> ok end.
	    
test() -> 	  
    Server = start(),
    spawn(fun() -> incr(Server),
		   io:format("Child 1 read ~p~n", [read(Server)]) end),
    incr(Server),
    spawn(fun() -> incr(Server),
	           io:format("child 2 read ~p~n", [read(Server)]) end),
    io:format("Parent read ~p~n", [read(Server)]).
		  

2 个答案:

答案 0 :(得分:2)

理解Lukasz答案的一个精度是所有服务器接口(读取,加载,重置)都是同步的:它们等待来自服务器的答案。这意味着在服务器完成请求之前,使用这些接口的进程无法执行任何操作。认为child2读数不能低于2是非常重要的。

2个序列图,用于可视化过程:

enter image description here

enter image description here

答案 1 :(得分:1)

尝试打印正在接收的任何消息服务器(或使用调试器跟踪)以便更好地理解,您应该得到类似的内容:

Server state was: 0 and received: {incr,<0.59.0>}
Server state was: 1 and received: {incr,<0.109.0>}
Server state was: 2 and received: {read,<0.59.0>}
Server state was: 2 and received: {incr,<0.110.0>}
Parent read 2
Server state was: 3 and received: {read,<0.109.0>}
Server state was: 3 and received: {read,<0.110.0>}
Child 1 read 3
child 2 read 3

<0.59.0>是父流程,<0.109.0>是子1,<0.110.0>是子2。

这意味着在read子进程之前,但在第一个子read之后传递了父incr条消息。但它不一定是这样的。这取决于进程安排。您唯一的保证是从进程A发送到进程B的消息将以相同的顺序传递。 由于incr(Server)read(Server)的同步特性,它并不重要。因为每个进程在incr(Server)之前运行read(Server)它必须至少得到1但是请注意,在父执行incr(Server)之后生成了子2,这是同步操作所以它必须至少为1时它运行自己的incr(Server),所以当它读取时它必须至少为2.每个值的最大值为3(incr(Server)的总数,表示每个read(Server)他们可能会被推迟)。

可能的印刷值摘要:父母:1,2,3;孩子1:1,2,3;孩子2:2,3

简化执行顺序:

你的情况(父母得到2,两个孩子都得3):

parent: spawn server
parent: spawn child 1
parent: incr(Server)
child 1: incr(Server)
parent: spawn child 2
parent: io:format("parent read ~p~n",[read(Server)]) % prints 2
child 2: incr(Server)
child 1: parent: io:format("child 1 read ~p~n",[read(Server)]) % prints 3
child 2: parent: io:format("child 2 read ~p~n",[read(Server)]) % prints 3

儿童1的最低限度案例:

parent: spawn server
parent: spawn child 1
child 1: incr(Server)
child 1: io:format("child 1 read ~p~n",[read(Server)]) % prints 1
...

父母的最大案例:

parent: spawn server
parent: spawn child 1
parent: incr(Server)
parent: spawned child 2
child 1: incr(Server)
child 2: incr(Server)
Parent: io:format("child 1 read ~p~n",[read(Server)]) % prints 3
...

我已经创建了大量测试,它产生了100000个同时运行test/0的进程,并创建了外部stat_server,它获取并计算每个进程read(Server) resault,这里是:

[{{child1,1},2}, % child 1 reads 1 only twice. Sometimes it's 1 sometimes it's 0, it varies
 {{child1,2},53629},
 {{child1,3},46369},
 {{child2,2},107},
 {{child2,3},99893},
 {{parent,1},855},
 {{parent,2},99112},
 {{parent,3},33}]