Operativsystemer: Tre enkle stykker. Del 3: Process API (oversettelse)

Introduksjon til operativsystemer

Hei Habr! Jeg vil gjerne gjøre deg oppmerksom på en serie artikler-oversettelser av en interessant litteratur etter min mening - OSTEP. Dette materialet diskuterer ganske dypt arbeidet til unix-lignende operativsystemer, nemlig arbeid med prosesser, ulike planleggere, minne og andre lignende komponenter som utgjør et moderne OS. Du kan se originalen av alt materiale her her. Vær oppmerksom på at oversettelsen ble gjort uprofesjonelt (ganske fritt), men jeg håper jeg beholdt den generelle betydningen.

Laboratoriearbeid om dette emnet finner du her:

Andre deler:

Du kan også sjekke kanalen min på telegram =)

Alarm! Det er en lab for denne forelesningen! Se github

Prosess API

La oss se på et eksempel på å lage en prosess i et UNIX-system. Det skjer gjennom to systemanrop gaffel() и utføre ().

Call fork()

Operativsystemer: Tre enkle stykker. Del 3: Process API (oversettelse)

Tenk på et program som gjør et fork()-kall. Resultatet av dens utførelse vil være som følger.

Operativsystemer: Tre enkle stykker. Del 3: Process API (oversettelse)

Først av alt går vi inn i hoved()-funksjonen og skriver ut strengen til skjermen. Linjen inneholder prosessidentifikatoren som i originalen kalles PID eller prosessidentifikator. Denne identifikatoren brukes i UNIX for å referere til en prosess. Den neste kommandoen vil kalle fork(). På dette tidspunktet opprettes en nesten nøyaktig kopi av prosessen. For operativsystemet ser det ut til at det er 2 kopier av det samme programmet som kjører på systemet, som igjen vil avslutte fork()-funksjonen. Den nyopprettede underordnede prosessen (i forhold til den overordnede prosessen som opprettet den) vil ikke lenger bli utført, fra hoved()-funksjonen. Det bør huskes at en underordnet prosess ikke er en eksakt kopi av den overordnede prosessen; spesielt har den sitt eget adresseområde, sine egne registre, sin egen peker til kjørbare instruksjoner og lignende. Dermed vil verdien som returneres til den som ringer fork()-funksjonen være annerledes. Spesielt vil den overordnede prosessen motta PID-verdien til den underordnede prosessen som en retur, og barnet vil motta en verdi lik 0. Ved å bruke disse returkodene kan du deretter skille prosesser og tvinge hver av dem til å gjøre sitt eget arbeid . Imidlertid er utførelsen av dette programmet ikke strengt definert. Etter å ha delt inn i 2 prosesser, begynner operativsystemet å overvåke dem, samt planlegge arbeidet deres. Hvis den utføres på en enkeltkjerneprosessor, vil en av prosessene, i dette tilfellet overordnet, fortsette å fungere, og deretter vil den underordnede prosessen få kontroll. Ved omstart kan situasjonen være annerledes.

Ring vente()

Operativsystemer: Tre enkle stykker. Del 3: Process API (oversettelse)

Tenk på følgende program. I dette programmet, på grunn av tilstedeværelsen av en samtale vente() Foreldreprosessen vil alltid vente på at den underordnede prosessen skal fullføres. I dette tilfellet vil vi få en strengt definert tekstutgang på skjermen

Operativsystemer: Tre enkle stykker. Del 3: Process API (oversettelse)

exec() kall

Operativsystemer: Tre enkle stykker. Del 3: Process API (oversettelse)

Vurder utfordringen utføre (). Dette systemkallet er nyttig når vi ønsker å kjøre et helt annet program. Her skal vi ringe execvp() å kjøre wc-programmet som er et ordtellingsprogram. Hva skjer når exec() kalles? Dette kallet sendes navnet på den kjørbare filen og noen parametere som argumenter. Deretter lastes koden og statiske data fra denne kjørbare filen og dets eget segment med koden overskrives. De gjenværende minneområdene, for eksempel stabelen og haugen, initialiseres på nytt. Deretter kjører OS ganske enkelt programmet og sender det et sett med argumenter. Så vi opprettet ikke en ny prosess, vi forvandlet ganske enkelt programmet som kjører for øyeblikket til et annet program som kjører. Etter å ha utført exec()-kallet i etterkommeren, ser det ut som om det opprinnelige programmet ikke kjørte i det hele tatt.

Denne oppstartskomplikasjonen er helt normal for et Unix-skall, og lar dette skallet kjøre kode etter å ha ringt gaffel(), men før samtalen utføre (). Et eksempel på slik kode vil være å justere skallmiljøet til behovene til programmet som lanseres, før det lanseres.

Shell - bare et brukerprogram. Hun viser deg invitasjonslinjen og venter på at du skal skrive noe i den. I de fleste tilfeller, hvis du skriver navnet på et program der, vil skallet finne sin plassering, kalle fork()-metoden, og deretter kalle en type exec() for å lage en ny prosess og vente til den fullføres med en wait() kall. Når den underordnede prosessen avsluttes, vil skallet returnere fra wait()-kallet og skrive ut ledeteksten på nytt og vente på at neste kommando legges inn.

Fork() & exec() splittet lar skallet gjøre følgende ting, for eksempel:
wc-fil > ny_fil.

I dette eksemplet blir utdataene fra wc-programmet omdirigert til en fil. Måten skallet oppnår dette på er ganske enkel - ved å lage en barneprosess før du ringer utføre (), lukker skallet standardutdata og åpner filen ny_fil, dermed all utgang fra det videre kjørende programmet wc vil bli omdirigert til en fil i stedet for en skjerm.

Unix rør implementeres på lignende måte, med den forskjellen at de bruker et pipe()-kall. I dette tilfellet vil prosessens utgangsstrøm kobles til en rørkø som ligger i kjernen, som inngangsstrømmen til en annen prosess vil bli koblet til.

Kilde: www.habr.com

Legg til en kommentar