Operativsystemer: Tre nemme stykker. Del 3: Process API (oversættelse)

Introduktion til operativsystemer

Hej Habr! Jeg vil gerne henlede din opmærksomhed på en række artikler-oversættelser af en interessant litteratur efter min mening - OSTEP. Dette materiale diskuterer ganske dybt arbejdet med unix-lignende operativsystemer, nemlig arbejde med processer, forskellige skemalæggere, hukommelse og andre lignende komponenter, der udgør et moderne OS. Du kan se originalen af ​​alle materialer her her. Bemærk venligst, at oversættelsen er lavet uprofessionelt (ganske frit), men jeg håber, at jeg har bevaret den generelle betydning.

Laboratoriearbejde om dette emne kan findes her:

Andre dele:

Du kan også tjekke min kanal på telegram =)

Alarm! Der er et laboratorium til dette foredrag! Se github

Proces API

Lad os se på et eksempel på at skabe en proces i et UNIX-system. Det sker gennem to systemkald gaffel() и exec().

Call fork()

Operativsystemer: Tre nemme stykker. Del 3: Process API (oversættelse)

Overvej et program, der laver et fork()-kald. Resultatet af dens udførelse vil være som følger.

Operativsystemer: Tre nemme stykker. Del 3: Process API (oversættelse)

Først og fremmest går vi ind i main()-funktionen og udskriver strengen til skærmen. Linjen indeholder procesidentifikationen, som i originalen kaldes PID eller procesidentifikator. Denne identifikator bruges i UNIX til at henvise til en proces. Den næste kommando kalder fork(). På dette tidspunkt oprettes en næsten nøjagtig kopi af processen. For operativsystemet ser det ud til, at der kører 2 kopier af det samme program på systemet, som igen vil afslutte fork()-funktionen. Den nyoprettede underordnede proces (i forhold til den overordnede proces, der oprettede den) vil ikke længere blive udført, startende fra funktionen main(). Det skal huskes, at en underordnet proces ikke er en nøjagtig kopi af den overordnede proces; i særdeleshed har den sit eget adresseområde, sine egne registre, sin egen pointer til eksekverbare instruktioner og lignende. Således vil den værdi, der returneres til kalderen af ​​fork()-funktionen, være anderledes. Især vil forældreprocessen modtage PID-værdien af ​​den underordnede proces som en retur, og barnet vil modtage en værdi lig med 0. Ved hjælp af disse returkoder kan du så adskille processer og tvinge hver af dem til at udføre sit eget arbejde . Udførelsen af ​​dette program er dog ikke nøje defineret. Efter opdeling i 2 processer begynder operativsystemet at overvåge dem samt planlægge deres arbejde. Hvis den udføres på en enkeltkerneprocessor, vil en af ​​processerne, i dette tilfælde forælderen, fortsætte med at arbejde, og derefter vil den underordnede proces modtage kontrol. Ved genstart kan situationen være anderledes.

Vent opkald()

Operativsystemer: Tre nemme stykker. Del 3: Process API (oversættelse)

Overvej følgende program. I dette program, på grund af tilstedeværelsen af ​​et opkald vente() Forældreprocessen vil altid vente på, at den underordnede proces er fuldført. I dette tilfælde vil vi få et strengt defineret tekstoutput på skærmen

Operativsystemer: Tre nemme stykker. Del 3: Process API (oversættelse)

exec() opkald

Operativsystemer: Tre nemme stykker. Del 3: Process API (oversættelse)

Overvej udfordringen exec(). Dette systemkald er nyttigt, når vi ønsker at køre et helt andet program. Her vil vi ringe execvp() at køre wc-programmet, som er et ordtælleprogram. Hvad sker der, når exec() kaldes? Dette kald videregives navnet på den eksekverbare fil og nogle parametre som argumenter. Hvorefter koden og statiske data fra denne eksekverbare fil indlæses og dets eget segment med koden overskrives. De resterende hukommelsesområder, såsom stakken og heapen, geninitialiseres. Hvorefter OS simpelthen udfører programmet og sender det et sæt argumenter. Så vi lavede ikke en ny proces, vi forvandlede blot det program, der kører i øjeblikket, til et andet kørende program. Efter at have udført exec()-kaldet i efterkommeren, ser det ud som om det originale program slet ikke kørte.

Denne opstartskomplikation er helt normal for en Unix-shell og tillader denne shell at udføre kode efter opkald gaffel(), men før opkaldet exec(). Et eksempel på en sådan kode ville være at justere shell-miljøet til behovene for det program, der lanceres, før det lanceres.

Shell - bare et brugerprogram. Hun viser dig invitationslinjen og venter på, at du skriver noget i den. I de fleste tilfælde, hvis du skriver navnet på et program der, vil skallen finde sin placering, kalde fork()-metoden og derefter kalde en type exec() for at oprette en ny proces og vente på, at den er fuldført ved hjælp af en wait() opkald. Når den underordnede proces afsluttes, vender skallen tilbage fra wait()-kaldet og udskriver prompten igen og venter på, at den næste kommando indtastes.

Fork() & exec() splittet tillader skallen at gøre følgende ting, for eksempel:
wc fil > ny_fil.

I dette eksempel bliver outputtet fra wc-programmet omdirigeret til en fil. Måden, hvorpå skallen opnår dette, er ret simpel - ved at oprette en underordnet proces, før du ringer exec(), lukker skallen standardoutput og åbner filen ny_fil, således alt output fra det videre kørende program wc vil blive omdirigeret til en fil i stedet for en skærm.

Unix rør er implementeret på en lignende måde, med den forskel, at de bruger et pipe()-kald. I dette tilfælde vil processens outputstrøm blive forbundet med en pipe-kø placeret i kernen, hvortil inputstrømmen fra en anden proces vil blive forbundet.

Kilde: www.habr.com

Tilføj en kommentar