Processes exiting normally

Given the two related processes child

and parent

how does the process child

find out that it parent

exits (exits) normally?

I, as an absolute beginner Erlang, believed that the process, when it had nothing else to do, exited with exit(normal)

. This then signals all related processes where

  • the behavior of processes trap_exit

    set to false

    this is to ignore the signal, and
  • the behavior of processes trap_exit

    set to this value true

    should generate a message {'EXIT', pid, normal}

    , where pid

    is the process ID of the terminating process.

My reason for thinking this is Find out you have Erlang for Great Good and Erlang Documentation stating the following.

It is said that the process ends normally if the reason for the exit is a normal atom. A process with no code to run usually ends.

Apparently this is not correct (?) Because exit(normal

) shows ** exception exit: normal

on the command line and does the code below. Exiting for lack of code to execute does not throw an exception or make my code work.

Consider the following code as an example.

-module(test).
-export([start/0,test/0]).

start() ->
     io:format("Parent (~p): started!\n",[self()]),
     P = spawn_link(?MODULE,test,[]),
     io:format(
        "Parent (~p): child ~p spawned. Waiting for 5 seconds\n",[self(),P]),
     timer:sleep(5000),
     io:format("Parent (~p): dies out of boredom\n",[self()]),
     ok. 

test() ->
     io:format("Child (~p): I'm... alive!\n",[self()]),
     process_flag(trap_exit, true),
     loop().

loop() ->
     receive
          Q = {'EXIT',_,_} ->
                io:format("Child process died together with parent (~p)\n",[Q]);
          Q ->
                io:format("Something else happened... (~p)\n",[Q])
     after
          2000 -> io:format("Child (~p): still alive...\n", [self()]), loop()
     end.

      

This outputs the result as follows.

(erlide@127.0.0.1)> test:start().
Parent (<0.145.0>): started!
Parent (<0.145.0>): child <0.176.0> spawned. Waiting for 5 seconds
Child (<0.176.0>): I'm... alive!
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Parent (<0.145.0>): dies out of boredom
ok
(erlide@127.0.0.1)10> Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
Child (<0.176.0>): still alive...
exit(pid(0,176,0),something).
Child process died together with parent ({'EXIT',<0.194.0>,something})

      

If you had to manually execute a command exit(pid(0,176,0),something)

to keep the child forever. Changing ok.

in start

to exit(normal)

makes the execution the same as

(erlide@127.0.0.1)3> test:start().
Parent (<0.88.0>): started!
Parent (<0.88.0>): child <0.114.0> spawned. Waiting for 5 seconds
Child (<0.114.0>): I'm... alive!
Child (<0.114.0>): still alive...
Child (<0.114.0>): still alive...
Parent (<0.88.0>): dies out of boredom
Child process died together with parent ({'EXIT',<0.88.0>,normal})
** exception exit: normal

      

My specific questions are as follows.

  • How can I get the above code to work as expected. That is, how can I ensure that the child process dies along with the parent process without changing the parent process?
  • Why does it exit(normal)

    generate ** exception exit: normal

    in the CLI? I find it hard to think of an exception as normal. What does smell mean in Erlang documentation?

I think these should be extremely simple questions, but I cannot figure it out. I am using Erlang 5.9.3.1 for Windows (x64).

+3


source to share


2 answers


Erlang shell has a worker for evaluating commands as a separate process, and all commands you enter are run by the same process. When you finish your function start

, the worker is still alive, and when you kill it with exit (), the shell understands it as a worker exception (because the worker will never die normally).

So:

  • You must run as a separate process with spawn

    orspawn_link

  • The CLI registers all work outputs as exceptional and normal.


Ps sorry for my english

PPS spawn(fun() -> test:start() end).

works as expected

4> spawn(fun() -> test:start() end).
Parent (<0.41.0>): started!
<0.41.0>
Parent (<0.41.0>): child <0.42.0> spawned. Waiting for 5 seconds
Child (<0.42.0>): I'm... alive!
Child (<0.42.0>): still alive...
Child (<0.42.0>): still alive...
Parent (<0.41.0>): dies out of boredom
Child process died together with parent ({'EXIT',<0.41.0>,normal})

      

+4


source


Comment on your question at @PetrKozorezov's answer. The shell doesn't behave on purpose. The shell worker process is a normal process, so if any process it is associated with crashes, then it will crash as well. Then another workflow will be launched. This is the usual Erlang way.

Function start/0

just returns and does NOT terminate its process, it just prints the message "to die of boredom". This is why the cycle continues to move, it does not receive a signal exit

, because no process has died.

When you change the function start/0

to end with exit(normal)

, then , you end the shell process, so the signal is exit

sent to the loop, which then receives the {'EXIT',...,...}

message and stamps.



When @PetrKozorezov spawned your original function start/0

in a separate process, which then died after being executed start/0

, it sent an exit signal normal

to the loop process which caused it to die.

This is perfectly normal Erlang behavior and style. Typically, you don't terminate the launch function with a help exit

, but leave it to the caller to decide when to die.

Another small point: since the start function does spawn_link

, you usually call it start_link

. Function A start

is considered a process only spawn

. This is of course just a convention, but a general one, so you haven't made a mistake.

+2


source







All Articles