Clause
← Toda a documentação

Traduzido do original em inglês · 1e3a39c8-dirty · 2026-10-26 · Ler em inglês

Processos

Executor

Um runtime executa os seus processos nos seus workers do escalonador (workers, modelo de execução). O arranque faz da chamada da função de entrada o primeiro processo, o processo principal, e executa o executor até este terminar:

Workers

O executor executa processos em RuntimeOptions::schedulers threads de trabalho (worker threads): a thread que iniciou o programa e mais uma thread por cada worker adicional. Os programas obtêm o número a partir de --schedulers N (de 1 a 1024, opções do runtime); por omissão, um worker por processador lógico em que o programa pode correr (a sua máscara de afinidade, como os escalonadores online do OTP), ou por CPU de --scheduler-cpus.

Os despertares e o encerramento não precisam de mais nenhum mecanismo, porque todas as mudanças do estado de escalonamento de um processo acontecem sob o mutex do executor:

Afinidade de CPU

Os workers não têm afinidade fixa por omissão: o sistema operativo coloca-os em qualquer CPU da máscara de afinidade do programa, como o +sbt u predefinido do OTP. --scheduler-cpus SET (opções do runtime) fixa o worker N à N-ésima CPU do conjunto, em rotação quando há mais workers, como o +sbt/+sct do OTP; as threads dos temporizadores e de E/S continuam sem afinidade fixa.

Timeouts de receive

Os temporizadores vivem numa roda de temporizadores hierárquica com hash (hierarchical hashed timer wheel), tal como o ERTS os mantém (scheduler/timer_wheel):

Saídas

Um processo que não seja o principal termina com uma razão de saída, como no OTP (detail::exit_reason, process/exits). Os sinais de saída levam-na aos processos ligados (ligações) e as mensagens 'DOWN' aos que o monitorizam (monitores); os relatórios de erro mostram-na.

Como o processo terminaRazão de saídaRelatório de erro
A sua primeira chamada retornanormalNenhum
exit(Reason) (também normal, kill)ReasonNenhum
Um erro (error/1,2,3, badarith, {badmatch, V}, undef, ...){Reason, Stack}Sim
Um throw(Value) não capturado{{nocatch, Value}, Stack}Sim
Um sinal de saída termina-o (sinais de saída)A razão do sinal, killed para exit(Pid, kill)Nenhum

Um relatório de erro é escrito no stderr quando o processo termina, depois de esvaziar a saída padrão, no formato do handler de logger por omissão do OTP:

=ERROR REPORT==== 8-Oct-2026::03:42:15.983000 ===
Error in process <0.8.0> with exit value:
{boom,[{crash_reports,'-main/1-fun-6-',0,[]}]}

O cabeçalho tem a hora local; a razão é disposta como faz ~p. O processo principal não escreve nenhum: a sua exceção não capturada é a do programa (executáveis).

Mensagens

Dest ! Msg e erlang:send(Dest, Msg) avaliam primeiro Dest e devolvem Msg.

DestEfeito
Um pid de um processo vivoMsg é copiada de forma plana para o heap do recetor (cópia entre heaps), como o OTP copia as mensagens, uma grande para um bloco de que o recetor toma posse (entrega de mensagens), e acrescentada à sua caixa de entrada de sinais; para um recetor em execução noutro worker, para um buffer entre as suas chegadas que aceita quando voltar a consultar (buffers de chegada)
Um pid de um processo que terminouNada; o envio tem sucesso
Um nome registadoComo para o seu pid; badarg quando nenhum processo vivo tem o nome
{Name, nonode@nohost} de dois átomosComo para o pid registado como Name; nada quando não existe nenhum
{Name, Node} para qualquer outro nóNada (não existem outros nós)
Uma referênciaComo para o dono de um alias ativo; nada caso contrário
Qualquer outra coisabadarg

Buffers de chegada

Um envio para um processo em execução noutro worker não obtém qualquer bloqueio (criação e destruição de processos):

Receive

receive seleciona entre as suas cláusulas como case, sobre as mensagens da caixa de correio:

Uma ligação (link) liga dois processos nos dois sentidos (Signals em cada contexto: os pids ligados por ordem de ligação e o indicador trap_exit).

Monitores

Um monitor é unidirecional: o processo que monitoriza detém-no (por referência, em Signals) e o processo monitorizado guarda a referência e o pid do monitorizador, para poder enviar a mensagem quando terminar.

Nomes registados

O executor mantém uma tabela de nomes (átomos) para pids, e cada processo o seu próprio nome (Signals::name).

Dicionário do processo

put/2, get/0,1, get_keys/0,1 e erase/0,1 comportam-se como no OTP: put/2 e erase/1 devolvem o valor anterior ou undefined, erase/0 devolve todos os {Key, Value} e esvazia o dicionário, e as chaves correspondem por igualdade exata (1 e 1.0 são duas chaves).

Temporizadores

start_timer/3,4 e send_after/3,4 (builtins/erlang/timers.cpp, scheduler/timers.cpp) armam um temporizador na roda do executor (a mesma que os timeouts de receive usam) que envia Msg, ou {timeout, TimerRef, Msg}, para um pid ou nome registado quando dispara.

Introspeção

process_info/1,2 (builtins/erlang/introspection.cpp, scheduler/introspection.cpp) lê outro processo sob o bloqueio do executor e copia os seus termos (mensagens, dicionário) para o heap do chamador; um processo em execução noutro worker é lido quando a sua fatia termina. Um pid sem processo vivo dá undefined.

Opções de spawn

Código-fonte: builtins/erlang/spawning.cpp, scheduler/aliases.cpp.

Aliases

Um alias é uma referência para a qual se podem enviar mensagens (Alias ! Msg): alias/0,1 (explicit_unalias, ou reply para uma mensagem), ou um monitor criado com {alias, explicit_unalias | demonitor | reply_demonitor} de monitor/3 (demonitor termina com o monitor, reply_demonitor também termina o monitor na sua primeira mensagem). unalias/1 termina um alias do chamador. Um envio para uma referência que não é um alias ativo, ou cujo dono terminou, é descartado. Um alias reply só é consumido quando a sua mensagem é entregue, depois de qualquer espera por um dono ocupado. {tag, Tag} de monitor/3 substitui 'DOWN' na mensagem do monitor; os monitores de portas não aceitam opções.

Nós

Um programa Clause é um único nó não distribuído, nonode@nohost, e responde como um nó OTP desse tipo (builtins/erlang/node.cpp): nodes/0 é [], nodes(this | known) [nonode@nohost], os outros tipos []; nodes/2 dá {nonode@nohost, #{connection_id => undefined, node_type => this}} para as chaves pedidas. is_alive/0 é false, monitor_node/2,3 lançam error:notalive e disconnect_node/1 devolve ignored.

Sinais de saída

Cada sinal de saída provém de um processo em execução (exit/2, exit_signal/2, link/1) ou do fim de um processo. O executor atua sobre ele de imediato quando o seu destino não está a correr noutro worker, caso contrário quando a fatia do destino tiver terminado (workers, scheduler/signals): um destino terminado sai da fila de execução ou da sua espera e é finalizado (as suas ligações sinalizadas, o seu relatório de erro escrito, o seu contexto libertado) antes de o builtin que enviou retornar. Uma cadeia longa de ligações termina processo a processo, sem recursão.

Sinal num processoSem capturar saídasA capturar saídas
exit(Pid, kill), exit_signal(Pid, kill)Termina com a razão killedTermina com a razão killed
Razão normal (de uma ligação, ou enviada a outro processo)NadaMensagem {'EXIT', From, normal}
exit(self(), normal)Termina com a razão normal (peculiaridade do OTP)Mensagem {'EXIT', Self, normal}
exit_signal(self(), normal)NadaMensagem {'EXIT', Self, normal}
Qualquer outra razão, incluindo kill de uma ligaçãoTermina com essa razãoMensagem {'EXIT', From, Reason}

Portas

As portas estão especificadas em portas: uma porta está ligada a quem a abriu, participa em ligações, monitores, sinais de saída e nomes registados como um processo, e comunica com o seu processo conectado através de mensagens.

Suspensão de processos

erlang:suspend_process/1,2 e erlang:resume_process/1 (scheduler/suspension.cpp): cada suspensão retém uma vez o destino no executor, pelo que um processo suspenso só volta a correr quando todas as suspensões de todos os suspensores forem retomadas; as mensagens e os sinais continuam a chegar-lhe (um sinal de saída continua a terminá-lo), e process_info(Pid, status) indica suspended. O fim de um suspensor retoma as suas suspensões. Uma suspensão síncrona de um processo em execução noutro worker espera que a sua fatia de tempo termine; asynchronous retorna de imediato, {asynchronous, Tag} envia também ao chamador {Tag, suspended}, e unless_suspending responde false quando o chamador já suspende o processo. Suspender ou retomar o próprio chamador, um processo terminado, um valor que não seja pid ou opções inválidas dão badarg, tal como retomar um processo que o chamador não suspende.

Builtins

BuiltinComportamento
spawn(Fun)badarg a menos que Fun seja um fun; caso contrário, um novo processo chama Fun(), lançando {badarity, {Fun, []}} nesse processo para outra aridade
spawn(M, F, Args)badarg a menos que M e F sejam átomos e Args uma lista própria; caso contrário, um novo processo chama M:F(Args...), lançando undef nesse processo quando nenhum módulo a exporta e nenhum builtin tem esse nome
spawn_link(Fun), spawn_link(M, F, Args)Como spawn, e o novo processo é ligado ao chamador (ligações)
is_process_alive(Pid)badarg a menos que Pid seja um pid; true enquanto o seu processo não tiver terminado
spawn_monitor(Fun), spawn_monitor(M, F, Args)Como spawn, devolvendo {Pid, Ref} de um novo monitor
link(Pid), unlink(Pid)badarg a menos que Pid seja um pid (ligações)
monitor(process, Item)badarg para outro tipo ou item; uma referência (monitores); Item é um pid ou um nome registado
register(Name, Pid), unregister(Name), whereis(Name), registered()Ver nomes registados; Name tem de ser um átomo
demonitor(Ref), demonitor(Ref, Options)badarg a menos que Ref seja uma referência e Options uma lista própria de flush e info
exit(Dest, Reason), exit_signal(Dest, Reason)badarg a menos que Dest seja um pid ou uma referência; true depois do sinal de saída
process_flag(trap_exit, Bool), process_flag(min_heap_size, N), process_flag(save_calls, N)A definição anterior; badarg para outro indicador, um não booleano ou um tamanho negativo ou não inteiro
erlang:send(Dest, Msg), Dest ! MsgMsg, depois de a enviar (mensagens); send/2 não é importado automaticamente
spawn(Node, ...), spawn_link(Node, ...), spawn_monitor(Node, ...) (/2, /4)Este nó (nonode@nohost): como sem Node. Outro nó: o pid inútil do OTP de um nó que não está ativo, um processo que termina de imediato com a razão noconnection, pelo que uma ligação ou monitor indica noconnection; badarg para um nó que não seja átomo
erlang:send(Dest, Msg, Options)ok, ou noconnect para uma mensagem para outro nó com a opção noconnect; opções nosuspend, noconnect, priority (uma mensagem normal)
send_nosuspend(Dest, Msg), send_nosuspend(Dest, Msg, [noconnect])true; false para outro nó com noconnect
link(Pid, Options), exit(Dest, Reason, Options), exit_signal(Dest, Reason, Options)Como sem opções; Options é [] ou [priority] (um sinal normal)
process_flag(Pid, save_calls, N)A definição anterior de outro processo (0..10000); guardada, mas o Clause não guarda chamadas; outros indicadores dão badarg
processes_iterator(), processes_next(Iter)Percorrem os processos vivos: {Pid, Iter1} ou none; um processo lançado durante o percurso pode aparecer
bump_reductions(N)true para um inteiro não negativo; o Clause não conta reduções
erlang:suspend_process(Pid), erlang:suspend_process(Pid, Options), erlang:resume_process(Pid)Ver suspensão de processos
erlang:process_display(Pid, backtrace)true depois de escrever a pilha de chamadas do processo vivo Pid na saída de erro padrão, um Module:Function/Arity por linha, a função atual primeiro; badarg para outro tipo ou um processo terminado

O novo processo junta-se ao fim da fila do worker do seu pai (workers); spawn devolve o seu pid de imediato.