Processes & Message Passing

Processes are cheap (~2.6 KB initial memory, microseconds to spawn).

24.1 Spawning processes

Processes are cheap (~2.6 KB initial memory, microseconds to spawn). Default max is ~262,144 processes; raise with erl +P 10000000.

Pid = spawn(fun() -> io:format("Hello from ~p~n", [self()]) end),
Pid2 = spawn(my_module, my_function, [Arg1, Arg2]),     % spawn(M, F, A)
Pid3 = spawn(Node, fun() -> ... end),                   % on another node
is_process_alive(Pid).

24.2 Sending & receiving

Each process has a mailbox (FIFO queue).

receive scans for the first message matching any pattern (selective receive); non-matching messages stay in the mailbox.

after 0 checks the mailbox without blocking.

Message ordering is guaranteed between a pair of processes only.

Pid ! {self(), hello},          % send: asynchronous, never fails, returns the message

receive
    {From, hello} ->
        From ! {self(), world};
    {From, Other} when is_atom(Other) ->
        From ! {error, unknown};
    stop ->
        ok
after 5000 ->                   % timeout in ms (or infinity)
    timeout
end.

24.3 A stateful server process

This client/server pattern — API functions wrapping messages, a tail-recursive loop holding state — is what gen_server generalizes.

-module(counter).
-export([start/0, increment/1, get/1, stop/1]).

start() -> spawn(fun() -> loop(0) end).

increment(Pid) -> Pid ! increment, ok.

get(Pid) ->
    Ref = make_ref(),
    Pid ! {get, self(), Ref},
    receive
        {Ref, Value} -> Value
    after 5000 -> error(timeout)
    end.

stop(Pid) -> Pid ! stop, ok.

loop(Count) ->
    receive
        increment -> loop(Count + 1);
        {get, From, Ref} -> From ! {Ref, Count}, loop(Count);
        stop -> ok;
        _Unknown -> loop(Count)      % discard junk to avoid mailbox growth
    end.

24.4 Registered names

register(counter, Pid),
counter ! increment,
whereis(counter),            % Pid | undefined
unregister(counter),
registered().

24.5 Process information & flags

self(),
process_info(Pid),
process_info(Pid, [message_queue_len, memory, current_function, status]),
erlang:processes(),
process_flag(trap_exit, true),
process_flag(priority, high),         % low | normal | high | max (use sparingly)
process_flag(message_queue_data, off_heap),
erlang:send_after(1000, self(), tick),
erlang:start_timer(1000, self(), tick),
erlang:cancel_timer(TRef),
timer:sleep(100), timer:apply_after(1000, M, F, A), timer:send_interval(1000, tick).

24.6 Process dictionary

put/2, get/1, erase/1 — per-process mutable storage. Avoid in normal code (hidden state), but used by some libraries (e.g., rand seeds, logger metadata).