我想从多个函数中生成一个进程,并创建一个指向该进程的链接。如何在系统进程中将接收到的信号转换为消息。我想制作" paralleljoin"系统进程,并从它的链接进程(taskTwo,taskThree,TaskFour)收到('退出',pid,正常)消息后,它将生成另一个进程(taskFive),但这在我的代码中没有正常工作,即" taskFive"没有执行。
-module(model).
-compile(export_all).
start() ->
io:format("codes of start event \n"),
%The spawn method calls the taskOne function with no parameters
spawn(model, taskOne, []),
Pid1 = spawn(model, paralleljoin, []),
register(join2,Pid1 ).
taskOne() ->
io:format(" code for bussiness logic of task one \n"),
spawn(model, parallelsplit, []).
parallelsplit()->
Pid2 = spawn(model, taskTwo, []),
register(task2, Pid2),
Pid3 = spawn(model, taskThree, []),
register(task3, Pid3),
Pid4 = spawn(model, taskFour, []),
register(task4, Pid4).
taskTwo() ->
io:format("code for bussiness logic of task two \n"),
link(whereis(join2)),
exit(whereis(join2), normal).
taskThree() ->
io:format(" code for bussiness logic of task three \n"),
link(whereis(join2)),
exit(whereis(join2), normal).
taskFour() ->
io:format(" code for bussiness logic of task four \n"),
link(whereis(join2)),
exit(whereis(join2), normal).
paralleljoin()->
process_flag(trap_exit, true),
Task2 = whereis(task2),
Task3 = whereis(task3),
Task4 = whereis(task4),
case get(messagesreceived) of
undefined -> put(messagesreceived, {nil, nil, nil});
{Task2, Task3, Task4} ->
spawn(model, taskFive, [])end,
receive
{'EXIT', Task2, normal} ->
put(messagesreceived, setelement(1, get(messagesreceived), Task2));
{'EXIT', Task3, normal}->
put(messagesreceived, setelement(2, get(messagesreceived), Task3));
{'EXIT', Task4, normal}->
put(messagesreceived, setelement(3, get(messagesreceived), Task4));
Other ->
ignore %Do something, or do nothing
end,
paralleljoin().
taskFive()->
io:format("code for bussiness logic of task five \n").
答案 0 :(得分:0)
我的代码出了什么问题
1)没有名为model:paralleljoin()
的函数。
当我从每个函数中生成它时,它会创建3个不同的进程
2)每次调用spawn()
时,erlang都会创建一个新进程。就这么简单。 spawn()不会检查赋值左侧的变量名称,以确定要执行的操作。
如果您希望taskTwo(),taskThree()和taskFour()进程都链接到一个公共进程,那么您需要将公共进程作为参数传递给每个函数,如下所示:
parallelsplit()->
Pid = spawn(model, paralleljoin, []),
spawn(?MODULE, taskTwo, [Pid]),
spawn(?MODULE, taskThree, [Pid]),
spawn(?MODULE, taskFour, [Pid]).
taskTwo(ParallelJoin) ->
io:format("code for bussiness logic of task two \n"),
link(ParallelJoin).
...
...
另一种选择是注册公共进程,它创建类似于可以从任何进程访问的全局变量:
start() ->
io:format("codes of start event \n"),
register(somename, spawn(model, paralleljoin, []) )
spawn(model, taskOne, []).
...
taskTwo() ->
io:format("code for bussiness logic of task two \n"),
link(whereis(somename) ). %% whereis() returns the pid of a registered name
答案 1 :(得分:0)
1)如果代码没有正确缩进,你不能指望任何人查看你的代码。你的缩进策略是什么?每行是否缩进了一个随机数的空格?发布后你是否无法查看代码并发现缩进是一团糟?如果您无法弄清楚如何在计算机编程论坛上发布代码,那么您需要与谷歌进行一些研究。您是否可能没有使用计算机编程编辑器?
2)如果你看一下erlang:process_flag/2
的定义,它会说:
当trap_exit设置为true时,到达进程的退出信号为 转换为
{'EXIT', From, Reason}
消息,可以作为 普通的消息。如果trap_exit设置为false,则进程退出if 它接收正常以外的退出信号,退出信号为 传播到其链接的进程。申请流程通常是 不要陷阱退出。返回标志的旧值。
另见exit / 2。
这告诉您如果进程正在捕获退出,则该进程将接收{'EXIT', From, Reason}
形式的消息。但是,它无法定义From
的类型以及Reason
的类型。 From
是原子吗?文档会说,“另请参阅exit / 2”,如果您查看erlang:exit/2
的文档,则会说:
如果Pid正在捕获退出,则退出信号将转换为a 消息
{'EXIT', From, Reason}
并传递给消息队列 PID。From
是发送退出流程的流程标识符 信号。
这告诉你,From需要成为Pid(但似乎你已经知道了,因为在你的评论中你说退出信号将被转换为{'EXIT', Pid, Why}
形式的消息)。
现在让我们看看你的模式是否匹配退出消息:
{'EXIT', task2, normal} ->
'EXIT'原子将在退出消息中与位置1匹配,但对于From
,您指定原子task2
。原子是Pid吗?提示:阅读我之前发布的代码示例中的单独注释。
请注意,您可以使用注册名称(即原子)发送消息,因为!
是erlang:send / 2的简写,在文档中定义如下:
erlang:send(Dest,Msg) - >消息强>
Dest可以是远程或本地 进程标识符 [即一个Pid],a (本地)端口, 本地注册名称 [即一个原子],或一个元组{RegName, Node}表示另一个节点的注册名称。
但是,通常情况下不能使用注册名称代替Pid。
3)而不是:
receive
MESSAGE->
case MESSAGE of
{'EXIT', task2, normal} ->
put(messagesreceived, setelement(1, get(messagesreceived), taskTwo));
{'EXIT', task3, normal}->
put(messagesreceived, setelement(2, get(messagesreceived), taskThree));
{'EXIT', task4, normal}->
put(messagesreceived, setelement(3, get(messagesreceived), taskFour))
end
end
你可以写:
receive
{'EXIT', task2, normal} ->
put(messagesreceived, setelement(1, get(messagesreceived), taskTwo));
{'EXIT', task3, normal}->
put(messagesreceived, setelement(2, get(messagesreceived), taskThree));
{'EXIT', task4, normal}->
put(messagesreceived, setelement(3, get(messagesreceived), taskFour))
end
不同之处在于:对于您的代码,如果您指定的消息之外的消息到达,则会发生运行时错误 - 因为当案例语句不能处理所有可能性时会发生这种情况 - 而在我的示例中如果指定的消息到达,则接收将阻止。您始终可以通过添加catch all来阻止接收阻止:
receive
{'EXIT', task2, normal} ->
put(messagesreceived, setelement(1, get(messagesreceived), taskTwo));
{'EXIT', task3, normal}->
put(messagesreceived, setelement(2, get(messagesreceived), taskThree));
{'EXIT', task4, normal}->
put(messagesreceived, setelement(3, get(messagesreceived), taskFour));
Other ->
%Do something, or do nothing
end,
%%No matter what message was sent to this process,
%%execution will continue here.
答案 2 :(得分:0)
使用OTP,主管。
让一个进程生成并重新启动worker,并将pid传递给需要它的其他进程或使用命名进程,这样你就不需要传递pid。
答案 3 :(得分:0)
我试图传递已终止进程的pid,如{'EXIT',whereis(task2),normal}但无效。
您收到illegal pattern
错误了吗?如果是这样,你需要写:
Task2 = whereis(task2),
receive
{'EXIT', Task2, Why} ->
模式不能包含表达式:
模式匹配
模式=表达式
模式由可以包含两个绑定的数据结构组成 和未绑定的变量,以及文字值(如原子, 整数或字符串) ...
...
表达式由数据结构,绑定变量,数学运算和函数调用组成。它可能不包含未绑定的值。Erlang编程(Cesarini,Thompson)