在Erlang模块中运行衍生时出错

xmakbtuz  于 2022-12-08  发布在  Erlang
关注(0)|答案(2)|浏览(175)

When running this module:

-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])).

I get this error:

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)

I can't seem to understand any further what it is asking of me. This is meant to simulate a concurrent building services and making this somewhat complicated in terms of communication. I can't however, find out what the problem is here, and therefore can't move on to finding what other problems there are !
Any help would be greatly appreciated !
EDIT:
I get the following from running first time:

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

Followed by the error previously mentioned.

a9wyjsp7

a9wyjsp71#

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

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

第一次运行程序时,会在该行中出现错误。第二次运行程序时,会在simulate()的第一行中出现错误:

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

这是因为在第一次运行程序时,注册的进程会陷入无限循环,因此在程序结束后,它们将永远存在于shell中。(重新编译不会有帮助)。由于程序中的问题,为了第二次运行程序,你需要杀死erlang shell并启动一个新的erlang shell。2这将终止你第一次运行程序时遗留下来的进程。
试试这个:
1.更正拼写错误。
1.启动新的Erlang shell。
1.运行simulate()
1.在shell中使用i()命令检查当前正在运行的进程。
下面是一个例子:

$ 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)以及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;

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

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"),

这对于打字来说不那么痛苦。

2nc8po8w

2nc8po8w2#

如果名称已经忙或者进程在你注册它之前就已经死了,register调用可能会失败。你可以用whereis(ProcessName)检查第一种情况,用erlang:is_process_alive(Pid)检查第二种情况。

相关问题