在Erlang模块

时间:2017-05-10 13:15:57

标签: erlang

运行此模块时:

-module(cbbs).

-export([ahu/0, duct/1, simulate/0, room1/1, vent1/0]).

duct(P) ->
      if
      P>=250 ->
        apid ! full,
        io:format("Full Pressure~n", []),
        receive
            gia ->
            vent1 ! {gia, self()},
            io:format("Feeding Vent1~n", []),
        duct(P-2)
        end;

      true ->
        apid ! {pressurise, self()},
        receive
            pressurise ->
                io:format("Receiving Pressure~n", []),
                duct(P + 1);
            gia ->
                vent1 ! gia,
                io:format("Feeding Vent1~n", []),
                duct(P - 1)
        end
    end.


ahu() ->
    receive
        full ->
            io:format("Stopped~n", []);
        {pressurise, duct} ->
            io:format("Pressurising~n", []),
                duct ! pressurise,
            ahu()       
    end.


vent1() ->
    receive
        {toohot, room1} ->
            io:format("Open~n", []),
            duct ! gia;

        {roomtemp, room1} ->
            io:format("Closed~n", []);

        {gia, duct} ->
            io:format("Feeding Room1~n", []),
            room1 ! ga,
            vent1()
        end.

room1(T) ->
     if
     T >= 20 ->
           vent1 ! {toohot, self()},
           io:format("R1 Too Hot~n", []),
           receive
            ga ->
            io:format("Cooling R1~n", []),
            room1(T-1)
        end;

     true ->
        vent1 ! {roomtemp, self()},
        io:format("Room Temperature~n", []),
        room1(T+1)

    end.

simulate() ->
        register(apid, spawn(cbbs, ahu, [])),
        register(vent1, spawn(cbbs, vent1, [])),
        register(duct, spawn(cbbs, duct,[0])),
        register(room1, spawn(ccbs, room1, [20])).

我收到此错误:

cbbs:simulate().
** exception error: bad argument
     in function  register/2
        called as register(apid,<0.292.0>)
     in call from cbbs:simulate/0 (cbbs.erl, line 76)

我似乎无法进一步理解它对我的要求。这是为了模拟并发的建筑服务,并使其在通信方面有些复杂。但是,我无法找出问题所在,因此无法继续发现其他问题!

非常感谢任何帮助!

编辑:

我从第一次运行中得到以下信息:

=ERROR REPORT==== 10-May-2017::15:36:54 ===
Error in process <0.69.0> with exit value:
{undef,[{ccbs,room1,[20],[]}]}

之前提到的错误。

2 个答案:

答案 0 :(得分:1)

如果名称已经占用,或者在您有时间注册之前进程已经死亡,则注册调用可能会失败。您可以使用whereis(ProcessName)检查第一个案例,使用erlang检查第二个案例:is_process_alive(Pid)。

答案 1 :(得分:1)

您在cbbs的最后一行错误地拼写了模块名称simulate()

   register(room1, spawn(ccbs, room1, [20])).

第一次运行程序时,您将收到该行的错误。第二次运行程序时,simulate()的第一行会出现错误:

register(apid, spawn(cbbs, ahu, [])),

这是因为第一次运行程序时,您注册的进程陷入了无限循环,所以它们在程序结束后永远存在于shell中。因此,当您第二次运行simulate()时,您尝试注册的名称将已经是正在运行的进程的名称(重新编译不会有帮助)。由于程序中存在问题,为了再次运行程序,您需要终止erlang shell并启动一个新的erlang shell。这将从您第一次运行程序时终止剩余的进程。

试试这个:

  1. 更正拼写错误。
  2. 启动一个新的erlang shell。
  3. 运行simulate()
  4. 使用shell中的i()命令检查当前正在运行的进程。
  5. 以下是一个例子:

    $ erl
    Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
    
    -----Now, do some Erlang for great Good!------
    
    Eshell V8.2  (abort with ^G)
    
    1> c(cbbs).
    {ok,cbbs}
    
    2> cbbs:simulate().
    R1 Too Hot
    ok
    
    3> i().
    Pid                   Initial Call                          Heap     Reds Msgs
    Registered            Current Function                     Stack              
    <0.0.0>               otp_ring0:start/2                      233      606    0
    init                  init:loop/1                              2              
    <0.1.0>               erts_code_purger:start/0               233        8    0
    erts_code_purger      erts_code_purger:loop/0                  3              
    <0.4.0>               erlang:apply/2                        4185   596196    0
    erl_prim_loader       erl_prim_loader:loop/3                   5              
    <0.30.0>              gen_event:init_it/6                    610      226    0
    error_logger          gen_event:fetch_msg/5                    8              
    <0.31.0>              erlang:apply/2                        1598      416    0
    application_controlle gen_server:loop/6                        7              
    <0.33.0>              application_master:init/4              233       64    0
                          application_master:main_loop/2           6              
    <0.34.0>              application_master:start_it/4          233       59    0
                          application_master:loop_it/4             5              
    <0.35.0>              supervisor:kernel/1                    610     1700    0
    kernel_sup            gen_server:loop/6                        9              
    <0.36.0>              erlang:apply/2                       10958   130910    0
    code_server           code_server:loop/1                       3              
    <0.38.0>              rpc:init/1                             233       21    0
    rex                   gen_server:loop/6                        9              
    <0.39.0>              global:init/1                          233       44    0
    global_name_server    gen_server:loop/6                        9              
    <0.40.0>              erlang:apply/2                         233       21    0
                          global:loop_the_locker/1                 5              
    <0.41.0>              erlang:apply/2                         233        3    0
                          global:loop_the_registrar/0              2              
    <0.42.0>              inet_db:init/1                         233      249    0
    inet_db               gen_server:loop/6                        9              
    <0.43.0>              global_group:init/1                    233       55    0
    global_group          gen_server:loop/6                        9              
    <0.44.0>              file_server:init/1                     376      554    0
    file_server_2         gen_server:loop/6                        9              
    <0.45.0>              supervisor_bridge:standard_error/      233       34    0
    standard_error_sup    gen_server:loop/6                        9              
    <0.46.0>              erlang:apply/2                         233       10    0
    standard_error        standard_error:server_loop/1             2              
    <0.47.0>              supervisor_bridge:user_sup/1           233       53    0
                          gen_server:loop/6                        9              
    <0.48.0>              user_drv:server/2                     1598     3850    0
    user_drv              user_drv:server_loop/6                   9              
    <0.49.0>              group:server/3                         233      210    0
    user                  group:server_loop/3                      4              
    <0.50.0>              group:server/3                         987    13450    0
                          group:server_loop/3                      4              
    <0.51.0>              erlang:apply/2                        4185     9974    0
                          shell:shell_rep/4                       17              
    <0.52.0>              kernel_config:init/1                   233      193    0
                          gen_server:loop/6                        9              
    <0.53.0>              supervisor:kernel/1                    233       56    0
    kernel_safe_sup       gen_server:loop/6                        9              
    <0.57.0>              erlang:apply/2                        1598    20441    0
                          c:pinfo/1                               50              
    <0.64.0>              cbbs:ahu/0                             233        2    1
    apid                  cbbs:ahu/0                               1              
    <0.65.0>              cbbs:vent1/0                           233        2    1
    vent1                 cbbs:vent1/0                             1              
    <0.66.0>              cbbs:duct/1                            233        2    0
    duct                  cbbs:duct/1                              2              
    <0.67.0>              cbbs:room1/1                           233       15    0
    room1                 cbbs:room1/1                             2              
    Total                                                      31365   779424    2
                                                                 228              
    ok
    4> 
    

    i()输出中,第一列的标题为:

    Pid
    Registered
    

    该列列出了当前在shell中运行的进程的所有进程标识符(Pid&#39;)以及Pid下的进程的注册名称 - 如果进程已注册。您可以看到已注册的进程列在第一列的底部。您的程序已终止,但这些进程仍在shell中运行。

    i()输出中,第二列的标题是:

    Initial Call
    Current Function
    

    Initial Call是您调用以启动该过程的函数,例如spawn(ccbs, room1, [20]),其下面是当前正在该进程中执行的函数。例如,如果room1()调用辅助函数来进行循环,比如说loop(),那么在第二列中你会看到:

    cbbs:room1/1
    cbbs:loop/1
    

    你的进程陷入无限循环的原因是你的receive子句中的模式有问题。例如,当您在此处发送消息时:

    room1(T) ->
         if
         T >= 20 ->
               vent1 ! {toohot, self()},
    

    self()不会返回room1,所以在这里的receive子句中:

    vent1() ->
        receive
            {toohot, room1} ->
                io:format("Open~n", []),
                duct ! gia;
    

    模式{toohot, room1}room1()发送的邮件不匹配。 self()实际上返回了一个Pid - 而不是一个注册名称。转换为输出字符串的Pid看起来像:<0.66.0>(但要记住Pid不是字符串,因此您无法在代码中为Pid写"<0.66.0>" )。

    您需要更改receive子句中的模式。您可以将模式更改为:

    vent1() ->
        receive
            {toohot, _From} ->  #<*** HERE
                io:format("Open~n", []),
                duct ! gia;
    

    该接收模式将匹配其第二项为任何的元组。或者,您可以将接收模式更改为:

    vent1() ->
        Room1 = whereis(room1),  #<***HERE
        receive
            {toohot, Room1} ->   #<***AND HERE
                io:format("Open~n", []),
                duct ! gia;
    

    whereis()返回已注册名称的Pid。在这种情况下,接收模式只匹配第二个元素是room1进程的Pid的元组。

    此外,if-statements在erlang中不受欢迎。查看room1()的以下备选方案:

    room1(T) when T >= 20 ->
        vent1 ! {toohot, self()},
        io:format("R1 Too Hot~n", []),
        receive
            ga ->
                io:format("Cooling R1~n", []),
                room1(T-1)
        end;
    room1(T) ->
        vent1 ! {roomtemp, self()},
        io:format("Room Temperature~n", []),
        room1(T+1).
    

    函数子句按照在代码中写入的顺序进行匹配。因此,当您调用room1()时,首先erlang将尝试匹配函数子句:

    room1(T) when T >= 20 ->
    

    如果T小于20,则该函数子句不匹配,因此erlang将继续执行下一个函数子句:

    room1(T) ->
    

    该函数子句将匹配任何单个参数,因此它将执行。请注意,分号分隔函数子句而不是句点。如果您不小心使用了句号,则会收到错误:

      

    功能室1/1已定义

    如果您首先编写if-statement感觉很自然,那么请继续执行此操作......但请立即将if-statement转换为一系列function clauses。在您进行一段时间的转换之后,我认为您的思维会适应function clauses而非if-statements的思考。

    另外,我发现你做的事与以往一样:

    io:format("R1 Too Hot~n", []),
    

    io:format()还有一个参数形式,所以你可以写:

    io:format("R1 Too Hot~n"),
    

    输入的痛苦就少了。