Clause
← Toute la documentation

Traduit de l'original anglais · 1e3a39c8-dirty · 2026-10-26 · Lire en anglais

Processus

Exécuteur

Un runtime exécute ses processus sur ses workers d'ordonnanceur (workers, modèle d'exécution). Le démarrage fait de l'appel de la fonction d'entrée le premier processus, le processus principal, et exécute l'exécuteur jusqu'à ce qu'il se termine :

Workers

L'exécuteur exécute les processus sur RuntimeOptions::schedulers threads workers : le thread qui a démarré le programme et un thread de plus par worker supplémentaire. Les programmes prennent ce nombre dans --schedulers N (1 à 1 024, options du runtime) ; par défaut, un worker par processeur logique sur lequel le programme peut s'exécuter (son masque d'affinité, comme les ordonnanceurs en ligne d'OTP), ou par CPU de --scheduler-cpus.

Les réveils et l'arrêt ne nécessitent aucun mécanisme supplémentaire, car tout changement de l'état d'ordonnancement d'un processus se fait sous le mutex de l'exécuteur :

Affinité CPU

Par défaut, les workers ne sont liés à aucun CPU : le système d'exploitation les place sur n'importe quel CPU du masque d'affinité du programme, comme le +sbt u par défaut d'OTP. --scheduler-cpus SET (options du runtime) lie le worker N au N-ième CPU de l'ensemble, de façon cyclique s'il y a davantage de workers, comme +sbt/+sct d'OTP ; les threads des minuteries et d'E/S restent sans affinité.

Délais de réception

Les minuteries vivent dans une roue de minuteries hiérarchique hachée (hierarchical hashed timer wheel), comme ERTS les gère (scheduler/timer_wheel) :

Sorties

Un processus autre que le principal se termine avec une raison de sortie, comme dans OTP (detail::exit_reason, process/exits). Les signaux de sortie la transmettent aux processus liés (liens) et les messages 'DOWN' aux processus qui le surveillent (moniteurs) ; les rapports d'erreur l'affichent.

Comment le processus se termineRaison de sortieRapport d'erreur
Son premier appel retournenormalAucun
exit(Reason) (y compris normal, kill)ReasonAucun
Une erreur (error/1,2,3, badarith, {badmatch, V}, undef, ...){Reason, Stack}Oui
Un throw(Value) non capturé{{nocatch, Value}, Stack}Oui
Un signal de sortie le termine (signaux de sortie)La raison du signal, killed pour exit(Pid, kill)Aucun

Un rapport d'erreur est écrit sur stderr lorsque le processus se termine, après le vidage de la sortie standard, au format du gestionnaire de journalisation (logger handler) par défaut d'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,[]}]}

L'en-tête contient l'heure locale ; la raison est mise en page comme le fait ~p. Le processus principal n'en écrit pas : son exception non capturée est celle du programme (exécutables).

Messages

Dest ! Msg et erlang:send(Dest, Msg) évaluent d'abord Dest et renvoient Msg.

DestEffet
Un pid d'un processus vivantMsg est copié à plat dans le tas du destinataire (copie entre tas), comme OTP copie les messages, un grand message dans un bloc que le destinataire reprend (remise des messages), et ajouté à sa boîte de réception des signaux ; pour un destinataire s'exécutant sur un autre worker, dans un tampon parmi ses arrivées qu'il prend lors de sa prochaine consultation (tampons d'arrivée)
Un pid d'un processus terminéRien ; l'envoi réussit
Un nom enregistréComme pour son pid ; badarg lorsqu'aucun processus vivant ne porte ce nom
{Name, nonode@nohost} de deux atomesComme pour le pid enregistré sous Name ; rien s'il n'y en a pas
{Name, Node} pour tout autre nœudRien (il n'y a pas d'autres nœuds)
Une référenceComme pour le propriétaire d'un alias actif ; rien sinon
Toute autre chosebadarg

Tampons d'arrivée

Un envoi à un processus s'exécutant sur un autre worker ne prend aucun verrou (création et destruction des processus) :

Réception

receive choisit parmi ses clauses comme case, sur les messages de la boîte aux lettres :

Un lien relie deux processus dans les deux sens (Signals dans chaque contexte : les pids liés dans l'ordre des liens et l'indicateur trap_exit).

Moniteurs

Un moniteur est unidirectionnel : le processus qui surveille le détient (par référence, dans Signals) et le processus surveillé garde la référence et le pid de l'observateur, afin de pouvoir envoyer le message lorsqu'il se termine.

Noms enregistrés

L'exécuteur garde une table unique associant des noms (atomes) à des pids, et chaque processus son propre nom (Signals::name).

Dictionnaire de processus

put/2, get/0,1, get_keys/0,1 et erase/0,1 se comportent comme ceux d'OTP : put/2 et erase/1 renvoient la valeur précédente ou undefined, erase/0 renvoie chaque {Key, Value} et vide le dictionnaire, les clés se comparent par égalité exacte (1 et 1.0 sont deux clés).

Minuteries

start_timer/3,4 et send_after/3,4 (builtins/erlang/timers.cpp, scheduler/timers.cpp) arment une minuterie dans la roue de l'exécuteur (celle qu'utilisent les délais de réception) qui envoie Msg, ou {timeout, TimerRef, Msg}, à un pid ou à un nom enregistré lorsqu'elle se déclenche.

Introspection

process_info/1,2 (builtins/erlang/introspection.cpp, scheduler/introspection.cpp) lit un autre processus sous le verrou de l'exécuteur et copie ses termes (messages, dictionnaire) dans le tas de l'appelant ; un processus en cours d'exécution sur un autre worker est lu une fois sa tranche terminée. Un pid sans processus vivant donne undefined.

Options de spawn

Sources : builtins/erlang/spawning.cpp, scheduler/aliases.cpp.

Alias

Un alias est une référence à laquelle on peut envoyer des messages (Alias ! Msg) : alias/0,1 (explicit_unalias, ou reply pour un seul message), ou un moniteur créé avec l'option {alias, explicit_unalias | demonitor | reply_demonitor} de monitor/3 (demonitor se termine avec le moniteur, reply_demonitor termine aussi le moniteur à son premier message). unalias/1 termine un alias de l'appelant. Un envoi à une référence qui n'est pas un alias actif, ou dont le propriétaire s'est terminé, est abandonné. Un alias reply n'est consommé que lorsque son message est délivré, après toute attente d'un propriétaire occupé. L'option {tag, Tag} de monitor/3 remplace 'DOWN' dans le message du moniteur ; les moniteurs de ports n'acceptent pas d'options.

Nœuds

Un programme Clause est un seul nœud non distribué, nonode@nohost, et répond comme un tel nœud OTP (builtins/erlang/node.cpp) : nodes/0 vaut [], nodes(this | known) [nonode@nohost], les autres types [] ; nodes/2 donne {nonode@nohost, #{connection_id => undefined, node_type => this}} pour les clés demandées. is_alive/0 vaut false, monitor_node/2,3 lèvent error:notalive et disconnect_node/1 renvoie ignored.

Signaux de sortie

Tout signal de sortie provient d'un processus en cours d'exécution (exit/2, exit_signal/2, link/1) ou de la fin d'un processus. L'exécuteur le traite immédiatement lorsque sa cible ne s'exécute pas sur un autre worker, sinon une fois la tranche de la cible terminée (workers, scheduler/signals) : une cible terminée quitte la file d'exécution ou son attente et est finalisée (ses liens reçoivent le signal, son rapport d'erreur est écrit, son contexte libéré) avant que le builtin émetteur ne retourne. Une longue chaîne de liens se termine processus par processus, sans récursion.

Signal reçu par un processusNe piège pas les sortiesPiège les sorties
exit(Pid, kill), exit_signal(Pid, kill)Se termine avec la raison killedSe termine avec la raison killed
Raison normal (depuis un lien, ou envoyée à un autre processus)RienMessage {'EXIT', From, normal}
exit(self(), normal)Se termine avec la raison normal (bizarrerie d'OTP)Message {'EXIT', Self, normal}
exit_signal(self(), normal)RienMessage {'EXIT', Self, normal}
Toute autre raison, y compris kill depuis un lienSe termine avec cette raisonMessage {'EXIT', From, Reason}

Ports

Les ports sont spécifiés dans ports : un port est lié au processus qui l'a ouvert, participe aux liens, moniteurs, signaux de sortie et noms enregistrés comme un processus, et communique avec son processus connecté par des messages.

Suspension des processus

erlang:suspend_process/1,2 et erlang:resume_process/1 (scheduler/suspension.cpp) : chaque suspension est une retenue de la cible par l'exécuteur ; un processus suspendu ne reprend donc que lorsque chaque suspension de chaque processus qui le suspend est levée ; les messages et signaux lui parviennent toujours (un signal de sortie le termine toujours), et process_info(Pid, status) indique suspended. La fin d'un processus qui en suspend d'autres lève ses suspensions. Une suspension synchrone d'un processus s'exécutant sur un autre worker attend la fin de sa tranche de temps ; asynchronous retourne immédiatement, {asynchronous, Tag} envoie aussi {Tag, suspended} à l'appelant, et unless_suspending répond false lorsque l'appelant suspend déjà le processus. Suspendre ou reprendre l'appelant lui-même, un processus terminé, une valeur qui n'est pas un pid, ou fournir de mauvaises options donne badarg, de même que reprendre un processus que l'appelant ne suspend pas.

Builtins

BuiltinComportement
spawn(Fun)badarg sauf si Fun est un fun ; sinon un nouveau processus appelle Fun(), levant {badarity, {Fun, []}} dans ce processus pour une autre arité
spawn(M, F, Args)badarg sauf si M et F sont des atomes et Args une liste propre ; sinon un nouveau processus appelle M:F(Args...), levant undef dans ce processus lorsqu'aucun module ne l'exporte et qu'aucun builtin ne porte ce nom
spawn_link(Fun), spawn_link(M, F, Args)Comme spawn, et le nouveau processus est lié à l'appelant (liens)
is_process_alive(Pid)badarg sauf si Pid est un pid ; true tant que son processus ne s'est pas terminé
spawn_monitor(Fun), spawn_monitor(M, F, Args)Comme spawn, en renvoyant {Pid, Ref} d'un nouveau moniteur
link(Pid), unlink(Pid)badarg sauf si Pid est un pid (liens)
monitor(process, Item)badarg pour un autre type ou élément ; une référence (moniteurs) ; Item est un pid ou un nom enregistré
register(Name, Pid), unregister(Name), whereis(Name), registered()Voir noms enregistrés ; Name doit être un atome
demonitor(Ref), demonitor(Ref, Options)badarg sauf si Ref est une référence et Options une liste propre de flush et info
exit(Dest, Reason), exit_signal(Dest, Reason)badarg sauf si Dest est un pid ou une référence ; true après le signal de sortie
process_flag(trap_exit, Bool), process_flag(min_heap_size, N), process_flag(save_calls, N)Le réglage précédent ; badarg pour un autre indicateur, une valeur non booléenne ou une taille négative ou non entière
erlang:send(Dest, Msg), Dest ! MsgMsg, après l'avoir envoyé (messages) ; send/2 n'est pas auto-importé
spawn(Node, ...), spawn_link(Node, ...), spawn_monitor(Node, ...) (/2, /4)Ce nœud (nonode@nohost) : comme sans Node. Un autre nœud : le pid inutile d'OTP pour un nœud qui n'est pas vivant, un processus qui se termine immédiatement avec la raison noconnection, donc un lien ou un moniteur signale noconnection ; badarg pour un nœud qui n'est pas un atome
erlang:send(Dest, Msg, Options)ok, ou noconnect pour un message vers un autre nœud avec l'option noconnect ; options nosuspend, noconnect, priority (un message ordinaire)
send_nosuspend(Dest, Msg), send_nosuspend(Dest, Msg, [noconnect])true ; false pour un autre nœud avec noconnect
link(Pid, Options), exit(Dest, Reason, Options), exit_signal(Dest, Reason, Options)Comme sans options ; Options est [] ou [priority] (un signal ordinaire)
process_flag(Pid, save_calls, N)Le réglage précédent d'un autre processus (0..10000) ; conservé, mais Clause n'enregistre aucun appel ; les autres indicateurs donnent badarg
processes_iterator(), processes_next(Iter)Parcourt les processus vivants : {Pid, Iter1} ou none ; un processus créé pendant le parcours peut apparaître
bump_reductions(N)true pour un entier non négatif ; Clause ne compte aucune réduction
erlang:suspend_process(Pid), erlang:suspend_process(Pid, Options), erlang:resume_process(Pid)Voir suspension des processus
erlang:process_display(Pid, backtrace)true après avoir écrit la pile d'appels du processus vivant Pid sur la sortie d'erreur standard, un Module:Function/Arity par ligne, la fonction courante d'abord ; badarg pour un autre type ou un processus terminé

Le nouveau processus rejoint la fin de la file du worker de son parent (workers) ; spawn renvoie immédiatement son pid.