500 likes | 640 Views
Planen for idag. Synkronisering: Tidsafhængighed i multiprogrammer Semaforer: Binære semaforer Tælle semaforer … Grænseflader: Hvordan implementeres systemkald. Tidsafhængighed i multiprogrammer. proces læser { do { læslinie(indlinie); memcpy(udlinie, indlinie, 80);
E N D
Planen for idag • Synkronisering: • Tidsafhængighed i multiprogrammer • Semaforer: • Binære semaforer • Tælle semaforer • … • Grænseflader: • Hvordan implementeres systemkald Datalogi 1F: Multiprogrammering[2]
Tidsafhængighed i multiprogrammer proces læser { do { læslinie(indlinie); memcpy(udlinie, indlinie, 80); } while(TRUE); } Inddata: rødbeder snabelsko Uddata: rødbeder snabelsko snabelsko snabelsko ……… Uddata: rødbelsko snabelsko snabelsko snabelsko ……… Uddata: snabelsko snabelsko snabelsko snabelsko ………… proces skriver { do { udskriv(udlinie); } while(TRUE); } Datalogi 1F: Multiprogrammering[2]
item nextProduced; while (1) { while (counter == BUFFER_SIZE) yield(); /* do nothing */ buffer[in] = nextProduced; in = (in + 1) % BUFFER_SIZE; counter++; } item nextConsumed; while (1) { while (counter == 0) yield(); /* do nothing */ nextConsumed = buffer[out]; out = (out + 1) % BUFFER_SIZE; counter--; } Producent-konsument:nu med tæller Datalogi 1F: Multiprogrammering[2]
Opdatering af delt lager • Ændringerne af counter skal ske udeleligt (uden afbrydelser) • Kaldes også atomisk • counter opdatering optræder som én operation på højniveau sprogniveau • MEN ikke nødvendigvis i den eksekverbare kode Datalogi 1F: Multiprogrammering[2]
Tælleropdateringer på assemblerniveau • “counter--” kan være implementeret som: register1 = counterregister1 = register1 – 1counter = register1 • “counter++” kan være implementeret som:register2 = counter register2 = register2 + 1counter = register2 • Ved processkift kan de to operationer sammenflettes Datalogi 1F: Multiprogrammering[2]
Sammenfletning af tælleropdateringer • Antag at counter har værdien 5. En sammenfletning af assemblerinstruktionerne for producent og konsument kunne være:konsument: register1 = counter (register1 = 5)konsument: register1 = register1 – 1 (register1 = 4)producent: register2 = counter (register2 = 5)producent: register2 = register2 + 1 (register2 = 6)producent: counter = register2 (counter = 6)konsument: counter = register1 (counter = 4) • Værdien af count kan være enten 4, 5 eller 6, men den tiltænkte værdi er 5. Datalogi 1F: Multiprogrammering[2]
Datakapløb • Datakapløb opstår, når resultatet af et multiprogram afhænger af afviklingsrækkefølgen af processerne i multiprogrammet • Opdateringer til delt lager skal foregå udeleligt: • Kritisk region sikrer det • Men det kan også være nødvendigt at synkronisere udførselshastigheden af de forskellige processer: • eks:.: snabelsko, snabelsko, snabelsko Datalogi 1F: Multiprogrammering[2]
Semaforer • Processer kommunikerer ved at sende signaler til hinanden • Dijkstra foreslog semaforer: • Variable der tæller antallet af gange et signal er sendt men ikke modtaget (den optræder som buffer) • Operationen signaler(semafor) der sender et signal til semafor • Operationen vent(semafor), der venter på et signal (hvis intet signal er bufret, sættes processen til at vente) • Buffer- og ventemekanismerne gør synkroniseringen tidsuafhængig Datalogi 1F: Multiprogrammering[2]
Semaforer: forhold • Semaforer skal udføres udeleligt: • Atomiske maskinkodeoperationer: • test and set • Implementeret i kerne: • Beskyttet mod afbrydelser (swpipl) • Aktiv venten kan undgås idet en proces kan suspenderes mens den venter • FIFO ventemekanisme kan forhindre udsultning Datalogi 1F: Multiprogrammering[2]
Forskellige slags semaforer • I dag findes et utal af semafortyper: • Binære semaforer • Tællesemaforer (Dijkstra’s oprindelige ide) • Beskedsemaforer • Postkassesemaforer • Trafiklyssemaforer Datalogi 1F: Multiprogrammering[2]
Class BinærSem { enum Tilstand {åben, låst} tilstand; kø prockø; int ventende; public: void BinærSem(Tilstand t=åben) { tilstand = t; ventende = 0; } void vent(); void signaler(); }; Binær semafor: tilstande Datalogi 1F: Multiprogrammering[2]
void BinærSem::vent() { if(tilstand==åben) tilstand=låst; else { ventende++; <blokér proces>; } } void BinærSem::signaler() { if(tilstand==låst) if(ventende > 0) { <aktiver proces>; ventende--; } else tilstand=åben; } Binære semafore: operationer Datalogi 1F: Multiprogrammering[2]
Binære semaforer:anvendelse • Sikring af udelelig adgang til delt data: • Binær semafor hedder ofte MUTEX (mutual exclusion) • Som eksempel: læser og skriver processerne fra slide 1 Datalogi 1F: Multiprogrammering[2]
proces læser { do { læslinie(indlinie); vent(skrevet); memcpy(udlinie, indlinie, 80); signaler(læst); } while(TRUE); } proces skriver { do { vent(læst); udskriv(udlinie); signaler(skrevet); } while(TRUE); } skriver læser Binær semafor: eksempel klar skriver læser læser læst skrevet Datalogi 1F: Multiprogrammering[2]
Tællesemafor: tilstand class TælleSem { int tæller; kø prockø; int ventende; public: void TælleSem(int c) { tæller = c; ventende = 0; } void vent(); void signaler(); }; Datalogi 1F: Multiprogrammering[2]
void TælleSem::vent() { if(tæller > 0) tæller--; else { ventende++; <bloker proces>; } } void TælleSem::signaler() { if(ventende > 0) { <aktiver proces>; ventende--; } else tæller++; } Tællesemafor: operationer Datalogi 1F: Multiprogrammering[2]
Tællesemafor: anvendelse • Administration af en samling ens ressourcer: • Frekvensbånd ved trådløs transmission • Jobskedulering på klyngecomputer • Uddeling af buffere • Begrænsning af antallet af aktive processer i en region: • Begrænsning af multiprogrammeringsgraden i en applikation Datalogi 1F: Multiprogrammering[2]
Beskedsemafor: tilstand class BeskedSem { kø bufkø; kø prockø; int ventende; public: void BeskedSem() { ventende = 0; } buf *vent(); void signaler(buf *); }; Datalogi 1F: Multiprogrammering[2]
buf *BeskesSem::vent() { if(!bufkø.tom()) return bufkø.frigiv(); else { ventende++; <bloker proces>; } } void BeskedSem::signaler(buf *buffer) { if(ventende > 0) { aflever(buf); <aktiver proces>; ventende--; } else bufkø.tilkø(buf); } Beskedsemafor: operationer Datalogi 1F: Multiprogrammering[2]
Beskedsemafor: anvendelse • Udveksling af data mellem processer, f.eks. producent-konsument forhold: • To beskedsemaforer: • FRIE: indeholder frie elementer • FULDE: indeholder fulde elementer • Producent: • Venter på frie elementer og signalerer med fulde elementer • Konsument: • Venter på fulde og signalerer med frie Datalogi 1F: Multiprogrammering[2]
process læser { do { lbuf = FRIE.vent(); læslinie(*lbuf); FULDE.signaler(lbuf); } while(TRUE); } process skriver { do { sbuf = FULDE.vent(); udskriv(*sbuf); FRIE.signaler(sbuf); } while(TRUE); } buf buf buf buf buf buf Producent-konsument for(i=0; i < N; i++) { nbuf = alloker(sizeof(buf)); FRIE.signaler(nbuf); } læser FRIE FULDE skriver Datalogi 1F: Multiprogrammering[2]
Postkassesemafor: tilstand class PostkasseSem { kø prockø; int ventende; public: void PostkasseSem() { ventende = 0; } void vent(); void signaler(); }; Datalogi 1F: Multiprogrammering[2]
void PostkasseSem::vent() { ventende++; <bloker proces>; } void PostkasseSem::signaler() { while (ventende > 0) { <aktiver proces>; ventende--; } } Postkassesemafor: operationer Datalogi 1F: Multiprogrammering[2]
Postkassesemafor: anvendelse • En proces kan give en gruppe processer besked om at en betingelse er opfyldt: • Der er kommet en afbrydelse fra uret • Delt data er blevet opdateret: • Check om tidsstempel er det samme som sidste gang • Hvis ja, vent på opdatering • Uafhængig af antallet af ventende processer Datalogi 1F: Multiprogrammering[2]
Trafiklyssemafor: tilstand class TrafiklysSem { enum Farve {rød, grøn} farve; kø prockø; int ventende; public: void TrafiklysSem (Farve startfarve=grøn) { farve = startfarve; ventende = 0; } void vent(); void start(); void stop(); }; Datalogi 1F: Multiprogrammering[2]
void TrafiklysSem::vent() { if(farve==rød) { ventende++; <bloker proces>; } } void TrafiklysSem::start() { farve=grøn; while(ventende > 0) { <aktiver proces>; ventende--; } } Trafiklyssemafor:operationer void TrafiklysSem::stop() { farve=rød; }
Trafiklyssemafor: anvendelse • Signal om at en proces/ressource er i en bestemt tilstand: • Lavprioritetsprocesser har adgang til netværk udenfor spidsbelastningstidspunkter • Timerstyret proces starter og stopper • Lavprioritetsprocesser venter Datalogi 1F: Multiprogrammering[2]
Valg af semafortype • Vi har set at de forskellige semafortyper egner sig til forskellige opgaver • Skal en kerne understøtte alle semafortyper? • Ikke nødvendigvis: • Simpel kerne = færre fejl • En given semafor kan bruges til at konstruere andre semaforer med (dvs. en semafortype er nok) Datalogi 1F: Multiprogrammering[2]
Tællesemafor ud fra binær semafor ? Datalogi 1F: Multiprogrammering[2]
Tællesemafor: tilstand class TælleSem { int tæller; kø prockø; int ventende; public: void TælleSem(int c) { tæller = c; ventende = 0; } void vent(); void signaler(); }; Datalogi 1F: Multiprogrammering[2]
void TælleSem::vent() { if(tæller > 0) tæller--; else { ventende++; <bloker proces>; } } void TælleSem::signaler() { if(ventende > 0) { <aktiver proces>; ventende--; } else tæller++; } Tællesemafor: operationer Datalogi 1F: Multiprogrammering[2]
Tællesemafor ud fra binær semafor • Ide: • Vi skal bruge en kø af ventende processer: • Dette er allerede understøttet af binære semaforer • Hvordan ved vi hvor mange signaler, der ikke er modtaget? • Vi skal bruge en tæller • Tælleren skal opdateres udeleligt: • vi har brug for en mutex semafor • Hvordan ser vent og signaler så ud? Datalogi 1F: Multiprogrammering[2]
void TælleSem::vent() { MUTEX.vent(); if(tæller > 0) tæller--; else { ventende++; KØ.vent(); } MUTEX.signaler(); } void TælleSem::signaler() { MUTEX.vent() if(ventende > 0) { KØ.signaler(); ventende--; } else tæller++; MUTEX.signaler(); } Tællesemafor: 1. forsøg Datalogi 1F: Multiprogrammering[2]
void TælleSem::vent() { MUTEX.vent(); if(tæller > 0) { tæller--; MUTEX.signaler(); } else { ventende++; MUTEX.signaler(); KØ.vent(); } } void TælleSem::signaler() { MUTEX.vent() if(ventende > 0) { KØ.signaler(); ventende--; } else tæller++; MUTEX.signaler(); } Tællesemafor: 2. forsøg Datalogi 1F: Multiprogrammering[2]
void TælleSem::vent() { KØ.vent(); MUTEX.vent(); tæller--; if(tæller <> 0) KØ.signaler(); MUTEX.signaler(); } void TælleSem::signaler() { MUTEX.vent(); if(tæller == 0) KØ.signaler(); tæller++; MUTEX.signaler(); } Tællesemafor: operationer Datalogi 1F: Multiprogrammering[2]
Grænseflader til kernen • Kernekald • Parameteroverførsel • Repræsentation af ressourcer Datalogi 1F: Multiprogrammering[2]
Kernekald • Et brugerprogram ønsker at kalde kernefunktionen signal(semafor) • Hvilken adresse specificeres i den eksekverbare kode i brugerprogrammet? • Applikationer og kerne udvikles typisk uafhængigt af hinanden Datalogi 1F: Multiprogrammering[2]
Statisk lænkning • Kerne og brugerprogrammer oversættes hver for sig, men lænkes sammen inden brug: • Kerne og brugerprogrammer startes som et samlet hele • Kan f.eks. bruges i indlejrede systemer: • Mobiltelefoner • Vaskemaskiner • Netværksroutere • Kernekald er blot alm. procedurekald == lave omkostninger Datalogi 1F: Multiprogrammering[2]
Dynamisk lænkning • Oversættelse af kernen resulterer i en symboltabel, der senere kan anvendes ved oversættelse/lænkning af brugerprogrammer: • Brugerprogrammer skal genlænkes ved ændringer i kernen • Dynamic Link Libraries (DLL’er): • Kald sker via en stubprocedure, der finder den rigtige adresse på køretidspunktet • Stubprocedurer kan evt. overskrives Datalogi 1F: Multiprogrammering[2]
Faste, absolutte adresser • Hvert kernekald har en fast defineret adresse, der er specificeret i f.eks. en headerfil: • Besværligt at arbejde med for kerneprogrammører Datalogi 1F: Multiprogrammering[2]
Indirekte kernekald • De absolutte adresser gemmes i en tabel • Kernekaldene foretages ved først at slå op i tabellen for at finde adressen på et kernekald: • Tabellens adresse er fast • Indeks i tabel er kernekaldets identifikation Datalogi 1F: Multiprogrammering[2]
Maskinelstøttede systemkald • I det foregående er det antaget lager er delt mellem kerne og brugerprogrammer • Dette er sjældent tilfældet: • Kernen beskyttes via separat adresserum • Systemkald via speciel maskininstruktion, der samtidig skifter privilegieniveau: • PAL kaldetcall_pal PAL_callsys på alphaerne • Fungerer typisk som indirekte kernekald, altså via en hoptabel Datalogi 1F: Multiprogrammering[2]
Speficikation af handler: lda a0, syscallHandler lda a1, 5 call_pal PAL_wrent Foretag et systemkald: lda a0, CALLSYS_WRITE call_pal PAL_callsys Specifikation af hoptabel: enum SysCallId { CALLSYS_WRITE, CALLSYS_READ}; Void (*jumpTable[]) () = { write, read }; Handler: Void syscallHandler (SysCallId id) { (*jumpTable[id])()} Alpha eksempel Datalogi 1F: Multiprogrammering[2]
Parameteroverførsel • Parametre overføres via: • registre (at foretrække): • Alphaerne bruger a0 – a5 • eksplicit i programkoden: • parametrene placeres i den eksekverbare kode efter kernekaldet • Returadressen skal ændres til at være første instruktion efter parametrene • Systemkald indkapsles i køretidsbiblioteker, der bl.a. håndterer typecheck: void writechar(char ch){ callsys (CALLSYS_WRITE, ch); } Datalogi 1F: Multiprogrammering[2]
Parameteroverførsel på Alpha’erne line: .asciiz ”Skriv mig ud!” .... lda a0, CALLSYS_WRITE lda a1, line call_pal callsys .... Datalogi 1F: Multiprogrammering[2]
Køretidsbiblioteker • Systemkald indkapsles i køretidsbib-lioteker, der bl.a. håndterer typecheck: callsys: call_pal PAL_callsys ret (ra) unsigned long callsys (SysCallId ...); void writechar(char ch) { callsys (SYS_WRITE, ch); } Datalogi 1F: Multiprogrammering[2]
Kerneressourcer vs. brugerressourcer • Ved kernekald kan brugerprogrammer overgive brugerressourcer til kernen: • Reference til buffer, der skal udskrives (en adresse i brugerprogrammets hukommelse og en længde) • Men kernekald opererer også på systemressourcer, fx: åbne filer, semaforer • Disse systemressourcer skal beskyttes af kernen, og kan derfor ikke placeres i brugerprogrammernes hukommelse • Hvordan repræsenteres disse i brugerprogrammet? Datalogi 1F: Multiprogrammering[2]
Håndtag til systemressourcer • Når et brugerprogram reserverer/opretter/får adgang til en systemressource, modtager den en nøgle (eng.: handle) • Ved efterfølgende brug af ressourcen præsenteres kernen for nøglen som identifikation • Afbildningen af nøgler til ressourcer sker per proces, dvs. man kan ikke gætte en anden proces’ nøgler • Nøgleafbildningen er typisk kædet sammen med proces kontrolblokken • Nøglen er typisk et heltal Datalogi 1F: Multiprogrammering[2]
Opsummering • Synkronisering af multiprogrammer: • Udelelige operationer • Forskel på højniveau operationer og lavniveau • Semaforer • Generelt synkroniseringsmekanisme • Ingen aktiv venten • Kernegrænseflade: • Hvordan implementeres systemkald Datalogi 1F: Multiprogrammering[2]
Kilder • Disse slides er baseret på indholdet af Datalogi 1F kursusbøgerne samt ”Operating System Concepts” 6. udgave Datalogi 1F: Multiprogrammering[2]