运行此模块时:
-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],[]}]}
之前提到的错误。
答案 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。这将从您第一次运行程序时终止剩余的进程。
试试这个:
simulate()
。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&#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"),
输入的痛苦就少了。