【问题标题】:Why doesn't my process die when the loop finishes executing?当循环完成执行时,为什么我的进程没有死?
【发布时间】:2017-03-28 18:47:33
【问题描述】:

这是我的代码:

-module(area_server0).
-export([loop/0]).
-include_lib("eunit/include/eunit.hrl").


loop() ->
    receive
        {circle, R} ->
            io:format("The area of a circle with radius ~w is: ~w~n",
                      [R, math:pi()*R*R]),
            loop();

        {rectangle, H, W} ->
            io:format("The are of a rectangle with sides ~w x ~w is: ~w~n",
                      [H, W, H*W]),
            loop();
        stop ->
            ok

    end.

在外壳中:

~/erlang_programs$ erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.4  (abort with ^G)

1> Pid = spawn(area_server0, loop, []).
<0.34.0>

2> i().
...
...
kernel_safe_sup       gen_server:loop/6                        9              
<0.32.0>              erlang:apply/2                        2586    18929    0
                      c:pinfo/1                               50              
<0.34.0>              area_server0:loop/0                    233        9    0
                      area_server0:loop/0                      1              
Total                                                      44876   318773    0
                                                             220  

3> Pid ! stop.
stop

4> i().
...
...
kernel_safe_sup       gen_server:loop/6                        9              
<0.32.0>              erlang:apply/2                        2586    38126    0
                      c:pinfo/1                               50              
<0.34.0>              area_server0:loop/0                    233        9    1
                      area_server0:loop/0                      1              
Total                                                      42900   355567    1
                                                         220             

我预计不会再在那里看到进程 。

现在,如果我改变我的代码以发送一个元组而不是原子的消息,那么进程就会终止:

-module(area_server0).
-export([loop/0]).
-include_lib("eunit/include/eunit.hrl").


loop() ->
    receive
        {circle, R} ->
            io:format("The area of a circle with radius ~w is: ~w~n",
                      [R, math:pi()*R*R]),
            loop();

        {rectangle, H, W} ->
            io:format("The are of a rectangle with sides ~w x ~w is: ~w~n",
                      [H, W, H*W]),
            loop();
        {stop, _Pid} ->
            ok

    end.

在外壳中:

~/erlang_programs$ erl
Erlang/OTP 17 [erts-6.4] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V6.4  (abort with ^G)

1> c(area_server0).
{ok,area_server0}

2> Pid = spawn(area_server0, loop, []).
<0.43.0>

3> i().
...
...
kernel_safe_sup       gen_server:loop/6                        9              
<0.32.0>              erlang:apply/2                         987    19840    0
                      c:pinfo/1                               50              
<0.43.0>              area_server0:loop/0                    233        1    0
                      area_server0:loop/0                      1              
Total                                                      37492   862830    0
                                                             220  
ok

4> Pid ! {stop, self()}.
{stop,<0.32.0>}

5> i().
...
...
kernel_safe_sup       gen_server:loop/6                        9              
<0.32.0>              erlang:apply/2                        2586    39352    0
                      c:pinfo/1                               50              
Total                                                      38858   900091    0
                                                             219              
ok

显然,第一个示例没有找到原子stop 的模式匹配。为什么不呢?

【问题讨论】:

    标签: erlang


    【解决方案1】:

    在您的第一个代码中,当您在 shell 中第二次调用 i/0 时

    进程循环/0 邮箱不为空(num = 1)

    表示您的停止消息与进程循环/0不匹配

    确保你的操作顺序正确:

    1. 编译

    2. 生成

    3. i/0

    4. 发送停止消息

    5. i/0

    【讨论】:

    • 嘿,这很聪明。
    【解决方案2】:

    好吧,看起来stop 可能是 erlang 中的保留原子。如果我替换原子finishedxyz,我的代码将按预期工作:

    loop() ->
        receive
            {circle, R} ->
                io:format("The area of a circle with radius ~w is: ~w~n",
                          [R, math:pi()*R*R]),
                loop();
    
            {rectangle, H, W} ->
                io:format("The are of a rectangle with sides ~w x ~w is: ~w~n",
                          [H, W, H*W]),
                loop();
            finished ->
                ok
    
        end.
    

    【讨论】:

    • 原子“stop”没有什么特别之处。更有可能的是,模块的加载版本与您的编辑器中的不同(可能您忘记重新编译和/或在更改后重新加载它)。当您再次修改代码时,您加载了新版本并且它可以工作。试着回到“停止”看看是否是这种情况。
    • @RichardC,你是对的,当然。现在,当我尝试我的代码并发送消息“停止”时;该过程终止。当我发布我的 shell 输出时,我通常会确保包含 c(modname)