如何在 erlang 中从多个进程生成或调用进程

  • 本文关键字:进程 调用 erlang erlang
  • 更新时间 :
  • 英文 :


我想从多个函数中生成一个进程并创建一个指向该进程的链接。 如何在系统进程中将接收到的信号转换为消息。我想制作"并行连接"系统进程,在它从其链接进程(任务二、任务三、任务四)收到一条("退出"、pid、正常)消息后,它将生成另一个进程(任务五),但这在我的代码中无法正常工作,即"任务五"没有执行。

-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 business 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 business logic  of task two n"),
link(whereis(join2)),
exit(whereis(join2), normal).
taskThree() ->
io:format(" code for business logic  of task three n"),
link(whereis(join2)),
exit(whereis(join2), normal).
taskFour() ->
io:format(" code for business 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 business logic of task five n").

1)如果代码没有正确缩进,你不能指望任何人查看你的代码。 您的缩进策略是什么? 每行是否缩进了随机数量的空格? 发布代码后,您是否无法查看代码并辨别缩进是一团糟? 如果你不能自己弄清楚如何在计算机编程论坛上发布代码,那么你需要用谷歌做一些研究。 您是否可能没有使用计算机编程编辑器?

2)如果你看一下erlang:process_flag/2的定义,它说:

当trap_exit设置为 true 时,到达进程的退出信号是 转换为{'EXIT', From, Reason}消息,可以接收为 普通消息。如果trap_exit设置为 false,则进程在以下情况下退出 它接收到非正常信号的退出信号,并且退出信号为 传播到其链接的进程。申请流程正常 不要困住出口。

返回标志的旧值。

另请参阅退出/2。

这告诉您,如果一个进程正在捕获出口,则该进程将收到表单{'EXIT', From, Reason}的消息。 但是,它没有定义From是什么类型,也没有定义Reason是什么类型。From是原子吗?文档确实说,"另请参阅退出/2",如果您检查文档中是否有erlang:exit/2,它说:

如果 Pid 正在捕获出口,则退出信号将转换为 消息{'EXIT', From, Reason}并传递到的消息队列 皮德。From是发送出口的进程的进程标识符信号。

这告诉您 From 需要成为 Pid(但您似乎已经知道这一点,因为您在评论中说退出信号将转换为{'EXIT', Pid, Why}形式的消息)。

现在让我们看一下匹配退出消息的模式:

{'EXIT', task2, normal} ->

"EXIT"原子将与退出消息中的位置 1 匹配,但对于From,您指定原子task2。 原子是Pid吗?提示:阅读我之前发布的代码示例中的单独评论。

请注意,您可以使用注册名称(即 atom)发送消息,因为!是 erlang:send/2 的简写,在文档中定义如下:

erlang:send(Dest, Msg) -> Msg

Dest 可以是远程或本地进程标识符[即 Pid],一个 (本地)端口、本地注册名称[即原子] 或元组 {RegName, 节点} 表示另一个节点上的注册名称。

但是,通常不能使用注册名称代替 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

区别在于:使用您的代码,如果指定的消息以外的消息到达,则会发生运行时错误 - 因为当 case 语句不处理所有可能性时就会发生这种情况 - 而在我的示例中,如果指定的消息以外的消息到达,接收将阻塞。 您始终可以通过添加全部捕获来阻止接收:

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.

使用 OTP,主管。

生成一个进程并重新启动工作线程,并将 pid 传递给需要它的其他进程或使用命名进程,这样你就不需要传递 pid。

我试图传递终止进程的 pid,例如 {'EXIT',其中(task2),正常} 但不起作用。

您是否收到illegal pattern错误? 如果是这样,您需要编写:

Task2 = whereis(task2),
receive
{'EXIT', Task2, Why} ->

模式不能包含表达式:

模式匹配

模式 = 表达式

模式由可以包含两个绑定的数据结构组成 和未绑定的变量,以及文字值(例如原子, 整数或字符串)。


表达式由数据结构、绑定变量、数学运算和函数调用组成。它不能包含未绑定的值。

Erlang Programming (Cesarini, Thompson)

我的代码有什么问题

  1. 没有名为model:paralleljoin()的函数。

当我从每个函数生成它时,它会创建 3 个不同的进程

  1. 每次调用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 business 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 business logic  of task two n"),
link(whereis(somename) ).  %% whereis() returns the pid of a registered name