在Erlang模块中运行spawns时出错
运行此模块时:在Erlang模块中运行spawns时出错,erlang,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 ! {gi
-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)
cbbs:simulate()。
**异常错误:参数错误
在功能寄存器/2中
称为寄存器(apid)
来自cbbs的呼叫中:模拟/0(cbbs.erl,第76行)
我似乎无法进一步理解它对我的要求。这是为了模拟一个并发的建筑服务,并使其在通信方面有点复杂。然而,我无法找出问题所在,因此无法继续找出其他问题
任何帮助都将不胜感激
编辑:
我从第一次跑步中获得以下信息:
=ERROR REPORT==== 10-May-2017::15:36:54 ===
Error in process <0.69.0> with exit value:
{undef,[{ccbs,room1,[20],[]}]}
=错误报告===2017年5月10日::15:36:54===
使用退出值处理时出错:
{undef,[{ccbs,第1房间,[20],]}
然后是前面提到的错误。如果名称已忙,或者进程在您有时间注册之前已停止,则注册调用可能会失败。您可以使用where is(ProcessName)检查第一个案例,使用erlang:is_process_alive(Pid)检查第二个案例。您在
simulate()
中的最后一行拼写了模块名cbbs
:
第一次运行程序时,该行将出现错误。第二次运行程序时,simulate()
的第一行将出现错误:
这是因为当你第一次运行你的程序时,你注册的进程会陷入无限循环中,所以在你的程序结束后,它们会永远存在于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>
该列列出了shell中当前运行的进程的所有进程标识符(Pid),以及Pid下的进程注册名称(如果进程已注册)。您可以看到您注册的进程列在第一列的底部。您的程序已终止,但这些进程仍在shell中运行
在i()
输出中,第二列的标题为:
Pid
Registered
Initial Call
Current Function
Initial Call
是您为启动流程而调用的函数,例如spawn(ccbs,room1,[20])
,下面是该流程中当前正在执行的函数。例如,如果room1()
cbbs:room1/1
cbbs:loop/1
进程陷入无限循环的原因是接收子句中的模式有缺陷。例如,当您在此处发送消息时:
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不是字符串,因此不能在Pid的代码中写入“”
)
您需要更改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;
函数子句按照它们在代码中的写入顺序进行匹配。因此,当您调用room1()
时,第一个erlang将尝试匹配function子句:
room1(T) when T >= 20 ->
room1(T) ->
如果T
小于20,则该函数子句将不匹配,因此erlang将继续执行下一个函数子句:
room1(T) when T >= 20 ->
room1(T) ->
该function子句将匹配任何单个参数,因此它将执行。请注意,分号分隔函数子句而不是句点。如果意外使用句点,则会出现以下错误:
功能室1/1已定义
如果您觉得首先编写一个If语句
是很自然的,那么就继续这样做吧……但要立即将If语句
转换为一系列函数子句
。在你做了一段时间的转换之后,我认为你的思维将适应于从函数子句
而不是if语句
的角度来思考
还有,我看到你在做我以前做过的事情:
io:format("R1 Too Hot~n", []),
还有一个额外的单参数形式io:format()
,因此您只需编写:
io:format("R1 Too Hot~n"),
输入起来不那么痛苦。看起来在该行执行之前,另一个进程已经注册为apid
。感谢您的回复!这很奇怪,因为当我模拟时它返回true,然后打印以下内容:=错误报告====2017年5月10日::15:36:54===进程中的错误,退出值:{unde,[{ccbs,room1,[20],]}}如果我再次模拟,它会给我前面提到的错误,进程应该自行注册(因为它知道它没有死…),你应该使用?模块宏。初学者应该始终使用?模块宏;它可以防止拼写错误。非常感谢你@7stud!!!绝对令人惊讶的答案。现在就尝试让它工作:)@GabrielSeite,如果你遇到更多问题,发表一篇针对我的评论,我会再看看你的节目。祝你好运@7stud感谢您的帮助,我已设法使系统与3个通风口和3个房间同时运行。如果您想要解决方案,请告诉我,我很乐意按您的方式发送!
io:format("R1 Too Hot~n"),