Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding the return value of spawn

I'm getting started with Erlang, and could use a little help understanding the different results when applying the PID returned from spawn/3 to the process_info/1 method.

Given this simple code where the a/0 function is exported, which simply invokes b/0, which waits for a message:

-module(tester).
-export([a/0]).

a() ->
    b().
b() ->
    receive {Pid, test} ->
        Pid ! alrighty_then
    end.

...please help me understand the reason for the different output from the shell:


Example 1:

Here, current_function of Pid is shown as being tester:b/0:

Pid = spawn(tester, a, []).

process_info( Pid ).

> [{current_function,{tester,b,0}},
    {initial_call,{tester,a,0}},
    ...

Example 2:

Here, current_function of process_info/1 is shown as being tester:a/0:

process_info( spawn(tester, a, []) ).

> [{current_function,{tester,a,0}},
    {initial_call,{tester,a,0}},
    ...

Example 3:

Here, current_function of process_info/1 is shown as being tester:a/0, but the current_function of Pid is tester:b/0:

process_info( Pid = spawn(tester, a, []) ).

> [{current_function,{tester,a,0}},
    {initial_call,{tester,a,0}},
    ...

process_info( Pid ).

> [{current_function,{tester,b,0}},
    {initial_call,{tester,a,0}},
    ...

I assume there's some asynchronous code happening in the background when spawn/3 is invoked, but how does variable assignment and argument passing work (especially in the last example) such that Pid gets one value, and process_info/1 gets another?

Is there something special in Erlang that binds variable assignment in such cases, but no such binding is offered to argument passing?


EDIT:

If I use a function like this:

TestFunc = fun( P ) -> P ! {self(), test}, flush() end.

TestFunc( spawn(tester,a,[]) ).

...the message is returned properly from tester:b/0:

Shell got alrighty_then
ok

But if I use a function like this:

TestFunc2 = fun( P ) -> process_info( P ) end.

TestFunc2( spawn(tester,a,[]) ).

...the process_info/1 still shows tester:a/0:

[{current_function,{tester,a,0}},
 {initial_call,{tester,a,0}},
 ...

Not sure what to make of all this. Perhaps I just need to accept it as being above my pay grade!

like image 912
user113716 Avatar asked Dec 06 '22 20:12

user113716


2 Answers

If you look at the docs for spawn it says it returns the newly created Pid and places the new process in the system scheduler queue. In other words, the process gets started but the caller keeps on executing.

Erlang is different from some other languages in that you don't have to explicitly yield control, but rather you rely on the process scheduler to determine when to execute which process. In the cases where you were making an assignment to Pid, the scheduler had ample time to switch over to the spawned process, which subsequently made the call to b/0.

like image 70
David Weldon Avatar answered Dec 22 '22 14:12

David Weldon


It's really quite simple. The execution of the spawned process starts with a call to a() which at some point shortly afterwards will call b() and then just sits there and waits until it receives a specific message. In the examples where you manage to immediately call process_info on the pid, you catch it while the process is still executing a(). In the other cases, when some delay is involved, you catch it after it has called b(). What about this is confusing?

like image 44
YOUR ARGUMENT IS VALID Avatar answered Dec 22 '22 16:12

YOUR ARGUMENT IS VALID