Если вы спрашиваете:
Если я создаю два процесса, которые выполняют одну и ту же функцию в модуле,
и первый процесс умирает, второй процесс тоже умирает?
Попробуйте это:
-module(my).
-compile(export_all).
get_divisor(X, Id) when is_integer(X) ->
Result = 10/X,
io:format("Process ~w: 10/~w = ~w~n", [Id, X, Result]),
timer:sleep(1000),
get_divisor(X-1, Id).
test() ->
Pid1 = spawn(my, get_divisor, [10, harry]),
Pid2 = spawn(my, get_divisor, [20, sally]),
io:format("harry's pid = ~w~nsally's pid = ~w~n", [Pid1, Pid2]).
В оболочке:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
harry's pid = <0.71.0>
sally's pid = <0.72.0>
Process harry: 10/10 = 1.0
Process sally: 10/20 = 0.5
ok
Process harry: 10/9 = 1.1111111111111112
Process sally: 10/19 = 0.5263157894736842
Process harry: 10/8 = 1.25
Process sally: 10/18 = 0.5555555555555556
После запуска вывода быстро введите i() command
(информация) в оболочке:
3> i().
Pid Initial Call Heap Reds Msgs
Registered Current Function Stack
<0.0.0> otp_ring0:start/2 376 990 0
init init:loop/1 2
<0.1.0> erts_code_purger:start/0 233 11 0
erts_code_purger erts_code_purger:wait_for_request 0
<0.2.0> erts_literal_area_collector:start 233 3 0
erts_literal_area_collector:msg_l 5
<0.3.0> erts_dirty_process_code_checker:s 233 3 0
erts_dirty_process_code_checker:m 1
<0.6.0> erlang:apply/2 6772 713103 0
erl_prim_loader erl_prim_loader:loop/3 5
<0.32.0> gen_event:init_it/6 987 414 0
error_logger gen_event:fetch_msg/6 10
<0.33.0> erlang:apply/2 1598 954 0
application_controlle gen_server:loop/7 7
<0.35.0> application_master:init/4 233 69 0
application_master:main_loop/2 7
<0.36.0> application_master:start_it/4 233 90 0
application_master:loop_it/4 5
<0.37.0> supervisor:kernel/1 987 2202 0
kernel_sup gen_server:loop/7 10
<0.38.0> erlang:apply/2 6772 142009 0
code_server code_server:loop/1 3
<0.40.0> rpc:init/1 233 32 0
rex gen_server:loop/7 10
<0.41.0> global:init/1 233 63 0
global_name_server gen_server:loop/7 10
<0.42.0> erlang:apply/2 233 25 0
global:loop_the_locker/1 5
<0.43.0> erlang:apply/2 233 3 0
global:loop_the_registrar/0 2
<0.44.0> inet_db:init/1 233 350 0
inet_db gen_server:loop/7 10
<0.45.0> global_group:init/1 233 74 0
global_group gen_server:loop/7 10
<0.46.0> file_server:init/1 1598 3436 0
file_server_2 gen_server:loop/7 10
<0.47.0> gen_event:init_it/6 233 51 0
erl_signal_server gen_event:fetch_msg/6 10
<0.48.0> supervisor_bridge:standard_error/ 233 50 0
standard_error_sup gen_server:loop/7 10
<0.49.0> erlang:apply/2 233 11 0
standard_error standard_error:server_loop/1 2
<0.50.0> supervisor_bridge:user_sup/1 233 72 0
gen_server:loop/7 10
<0.51.0> user_drv:server/2 1598 7176 0
user_drv user_drv:server_loop/6 9
<0.52.0> group:server/3 233 88 0
user group:server_loop/3 4
<0.53.0> group:server/3 196650 89053 0
group:server_loop/3 4
<0.54.0> kernel_config:init/1 233 48 0
gen_server:loop/7 10
<0.55.0> supervisor:kernel/1 376 282 0
kernel_safe_sup gen_server:loop/7 10
<0.59.0> supervisor:disk_log_sup/1 233 147 0
disk_log_sup gen_server:loop/7 10
<0.60.0> disk_log_server:init/1 610 91 0
disk_log_server gen_server:loop/7 10
<0.61.0> disk_log:init/2 6772 36424 0
disk_log:loop/1 5
<0.63.0> erlang:apply/2 17731 4082 0
shell:shell_rep/4 17
<0.64.0> erlang:apply/2 318187 45309 0
c:pinfo/1 50
<0.71.0> my:get_divisor/2 233 59 0
timer:sleep/1 5
<0.72.0> my:get_divisor/2 233 59 0
timer:sleep/1 5
Total 565674 1046833 0
283
ok
В нижней части вывода выше вы можете видеть, что my:get_divisor/2
работает как в процессе <0.71.0>
, так и в процессе <0.72.0>
. И, если вы посмотрите на вывод для строки iex 2>
, вы увидите:
2> my:test().
harry's pid = <0.71.0>
sally's pid = <0.72.0>
, который подтверждает, что это процессы, которые породила функция test()
.
Вывод двух порожденных процессов продолжается:
Process harry: 10/7 = 1.4285714285714286
Process sally: 10/17 = 0.5882352941176471
Process harry: 10/6 = 1.6666666666666667
Process sally: 10/16 = 0.625
Process harry: 10/5 = 2.0
Process sally: 10/15 = 0.6666666666666666
Process harry: 10/4 = 2.5
Process sally: 10/14 = 0.7142857142857143
Process harry: 10/3 = 3.3333333333333335
Process sally: 10/13 = 0.7692307692307693
Process harry: 10/2 = 5.0
Process sally: 10/12 = 0.8333333333333334
Process harry: 10/1 = 10.0
Process sally: 10/11 = 0.9090909090909091
Process sally: 10/10 = 1.0
4>
=ERROR REPORT==== 10-May-2019::20:40:51 ===
Error in process <0.71.0> with exit value:
{badarith,[{my,get_divisor,2,[{file,"my.erl"},{line,5}]}]}
Последняя строка говорит, что у процесса <0.71.0>
, то есть у процесса harry
, произошла ошибка, но вывод Салли продолжается:
Process sally: 10/9 = 1.1111111111111112
Process sally: 10/8 = 1.25
Process sally: 10/7 = 1.4285714285714286
Process sally: 10/6 = 1.6666666666666667
Process sally: 10/5 = 2.0
Process sally: 10/4 = 2.5
Process sally: 10/3 = 3.3333333333333335
Process sally: 10/2 = 5.0
Process sally: 10/1 = 10.0
4>
=ERROR REPORT==== 10-May-2019::20:41:01 ===
Error in process <0.72.0> with exit value:
{badarith,[{my,get_divisor,2,[{file,"my.erl"},{line,5}]}]}
Последняя строка выше показывает, что теперь процесс <0.72.0>
, то есть процесс sally
, имел ошибку.
Если вы снова используете i() command
, вы увидите, что ни один из процессов <0.71.0>
и <0.72.0>
больше не работает.
i().
Pid Initial Call Heap Reds Msgs
Registered Current Function Stack
<0.0.0> otp_ring0:start/2 376 990 0
init init:loop/1 2
<0.1.0> erts_code_purger:start/0 233 11 0
erts_code_purger erts_code_purger:wait_for_request 0
<0.2.0> erts_literal_area_collector:start 233 3 0
erts_literal_area_collector:msg_l 5
<0.3.0> erts_dirty_process_code_checker:s 233 3 0
erts_dirty_process_code_checker:m 1
<0.6.0> erlang:apply/2 6772 714364 0
erl_prim_loader erl_prim_loader:loop/3 5
<0.32.0> gen_event:init_it/6 2586 3251 0
error_logger gen_event:fetch_msg/6 10
<0.33.0> erlang:apply/2 1598 954 0
application_controlle gen_server:loop/7 7
<0.35.0> application_master:init/4 233 69 0
application_master:main_loop/2 7
<0.36.0> application_master:start_it/4 233 90 0
application_master:loop_it/4 5
<0.37.0> supervisor:kernel/1 987 2202 0
kernel_sup gen_server:loop/7 10
<0.38.0> erlang:apply/2 6772 142119 0
code_server code_server:loop/1 3
<0.40.0> rpc:init/1 233 32 0
rex gen_server:loop/7 10
<0.41.0> global:init/1 233 63 0
global_name_server gen_server:loop/7 10
<0.42.0> erlang:apply/2 233 25 0
global:loop_the_locker/1 5
<0.43.0> erlang:apply/2 233 3 0
global:loop_the_registrar/0 2
<0.44.0> inet_db:init/1 233 350 0
inet_db gen_server:loop/7 10
<0.45.0> global_group:init/1 233 74 0
global_group gen_server:loop/7 10
<0.46.0> file_server:init/1 1598 3436 0
file_server_2 gen_server:loop/7 10
<0.47.0> gen_event:init_it/6 233 51 0
erl_signal_server gen_event:fetch_msg/6 10
<0.48.0> supervisor_bridge:standard_error/ 233 50 0
standard_error_sup gen_server:loop/7 10
<0.49.0> erlang:apply/2 233 11 0
standard_error standard_error:server_loop/1 2
<0.50.0> supervisor_bridge:user_sup/1 233 72 0
gen_server:loop/7 10
<0.51.0> user_drv:server/2 987 19868 0
user_drv user_drv:server_loop/6 9
<0.52.0> group:server/3 233 114 0
user group:server_loop/3 4
<0.53.0> group:server/3 196650 153779 0
group:server_loop/3 4
<0.54.0> kernel_config:init/1 233 48 0
gen_server:loop/7 10
<0.55.0> supervisor:kernel/1 376 282 0
kernel_safe_sup gen_server:loop/7 10
<0.59.0> supervisor:disk_log_sup/1 233 147 0
disk_log_sup gen_server:loop/7 10
<0.60.0> disk_log_server:init/1 610 91 0
disk_log_server gen_server:loop/7 10
<0.61.0> disk_log:init/2 6772 36600 0
disk_log:loop/1 5
<0.63.0> erlang:apply/2 17731 4277 0
shell:shell_rep/4 17
<0.64.0> erlang:apply/2 318187 81397 0
c:pinfo/1 50
Total 566196 1164826 0
273
ok
5>
Erlang также позволяет link
процессу перейти к другому процессу, что приведет к смерти обоих процессов в случае смерти одного из процессов:
-module(my).
-compile(export_all).
get_divisor(X, Id) when is_integer(X) ->
Result = 10/X,
io:format("Process ~w: 10/~w = ~w~n", [Id, X, Result]),
timer:sleep(1000),
get_divisor(X-1, Id).
test() ->
Pid1 = spawn_link(my, get_divisor, [10, harry]),
Pid2 = spawn_link(my, get_divisor, [20, sally]),
io:format("shell pid = ~w~n", [self()]),
io:format("harry's pid = ~w~nsally's pid = ~w~n", [Pid1, Pid2]).
"spawn_link ()" можно читать как "spawn_and_link ()". В test()
оба процесса будут связаны с процессом оболочки (потому что я вызову test()
в оболочке, а процесс, вызывающий spawn_link()
, является другой стороной ссылки). Затем, если Pid1 умирает, Pid1 заставит процесс оболочки умереть, и поскольку процесс оболочки связан с Pid2, это означает, что Pid2 также умрет. Кстати, когда процесс оболочки умирает, автоматически запускается другой процесс оболочки (с другим pid).
В оболочке:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.3 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:test().
shell pid = <0.64.0>
Process harry: 10/10 = 1.0
Process sally: 10/20 = 0.5
harry's pid = <0.71.0>
sally's pid = <0.72.0>
ok
Process harry: 10/9 = 1.1111111111111112
Process sally: 10/19 = 0.5263157894736842
Process harry: 10/8 = 1.25
Process sally: 10/18 = 0.5555555555555556
Process harry: 10/7 = 1.4285714285714286
Process sally: 10/17 = 0.5882352941176471
Process harry: 10/6 = 1.6666666666666667
Process sally: 10/16 = 0.625
Process harry: 10/5 = 2.0
Process sally: 10/15 = 0.6666666666666666
Process harry: 10/4 = 2.5
Process sally: 10/14 = 0.7142857142857143
Process harry: 10/3 = 3.3333333333333335
Process sally: 10/13 = 0.7692307692307693
Process harry: 10/2 = 5.0
Process sally: 10/12 = 0.8333333333333334
Process harry: 10/1 = 10.0
Process sally: 10/11 = 0.9090909090909091
Process sally: 10/10 = 1.0
** exception error: an error occurred when evaluating an arithmetic expression
in function my:get_divisor/2 (my.erl, line 5)
3>
=ERROR REPORT==== 11-May-2019::12:06:18 ===
Error in process <0.71.0> with exit value:
{badarith,[{my,get_divisor,2,[{file,"my.erl"},{line,5}]}]}
И это конец вывода. Вы не видите ошибку от процесса <0.72.0>
, потому что, когда процесс <0.71.0>
умер, это привело к смерти оболочки (даже если вывод этих сообщений об ошибках был отменен), а новая оболочка, которая была автоматически запущена, не знать что-либо о процессе <0.72.0>
, и поэтому новый процесс оболочки не выводит сообщения об ошибках <0.72.0>
процесса.
Если вы используете i()
, вы увидите, что ни один из следующих процессов не запущен:
shell process = <0.64.0>
...
...
harry's pid = <0.71.0>
sally's pid = <0.72.0>
3> i().
=ERROR REPORT==== 10-May-2019::21:17:19 ===
Error in process <0.71.0> with exit value:
{badarith,[{my,get_divisor,2,[{file,"my.erl"},{line,5}]}]}
3> i().
Pid Initial Call Heap Reds Msgs
Registered Current Function Stack
<0.0.0> otp_ring0:start/2 376 990 0
init init:loop/1 2
<0.1.0> erts_code_purger:start/0 233 11 0
erts_code_purger erts_code_purger:wait_for_request 0
<0.2.0> erts_literal_area_collector:start 233 3 0
erts_literal_area_collector:msg_l 5
<0.3.0> erts_dirty_process_code_checker:s 233 3 0
erts_dirty_process_code_checker:m 1
<0.6.0> erlang:apply/2 6772 714804 0
erl_prim_loader erl_prim_loader:loop/3 5
<0.32.0> gen_event:init_it/6 1598 1848 0
error_logger gen_event:fetch_msg/6 10
<0.33.0> erlang:apply/2 1598 954 0
application_controlle gen_server:loop/7 7
<0.35.0> application_master:init/4 233 69 0
application_master:main_loop/2 7
<0.36.0> application_master:start_it/4 233 90 0
application_master:loop_it/4 5
<0.37.0> supervisor:kernel/1 987 2202 0
kernel_sup gen_server:loop/7 10
<0.38.0> erlang:apply/2 6772 142113 0
code_server code_server:loop/1 3
<0.40.0> rpc:init/1 233 32 0
rex gen_server:loop/7 10
<0.41.0> global:init/1 233 63 0
global_name_server gen_server:loop/7 10
<0.42.0> erlang:apply/2 233 25 0
global:loop_the_locker/1 5
<0.43.0> erlang:apply/2 233 3 0
global:loop_the_registrar/0 2
<0.44.0> inet_db:init/1 233 350 0
inet_db gen_server:loop/7 10
<0.45.0> global_group:init/1 233 74 0
global_group gen_server:loop/7 10
<0.46.0> file_server:init/1 1598 3436 0
file_server_2 gen_server:loop/7 10
<0.47.0> gen_event:init_it/6 233 51 0
erl_signal_server gen_event:fetch_msg/6 10
<0.48.0> supervisor_bridge:standard_error/ 233 50 0
standard_error_sup gen_server:loop/7 10
<0.49.0> erlang:apply/2 233 11 0
standard_error standard_error:server_loop/1 2
<0.50.0> supervisor_bridge:user_sup/1 233 72 0
gen_server:loop/7 10
<0.51.0> user_drv:server/2 2586 12209 0
user_drv user_drv:server_loop/6 9
<0.52.0> group:server/3 233 101 0
user group:server_loop/3 4
<0.53.0> group:server/3 318187 86312 0
group:server_loop/3 4
<0.54.0> kernel_config:init/1 233 48 0
gen_server:loop/7 10
<0.55.0> supervisor:kernel/1 376 282 0
kernel_safe_sup gen_server:loop/7 10
<0.59.0> supervisor:disk_log_sup/1 233 147 0
disk_log_sup gen_server:loop/7 10
<0.60.0> disk_log_server:init/1 610 91 0
disk_log_server gen_server:loop/7 10
<0.61.0> disk_log:init/2 6772 37458 0
disk_log:loop/1 5
<0.63.0> erlang:apply/2 17731 4978 0
shell:shell_rep/4 17
<0.74.0> erlang:apply/2 318187 39091 0
c:pinfo/1 50
Total 688344 1047971 0
273
ok
4>