Processer
Exekutor
En runtime kör sina processer på sina schemaläggares arbetstrådar (arbetstrådar, exekveringsmodell). Vid uppstart görs anropet av ingångsfunktionen till den första processen, huvudprocessen, och exekutorn körs tills den avslutas:
- Körbara processer väntar i sin arbetstråds först in, först ut-kö
(arbetstrådar). En arbetstråd kör den första under en tidsskiva
på 4 000 reduktioner (OTP:s
CONTEXT_REDS) och lägger sedan tillbaka den sist i sin kö, om den inte har avslutats. - Varje funktionsingång förbrukar en reduktion: anrop, svansanrop, fun- och dynamiska anrop samt inbyggda funktioner. När inga reduktioner återstår sker ingången inte: processen registrerar funktionen den var på väg in i, behåller sina argument i sina register (de förblir rötter för skräpsamlingen) och återvänder till exekutorn, som senare återupptar den genom att upprepa ingången (exekveringsmodell). Varje loophuvud i en comprehension förbrukar också en, så att även en loop utan anrop lämnar ifrån sig körningen. Inbyggda funktioner vars arbete växer med ett list- eller binary-argument körs i portioner och lämnar ifrån sig körningen mellan dem (portioner).
- Varje process äger sin heap och sin stack. Argument till en ny process kopieras in i dess heap (kopiering mellan heapar).
- En process avslutas när dess första anrop returnerar eller kastar ett
undantag. En avslutad process lämnar processtabellen direkt; dess pid
förblir en giltig term och
is_process_alive/1returnerar false för den. Dess kontext, heap och stack frigörs när arbetstråden som avslutade den lämnar exekutorns mutex. - En process som väntar i en
receivestår inte i någon kö; en sändning till den köar den igen (receive). - När huvudprocessen avslutas, avslutas programmet med dess utfall
(körbara filer): processer som fortfarande står i kö eller
väntar frigörs utan att köras vidare, på samma sätt som ett OTP-escript
stannar när
main/1returnerar. - En exitsignal som avslutar huvudprocessen avslutar programmet (exitsignaler).
erlang:halt/0,1i vilken process som helst avslutar programmet med dess status. Ett runtime-fel i vilken process som helst (minnet slut, ett valfritt tak överskridet, ett internt fel) avslutar programmet som ett runtime-fel (exit 70). Ett Erlang-undantag avslutar endast den process som kastade det (avslut).- Värdanrop av exporterade funktioner (
CLAUSE_invoke_v1) kör sin funktion i den anropande kontexten till slut och återupptar den efter varje gång den lämnar ifrån sig körningen, utan att köra andra processer; program som startas avCLAUSE_main_v1använder exekutorn.
Arbetstrådar
Exekutorn kör processer på RuntimeOptions::schedulers arbetstrådar: tråden
som startade programmet och ytterligare en tråd per extra arbetstråd. Program
tar antalet från --schedulers N (1 till 1 024,
runtime-alternativ); standardvärdet är en
arbetstråd per logisk processor som programmet får köras på (dess
affinitetsmask, som OTP:s onlineschemaläggare), eller per CPU i
--scheduler-cpus.
- Varje arbetstråd har sin egen körkö, liksom varje ERTS-schemaläggare: en process stannar hos den arbetstråd den senast kördes på, så att dess heap stannar i den kärnans cacheminnen. En startad process börjar på sin förälders arbetstråd. Lediga arbetstrådar sover tills en process köas åt dem eller det finns arbete att stjäla; timertråden köar processer vars tidsgräns för receive löper ut (tidsgränser för receive).
- Processer migrerar som i ERTS, som balanserar sina körköer periodiskt: var fjärde tidsskiva jämför en arbetstråd sin kö med grannens och tar en process från den när grannen har minst två fler. En arbetstråd med tom kö stjäl en process från den längsta kön som har minst två, eller den enda processen hos en sovande arbetstråd, som den kör innan den arbetstråden vaknar.
- Väckningar är lata, liksom ERTS håller processer som pratar med varandra på en schemaläggare: en körande process som väcker en process hos en sovande, tom arbetstråd köar den på sin egen arbetstråd, som tar den när dess tidsskiva tar slut; en annan arbetstråd väcks endast när en kö då har mer än en process. Timer- och I/O-trådarna, portuppgifter och arbetstrådar mellan tidsskivor köar en process åt dess egen arbetstråd, eller åt en ledig arbetstråd när dess egen är upptagen.
- En exekutormutex skyddar de väntande processerna, timrarna, de registrerade namnen, varje process länkar och monitorer samt varje process som inte körs. En körande process heap, stack, brevlåda och felkanal tillhör enbart dess arbetstråd; Erlang-kod körs utan låset. Körköerna och arbetstrådarnas vilotillstånd har ett eget lås, som tas efter exekutorns mutex; lediga arbetstrådar sover på det (skapande och nedmontering av processer).
- En spawn bygger den nya processens kontext och kopierar in dess anrop utan
något lås. En som varken länkar eller övervakar publicerar den sedan i
processtabellen och köar den enbart under deras egna lås, utan att någonsin
ta exekutorns mutex;
spawn_link,spawn_monitoroch de övervakande formerna avspawn_opt/spawn_requestpublicerar, länkar eller övervakar och köar under exekutorns mutex. En arbetstråd frigör avslutade processers kontexter direkt efter att den lämnar mutexen inför nästa tidsskiva. - En process kostar sex allokeringar under sin livstid (kostnad för att skapa processer): dess kontext, kontextens runtime-bindningar med dess schemaläggningstillstånd, dess heaplagring och första heapblock, dess ankomster och dess livstidstoken. De första 64 stackorden och fyra listnoder för brevlådan ligger i kontexten, monitorernas maps skapas av den första monitorn, och runtimens register (kontexter, återvinning av persistenta termer) håller ingen nod per process.
- Länkar, monitorer och namn ändras under låset direkt, även för en process
som körs någon annanstans. Ett meddelande väntar i en buffert bland
mottagarens ankomster tills mottagaren tar det
(ankomstbuffertar). En exitsignal
från
exit/2ellerexit_signal/2till en sådan process gör ingenting och dess process avslutar sin tidsskiva (builtins::Blocked); den väntar tills målets tidsskiva tar slut, körs sedan först och upprepar den inbyggda funktionen med samma argument. Målet hålls kvar till dess, så att den upprepade inbyggda funktionen inte kan hitta det körande igen. En process som avslutas med länkar eller monitorer vars processer körs någon annanstans slutförs på samma sätt när deras tidsskivor tar slut. - Därför behåller signaler sin ordning: ett meddelande som buffrats före en
blockerad exitsignal från samma avsändare når mottagaren först, och
is_process_alive/1efterexit(Pid, kill)är false, som OTP utlovar för signaler från anroparen. - En spawn länkar eller övervakar den nya processen (
spawn_link,spawn_monitor) innan någon arbetstråd kan köra den. En startad process kan köras innan dess förälder fortsätter, så ett program som övervakar eller länkar till en kortlivad process efterspawn/1kan senoproc, som i en OTP med flera schemaläggare. - Huvudprocessens slut, en halt eller ett runtime-fel stoppar programmet när varje arbetstråd har avslutat sin pågående tidsskiva; därefter frigörs de andra processerna.
- Delade runtime-tjänster är synkroniserade (trådar): atomer, kodservern, pid- och portnummer och minnesredovisningen.
- Utdata från olika processer flätas samman i den ordning deras skrivningar
sker. Varje anrop av
io:formatocherlang:displayskriver sin text direkt.
Väckningar och nedstängning behöver ingen ytterligare mekanism, eftersom varje ändring av en process schemaläggningstillstånd sker under exekutorns mutex:
- Ett meddelande,
'EXIT'eller'DOWN'för en väntande process köar den i samma kritiska sektion som levererar det och väcker en arbetstråd som ovan. En process som fortfarande är i den tidsskiva där den började vänta kan inte få något meddelande då (dess avsändare väntar på att tidsskivan ska ta slut), så leveransen hittar den alltid parkerad. Ett postat meddelande (ankomstbuffertar) går inte heller förlorat: parkeringen kontrollerar ankomsterna under deras lås, och en postning som hittar mottagaren parkerad väcker den under exekutorns mutex. - En arbetstråd som inte hittar någon körbar process sover tills en annan arbetstråd, en sändning, en spawn eller timertråden köar en, eller programmet avslutas; den tittar på köerna och sover under körköernas lås, som varje köläggning tar. Arbetstrådar läser aldrig klockan för timrar; att parkera en process med en tidsgräns tidigare än alla andra väcker endast timertråden.
- Ett meddelande och en tidsgräns som löper ut för samma receive kan kapplöpa: det som kommer först köar processen och avbryter det andra, och receive tar ett meddelande som anlände innan den återupptogs, som OTP:s gör.
- En exitsignal till en väntande, köad, kvarhållen eller blockerad process tar ut den ur var den än befinner sig innan den slutförs.
- När programmet avslutas slutför varje arbetstråd sin pågående tidsskiva och
stannar;
run()returnerar efter att ha förenat (join) dem, och varje annan process som exekutorn startade frigörs, så att runtimen stängs ned utan några kvarvarande kontexter. - OTP-golden-testet
executables_wakeupsstresstestar detta med 1, 2, 4 och alla arbetstrådar: mottagare vars tidsgränser på 0–2 ms kapplöper med avsändarnas meddelanden, en kedja av 16 länkade snurrande processer som avslutas av en enda exitsignal där varje medlem övervakas, övervakade processer som avslutas medan deras bevakare vaknar, ett program som avslutas medan processer snurrar, väntar och översvämmar varandra, samt en halt i en annan process.
CPU-bindning
Arbetstrådar är obundna som standard: operativsystemet placerar dem på valfri
CPU i programmets affinitetsmask, som OTP:s standard +sbt u.
--scheduler-cpus SET (runtime-alternativ)
binder arbetstråd N till mängdens N:te CPU, i turordning med omstart när det
finns fler arbetstrådar, som OTP:s +sbt/+sct; timer- och I/O-trådarna förblir
obundna.
performanceär den snabbaste kärnklassen: Windows-kärnor med högstEfficiencyClass, Linux/sys/devices/cpu_core/cpus(Intel hybrid) eller CPU:erna med störstcpu_capacity; på en CPU vars kärnor är likadana, varje CPU.allär varje CPU i affinitetsmasken. En lista (0-15,2,4,6, CPU:er upp till 1023) får bara ange CPU:er i affinitetsmasken:--scheduler-cpus: CPU N is not available to the program, exit 70.- Windows numrerar CPU:erna i processens processorgrupp (högst 64);
performanceläser grupp 0. - macOS har ingen trådaffinitet: alternativet godtas,
performanceräknar den första prestandanivån (hw.perflevel0.logicalcpu) för standardantalet arbetstrådar, och bindning höjer bara varje arbetstråd till QoS-klassenUSER_INTERACTIVE, som macOS i första hand kör på P-kärnorna.
Tidsgränser för receive
Timrar ligger i ett hierarkiskt hashat timerhjul, så som ERTS håller dem
(scheduler/timer_wheel):
- Tick är millisekunder sedan exekutorn startade. Sex nivåer med 64 platser täcker 2^36 tick, mer än den längsta tidsgränsen (4 294 967 295 ms). En timer ligger på platsen för den högsta 6-bitarssiffra där dess tick skiljer sig från hjulets aktuella tick; upptagna platser är bitmappar per nivå.
- Att aktivera (en väntande process parkeras) och avbryta (ett meddelande, en exitsignal eller processens slut kommer först) länkar ur eller in en intrusiv listnod som hålls tillsammans med processens schemaläggningstillstånd: konstant tid. En tidsfrist blir det tick som ligger vid eller efter den, så ingen tidsgräns utlöses för tidigt.
- En timertråd per körning sover till nästa upptagna plats (den första upptagna platsen efter den aktuella på någon nivå), läser klockan en gång när den vaknar och flyttar fram hjulet till det ticket: platser på högre nivåer som nås vid sin början flyttar ned sina timrar, och platsen på nivå 0 utlöses. Endast platser vars tid har kommit konsulteras; väntande processer genomsöks aldrig. Processer som löpt ut köas i tickordning.
- Hjulet delas av arbetstrådarna under exekutorns mutex.
after 0väntar aldrig ochinfinityaktiverar aldrig en timer. --profilerapporterar tidsskivorna och timertrådens klockavläsningar (profilering). Timrar utlöses bara så exakt som värdens tidsbegränsade väntan (på Windows standardupplösningen för timrar).runtime_timer_wheelaktiverar 20 000 timrar över alla nivåer, avbryter 90 % och flyttar fram i ojämna steg: varje kvarvarande timer utlöses en gång, i den första framflyttning som når dess tick, i tickordning; ingen avbruten utlöses.
Avslut
En annan process än huvudprocessen avslutas med en exitorsak, som i OTP
(detail::exit_reason, process/exits). Exitsignaler bär den till länkade
processer (länkar) och 'DOWN'-meddelanden till övervakande
(monitorer); felrapporter visar den.
| Hur processen avslutas | Exitorsak | Felrapport |
|---|---|---|
| Dess första anrop returnerar | normal | Ingen |
exit(Reason) (även normal, kill) | Reason | Ingen |
Ett fel (error/1,2,3, badarith, {badmatch, V}, undef, ...) | {Reason, Stack} | Ja |
Ett ofångat throw(Value) | {{nocatch, Value}, Stack} | Ja |
| En exitsignal avslutar den (exitsignaler) | Signalens orsak, killed för exit(Pid, kill) | Ingen |
En felrapport skrivs på stderr när processen avslutas, efter att standard-utdata har tömts, i formatet för OTP:s standardhanterare för loggning:
=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,[]}]}
Huvudet innehåller lokal tid; orsaken formateras som ~p gör. Huvudprocessen
skriver ingen: dess ofångade undantag är programmets
(körbara filer).
Meddelanden
Dest ! Msg och erlang:send(Dest, Msg) evaluerar Dest först och
returnerar Msg.
Dest | Effekt |
|---|---|
| En pid för en levande process | Msg kopieras platt in i mottagarens heap (kopiering mellan heapar), så som OTP kopierar meddelanden, ett stort meddelande in i ett block som mottagaren tar över (överlämning av meddelanden), och läggs till sist i dess signalinkorg; till en mottagare som körs på en annan arbetstråd, in i en buffert bland dess ankomster som den tar nästa gång den tittar (ankomstbuffertar) |
| En pid för en process som har avslutats | Ingenting; sändningen lyckas |
| Ett registrerat namn | Som för dess pid; badarg när ingen levande process har namnet |
{Name, nonode@nohost} av två atomer | Som för den pid som är registrerad som Name; ingenting när det inte finns någon |
{Name, Node} för någon annan nod | Ingenting (det finns inga andra noder) |
| En referens | Som för ägaren till ett aktivt alias; annars ingenting |
| Allt annat | badarg |
- Meddelanden från en avsändare anländer i den ordning den skickade dem; en sändning till sig själv är ett meddelande som vilket annat som helst.
- Varje meddelande är en rot för skräpsamlingen hos sin mottagare tills en receive tar det (runtime-heap).
- Mottagarens brevlåda (
Mailbox) har en signalinkorg, dit sändningar läggs, och en meddelandekö som receive söker igenom från en sparad position: anlända meddelanden flyttas sist i kön när en receive undersöker dem. Båda listorna återanvänder upp till 64 reservnoder i brevlådan, så en sändning och mottagning av ett meddelande allokerar ingen nod från C++-heapen. - När mottagarens heap vägrar kopian (ett valfritt tak som
--max-heap, eller att värden har slut på minne) levereras ingenting och den sändande processen misslyckas med ett runtime-fel (exit 70), som varje process som överskrider ett tak; en mottagare som vägrar ett meddelande från sina ankomster misslyckas själv.
Ankomstbuffertar
En sändning till en process som körs på en annan arbetstråd tar inget lås alls (skapande och nedmontering av processer):
- Runtimens processtabell (
ProcessTable) är en array med öppen adressering och atomära platser som en sändning på en arbetstråd läser utan något lås: pid-nummer återanvänds aldrig, så en raderad plats förblir en gravsten tills en insättning bygger om arrayen. Insättningar och raderingar tar ett skrivarlås och håller även exekutorlåset, under vilket uppslagningar inte behöver något mer. - Varje process har sina ankomster (
Arrivals): en låsfri lista som avsändare lägger meddelanden på, med en kopia av exekutorns körtillstånd för processen. Avsändaren slår upp mottagarens ankomster och läser det tillståndet; en avsändare vars senaste sändning till samma mottagare fann att den inte kördes hoppar över uppslagningen. - Avsändaren går igenom meddelandet en gång, före varje lås
(en enda meddelandegenomgång). Till en
körande mottagare kopierar den meddelandet direkt efter en listnod, i en
allokering (ett stort meddelande eller ett som håller binaries utanför heapen
till en
MessageBuffer), och lägger till det; mottagaren kopierar senare dessa ord till sin heap och omlokaliserar deras pekare. Varje annan mottagare får meddelandet under exekutorlåset som förut: kopierat till dess heap, eller lagt sist bland dess ankomster när den har börjat en tidsskiva under tiden eller fortfarande har ankomster, så att en avsändares meddelanden aldrig passerar varandra och avsändaren aldrig kopierar en anhopning under låset. Båda utfallen av en kapplöpning är korrekta. - Mottagaren tar sina ankomster till sin heap och signalinkorg, äldst först:
64 åt gången när dess receive har undersökt varje meddelande och skulle
vänta, så att en flod når heapen lika snabbt som receive förbrukar den (OTP
håller sådana meddelanden i heapfragment tills de behövs); alla när den går
i dvala, och innan något annat levereras till den under exekutorlåset (ett
meddelande,
'EXIT','DOWN', port- eller aliasmeddelande), så att varje avsändares meddelanden behåller sin ordning i förhållande till dess andra signaler.process_infotar dem innan den räknar eller listar meddelanden. Timermeddelanden och andra meddelanden till en körande process väntar också bland ankomsterna. - En process parkeras under exekutorlåset först efter en sekventiellt konsistent kontroll att ingen ankomst väntar; en tilläggning som hittar den parkerad tar exekutorlåset och väcker den.
- En avslutad process ankomster och ersatta tabellarrayer frigörs först när varje arbetstråd har passerat en tidsskivegräns efter att de tagits ur bruk, eller väntar på arbete (återvinning vid vila): en arbetstråd registrerar återvinningsepoken vid varje tidsskivegräns, och en sändning håller det den hittade endast inom sin tidsskiva.
- En sändning till sig själv går direkt till avsändarens egen signalinkorg.
Receive
receive väljer bland sina klausuler som case, över meddelandena i
brevlådan:
- Genomsökningen av brevlådan börjar vid det äldsta meddelandet. Varje
meddelande matchas mot klausulerna i ordning (mönster och guards, som kan
läsa bindningar från före
receive); det första meddelande som någon klausul matchar tas bort och den klausulens kropp körs. Meddelanden som ingen klausul matchar stannar i brevlådan i sin ordning; nästa receive börjar åter vid det äldsta meddelandet. - När varje meddelande har undersökts väntar processen
(
CLAUSE_wait_frame_v1, en inbyggd funktion som anropas som ett anrop): den lämnar körkön tills en sändning levererar ett meddelande till den, och sedan fortsätter genomsökningen med de meddelanden som har anlänt. Väntande processer behåller sina ramar och meddelanden som rötter för skräpsamlingen och samlar skräp när de återupptas (väntande processer). - Namn som binds i varje klausul, och i
after-kroppen när en sådan finns, exporteras efterreceive, som förcase; ett anrop i svansposition i en klausul eller iafter-kroppen är ett svansanrop, så en serverloop körs med konstant stack. after T -> Body:Tevalueras först, före genomsökningen. När receive skulle vänta måsteTvarainfinityeller ett heltal i 0..4294967295 (millisekunder), annarserror:timeout_value, varefter nästa receive söker från det äldsta meddelandet; ett meddelande som matchar direkt kontrollerar det aldrig, som i OTP.after 0körBodyså snart varje meddelande har undersökts. En ändlig tidsgräns startar när receive först väntar och startas inte om av meddelanden som inte matchar någon klausul; när den löper ut körsBodymed bindningarna från före receive och nästa receive söker från det äldsta meddelandet. Ett meddelande som anländer innan tidsgränsen löper ut tas. En receive med enbartafterär en sömn (idiomet förtimer:sleep/1).- Genererad kod: ett loophuvud tittar på nästa ej undersökta meddelande
(
CLAUSE_receive_v1peek, in i en rotplats), klausulvalet tar ett matchat meddelande (take) före dess kropp eller hoppar över ett omatchat (skip) och loopar; när inga meddelanden återstår går loopen in i väntan med tidsgränsen, som svarartrue(sök igen) ellerfalse(tidsgränsen löpte ut:restart, sedanafter-kroppen). - Exekutorn har en timer per väntande process med en ändlig tidsgräns i ett timerhjul (tidsgränser för receive): en timer som löpt ut köar processen igen. Tidsgränser mäts med en monoton klocka i millisekunder och utlöses aldrig för tidigt.
- När varje process väntar utan tidsgräns på ett meddelande som ingenting kan
skicka, väntar programmet för evigt, som OTP:s gör. Ett värdanrop
(
CLAUSE_invoke_v1) som skulle vänta misslyckas i stället medbusy: ingen annan process körs under det.
Länkar
En länk förbinder två processer i båda riktningarna (Signals i varje
kontext: de länkade pid:arna i länkordning och flaggan trap_exit).
link(Pid)länkar anroparen till en levande process och returnerartrue; att länka till sig själv eller igen gör ingenting. För en process som har avslutats kastar denerror:noproc, eller, när anroparen fångar exits, returnerartrueoch skickar{'EXIT', Pid, noproc}till anroparen, som OTP:s lokalalink/1gör.unlink(Pid)tar bort länken på båda sidor; länken har ingen verkan efter att anropet har returnerat.trueäven när det inte fanns någon länk.spawn_link/1,3länkar den nya processen till anroparen innan den körs.- När en process avslutas får varje länkad process en exitsignal med dess exitorsak (avslut) och länken försvinner. Länkade processer signaleras i den ordning länkarna skapades.
Monitorer
En monitor är enkelriktad: den övervakande processen håller den (via referens,
i Signals) och den övervakade processen behåller referensen och den
övervakande pid:en, så att den kan skicka meddelandet när den avslutas.
monitor(process, Pid)returnerar en ny referens. När processen avslutas får anroparen{'DOWN', Ref, process, Pid, Reason}med dess exitorsak (avslut); för en process som redan har avslutats får den meddelandet direkt med orsakennoproc. Att övervaka sig själv skapar ingenting. Varje anrop skapar en separat monitor med ett eget meddelande; meddelandena från en process skickas i den ordning monitorerna skapades.demonitor(Ref)stoppar monitorn: inget'DOWN'från den anländer därefter. Den returnerartrue, även för en referens som inte är en aktiv monitor hos anroparen.demonitor(Ref, Options):inforeturnerar om monitorn fortfarande var aktiv;flushtar bort det äldsta meddelandet{_, Ref, _, _, _}när den inte var det (dess'DOWN'ligger redan i brevlådan), som OTP gör.spawn_monitor/1,3returnerar{Pid, Ref}, med monitorn skapad innan den nya processen körs.- En process som avslutas släpper de monitorer den håller.
monitor(process, Name)ochmonitor(process, {Name, nonode@nohost})övervakar den process som är registrerad somName(noprocdirekt när det inte finns någon); dess'DOWN'anger{Name, nonode@nohost}i stället för pid:en.{Name, Node}för en annan nod gerbadarg.monitor(port, Port | Name)övervakar en port (portar):{'DOWN', Ref, port, Port, Reason}när den stängs. En pid förport, eller en port förprocess, gerbadarg.
Registrerade namn
Exekutorn har en tabell från namn (atomer) till pid:ar, och varje process sitt
eget namn (Signals::name).
register(Name, Pid)namnger en levande process:badargförundefined, ett namn som används, en process som redan har ett namn, en process som har avslutats, eller enPidsom inte är en pid. En process får registrera sig själv.unregister(Name)frigör namnet (badargnär ingen process har det);whereis(Name)är pid:en ellerundefined;registered()listar namnen i atomtabellens ordning (OTP:s ordning är också ospecificerad).- En process namn frigörs när den avslutas, innan dess länkar och monitorer
signaleras, så att en mottagare av
'DOWN'eller'EXIT'kan registrera namnet igen, som i OTP.
Processlexikon
put/2, get/0,1, get_keys/0,1 och erase/0,1 beter sig som OTP:s:
put/2 och erase/1 returnerar det tidigare värdet eller undefined,
erase/0 returnerar varje {Key, Value} och tömmer lexikonet, nycklar
matchas med exakt likhet (1 och 1.0 är två nycklar).
- Varje process har sitt eget lexikon; en startad process börjar tom.
- Poster är ord på processens heap som hålls i
ProcessDictionary(process_dictionary.hpp) och besöks som rötter för skräpsamlingen (rötter); de frigörs med processen. - Ordningen för
get/0ochget_keys/0,1är ospecificerad, som i OTP. Uppslagning söker linjärt igenom posterna; omedelbara nycklar jämförs per ord.put/2,get/1ocherase/1tar och returnerar postorden som de är, utan att godta någon term.
Timrar
start_timer/3,4 och send_after/3,4 (builtins/erlang/timers.cpp,
scheduler/timers.cpp) aktiverar en timer i exekutorns hjul (det som
tidsgränser för receive använder) som skickar Msg, eller
{timeout, TimerRef, Msg}, till en pid eller ett registrerat namn när den
utlöses.
- Meddelandet kopieras när timern startar till en
MessageBuffer(meddelandebuffertar), ett eget heapblock för timern, och kopieras igen till mottagarens heap när den utlöses, så som en sändning kopierar: vilken term som helst, även lokala funs, färdas oförändrad. - En mottagare som körs på en arbetstråd får meddelandet när dess tidsskiva tar slut. Ett registrerat namn slås upp när timern utlöses; ett namn som ingen har, eller en pid för en avslutad process, gör att meddelandet kastas. Timrar som skickas till en pid frigörs när den processen avslutas.
- Tid är relativa millisekunder i 0..2^49-1, eller med
{abs, true}en absoluterlang:monotonic_time(millisecond); allt annat gerbadarg. En tidsfrist bortom hjulets räckvidd aktiveras igen när den platsen kommer. cancel_timer/1,2ochread_timer/1,2returnerar återstående millisekunder ellerfalse;{async, true}returnerarokoch skickar{cancel_timer, Ref, Left}({read_timer, ...}),{info, false}returnerarokutan resultat.
Introspektion
process_info/1,2 (builtins/erlang/introspection.cpp,
scheduler/introspection.cpp) läser en annan process under exekutorns lås och
kopierar dess termer (meddelanden, lexikon) till anroparens heap; en process
som körs på en annan arbetstråd läses när dess tidsskiva tar slut. En pid utan
levande process ger undefined.
- Poster:
registered_name([]ensam när processen inte är registrerad),status(running,runnable,waiting),message_queue_len,messages,links,monitors,monitored_by,dictionary,trap_exit,group_leader,heap_size,total_heap_size,stack_size,memory(ord för heapen, dess fragment och binaries utanför heapen, samt stacken),reductions(0),priority(normal),error_handler,garbage_collection.process_info/1listar dem frånstatustillgarbage_collection. - OTP-poster som Clause inte håller (
current_function,initial_call,current_stacktrace, ...) gererror:{notsup, Item}; okända poster gerbadarg. processes/0listar levande pids i skapandeordning. En startad process ärver sin förälders group leader; den första processen leder sig själv.group_leader/2för en pid utan levande process gerbadarg.garbage_collect/0,1,2begär en skräpsamling vid målets nästa safepoint och returnerartrue(falsenär ingen levande process finns); med{async, RequestId}returnerar denasyncoch skickar{garbage_collect, RequestId, Result}.yield/0avslutar tidsskivan vid nästa funktionsingång.
Spawn-alternativ
Källor: builtins/erlang/spawning.cpp, scheduler/aliases.cpp.
spawn_opt/2..5tarlink,monitor,{monitor, MonitorOptions}och inställningsalternativen{priority, P},{fullsweep_after, N},{min_heap_size, N},{min_bin_vheap_size, N},{max_heap_size, S},{message_queue_data, M},{async_dist, B};{min_heap_size, N}sätter barnets minsta heap, de övriga inställningsalternativen kontrolleras och godtas, men tillämpas inte. En annan nod ännonode@nohostgerbadarg.spawn_request/1..5startar direkt och skickar{Tag, ReqId, ok, Pid}({Tag, ReqId, error, Reason}vid fel,badoptför ett ogiltigt alternativ) så som{reply_tag, Tag}och{reply, yes | no | error_only | success_only}begär; medmonitorär begärans id monitorreferensen.spawn_request_abandon/1returnerarfalse: svaret är redan skickat.hibernate(M, F, A)väntar tills brevlådan innehåller ett meddelande och anropar sedanM:F(A...)i stället för anropet; stacken behålls, så resultatet returneras till anroparen.
Alias
Ett alias är en referens som meddelanden kan skickas till (Alias ! Msg):
alias/0,1 (explicit_unalias, eller reply för ett meddelande), eller en
monitor skapad med {alias, explicit_unalias | demonitor | reply_demonitor}
till monitor/3 (demonitor upphör med monitorn, reply_demonitor avslutar
också monitorn vid dess första meddelande). unalias/1 avslutar ett alias hos
anroparen. En sändning till en referens som inte är ett aktivt alias, eller
vars ägare har avslutats, kastas. Ett svarsalias förbrukas först när dess
meddelande levereras, efter eventuell väntan på en upptagen ägare.
{tag, Tag} till monitor/3 ersätter 'DOWN' i monitormeddelandet;
portmonitorer tar inga alternativ.
Noder
Ett Clause-program är en nod som inte är distribuerad, nonode@nohost, och
svarar som en sådan OTP-nod (builtins/erlang/node.cpp): nodes/0 är [],
nodes(this | known) [nonode@nohost], andra typer []; nodes/2
ger {nonode@nohost, #{connection_id => undefined, node_type => this}} för de efterfrågade nycklarna. is_alive/0 är false,
monitor_node/2,3 ger error:notalive och disconnect_node/1 returnerar
ignored.
Exitsignaler
Varje exitsignal kommer från en körande process (exit/2, exit_signal/2,
link/1) eller från slutet av en process. Exekutorn hanterar den direkt när
dess mål inte körs på en annan arbetstråd, annars när målets tidsskiva har
tagit slut (arbetstrådar, scheduler/signals): ett avslutat mål
lämnar körkön eller sin väntan och slutförs (dess länkar signaleras, dess
felrapport skrivs, dess kontext frigörs) innan den sändande inbyggda
funktionen returnerar. En lång länkad kedja avslutas process för process utan
rekursion.
| Signal till en process | Fångar inte exits | Fångar exits |
|---|---|---|
exit(Pid, kill), exit_signal(Pid, kill) | Avslutas med orsaken killed | Avslutas med orsaken killed |
Orsaken normal (från en länk, eller skickad till en annan process) | Ingenting | Meddelandet {'EXIT', From, normal} |
exit(self(), normal) | Avslutas med orsaken normal (OTP:s egenhet) | Meddelandet {'EXIT', Self, normal} |
exit_signal(self(), normal) | Ingenting | Meddelandet {'EXIT', Self, normal} |
Varje annan orsak, inklusive kill från en länk | Avslutas med den orsaken | Meddelandet {'EXIT', From, Reason} |
process_flag(trap_exit, Bool)slår på eller av fångandet och returnerar den tidigare inställningen (från börjanfalse);process_flag(min_heap_size, N)sätter den minsta heapen från nästa skräpsamling och returnerar den tidigare.- En process som avslutas av en signal den skickat till sig själv
(
exit(self(), kill)) rullas upp förbi varjecatch,try-hanterare ochafter-kropp: signalen är inte ett undantag (CallError::exitedi felkanalen). exit/2ochexit_signal/2returnerartrue; till en process som har avslutats gör de ingenting. En referens som mål gör inte heller någonting, inte ens ett aktivt alias.- En exitsignal som avslutar huvudprocessen avslutar programmet som ett
ofångat
exit(avslutsstatus): orsakennormalavslutar med 0. - När mottagarens heap vägrar en exitorsak eller ett
'EXIT'-meddelande misslyckas mottagaren med ett runtime-fel (exit 70).
Portar
Portar specificeras i portar: en port är länkad till den som öppnade den, deltar i länkar, monitorer, exitsignaler och registrerade namn som en process och kommunicerar med sin anslutna process via meddelanden.
Suspendering av processer
erlang:suspend_process/1,2 och erlang:resume_process/1
(scheduler/suspension.cpp): varje suspendering är ett kvarhållande av målet i
exekutorn, så en suspenderad process körs igen först när varje suspendering
från varje suspenderare har återupptagits; meddelanden och signaler når den
fortfarande (en exitsignal avslutar den fortfarande), och
process_info(Pid, status) rapporterar suspended. När en suspenderare
avslutas återupptas dess suspenderingar. En synkron suspendering av en process
som körs på en annan arbetstråd väntar tills dess tidsskiva tar slut;
asynchronous returnerar direkt, {asynchronous, Tag} skickar också
{Tag, suspended} till anroparen, och unless_suspending svarar false när
anroparen redan suspenderar processen. Att suspendera eller återuppta
anroparen själv, en avslutad process, ett värde som inte är en pid eller med
felaktiga alternativ ger badarg, liksom att återuppta en process som
anroparen inte suspenderar.
Inbyggda funktioner
| Inbyggd funktion | Beteende |
|---|---|
spawn(Fun) | badarg om inte Fun är en fun; annars anropar en ny process Fun() och kastar {badarity, {Fun, []}} i den processen för en annan aritet |
spawn(M, F, Args) | badarg om inte M och F är atomer och Args en äkta lista; annars anropar en ny process M:F(Args...) och kastar undef i den processen när ingen modul exporterar den och ingen inbyggd funktion har det namnet |
spawn_link(Fun), spawn_link(M, F, Args) | Som spawn, och den nya processen länkas till anroparen (länkar) |
is_process_alive(Pid) | badarg om inte Pid är en pid; sant så länge dess process inte har avslutats |
spawn_monitor(Fun), spawn_monitor(M, F, Args) | Som spawn, och returnerar {Pid, Ref} för en ny monitor |
link(Pid), unlink(Pid) | badarg om inte Pid är en pid (länkar) |
monitor(process, Item) | badarg för en annan typ eller ett annat objekt; en referens (monitorer); Item är en pid eller ett registrerat namn |
register(Name, Pid), unregister(Name), whereis(Name), registered() | Se registrerade namn; Name måste vara en atom |
demonitor(Ref), demonitor(Ref, Options) | badarg om inte Ref är en referens och Options en äkta lista av flush och info |
exit(Dest, Reason), exit_signal(Dest, Reason) | badarg om inte Dest är en pid eller referens; true efter exitsignalen |
process_flag(trap_exit, Bool), process_flag(min_heap_size, N), process_flag(save_calls, N) | Den tidigare inställningen; badarg för en annan flagga, ett icke-booleskt värde eller en negativ storlek eller en storlek som inte är ett heltal |
erlang:send(Dest, Msg), Dest ! Msg | Msg, efter att det har skickats (meddelanden); send/2 importeras inte automatiskt |
spawn(Node, ...), spawn_link(Node, ...), spawn_monitor(Node, ...) (/2, /4) | Denna nod (nonode@nohost): som utan Node. En annan nod: OTP:s oanvändbara pid för en nod som inte är vid liv, en process som avslutas direkt med orsaken noconnection, så att en länk eller monitor rapporterar noconnection; badarg för en nod som inte är en atom |
erlang:send(Dest, Msg, Options) | ok, eller noconnect för ett meddelande till en annan nod med alternativet noconnect; alternativen nosuspend, noconnect, priority (ett vanligt meddelande) |
send_nosuspend(Dest, Msg), send_nosuspend(Dest, Msg, [noconnect]) | true; false för en annan nod med noconnect |
link(Pid, Options), exit(Dest, Reason, Options), exit_signal(Dest, Reason, Options) | Som utan alternativ; Options är [] eller [priority] (en vanlig signal) |
process_flag(Pid, save_calls, N) | Den tidigare inställningen för en annan process (0..10000); behålls, men Clause sparar inga anrop; andra flaggor ger badarg |
processes_iterator(), processes_next(Iter) | Iterera över de levande processerna: {Pid, Iter1} eller none; en process som startas under genomgången kan dyka upp |
bump_reductions(N) | true för ett icke-negativt heltal; Clause räknar inga reduktioner |
erlang:suspend_process(Pid), erlang:suspend_process(Pid, Options), erlang:resume_process(Pid) | Se suspendering av processer |
erlang:process_display(Pid, backtrace) | true efter att anropsstacken för den levande processen Pid skrivits på standard-fel, en Module:Function/Arity per rad, den aktuella funktionen först; badarg för en annan typ eller en process som har avslutats |
Den nya processen läggs sist i förälderns arbetstråds kö
(arbetstrådar); spawn returnerar dess pid direkt.
Clause