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 { læslinie(indlinie); memcpy(udlinie, indlinie, 80); while(true); proces skriver { udskriv(udlinie); while(true); Inddata: rødbeder Uddata: rødbeder Uddata: Uddata: rødbelsko 1 2 Producent-konsument: nu med tæller item nextproduced; while (1) { while (counter == BUFFER_SIZE) yield(); /* do nothing */ fer[in] = nextproduced; in = (in + 1) % BUFFER_SIZE; counter++; item nextconsumed; while (1) { while (counter == 0) yield(); /* do nothing */ nextconsumed = fer[out]; out = (out + 1) % BUFFER_SIZE; counter--; 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 3 4 Tælleropdateringer på assemblerniveau counter-- kan være implementeret som: register1 = counter register1 = register1 1 counter = register1 counter++ kan være implementeret som: register2 = counter register2 = register2 + 1 counter = register2 Ved processkift kan de to operationer sammenflettes 5 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. 6 1
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:.:,, 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 fer) Operationen signaler(semafor) der sender et signal til semafor Operationen vent(semafor), der venter på et signal (hvis intet signal er ret, sættes processen til at vente) Buffer- og ventemekanismerne gør synkroniseringen tidsuafhængig 7 8 Semaforer: forhold Forskellige slags semaforer 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 I dag findes et utal af semafortyper: Binære semaforer Tællesemaforer (Dijkstra s oprindelige ide) Beskedsemaforer Postkassesemaforer Trafiklyssemaforer 9 10 Binær semafor: tilstande Class BinærSem { enum Tilstand {åben, låst tilstand; void BinærSem(Tilstand t=åben) { tilstand = t; void signaler(); ; Binære semafore: operationer void BinærSem::vent() { if(tilstand==åben) tilstand=låst; <blokér proces>; void BinærSem::signaler() { if(tilstand==låst) else tilstand=åben; 11 12 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 Binær semafor: eksempel proces læser { læslinie(indlinie); vent(skrevet); memcpy(udlinie, indlinie, 80); signaler(læst); while(true); proces skriver { vent(læst); udskriv(udlinie); signaler(skrevet); while(true); skriver læser læser skriver læser klar læst skrevet 13 14 Tællesemafor: tilstand class TælleSem { int tæller; void TælleSem(int c) { tæller = c; void signaler(); ; Tællesemafor: operationer if(tæller > 0) else 15 16 Tællesemafor: anvendelse Administration af en samling ens ressourcer: Frekvensbånd ved trådløs transmission Jobskedulering på klyngecomputer Uddeling af fere Begrænsning af antallet af aktive processer i en region: Begrænsning af multiprogrammeringsgraden i en applikation Beskedsemafor: tilstand class BeskedSem { kø kø; void BeskedSem() { *vent(); void signaler( *); ; 17 18 3
Beskedsemafor: operationer void BeskedSem::signaler( *fer) { aflever(); else kø.tilkø(); *BeskesSem::vent() { if(!kø.tom()) return kø.frigiv(); 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 19 20 Producent- for(i=0; process læser i < N; { i++) { n = alloker(sizeof()); FRIE.signaler(n); l = FRIE.vent(); læslinie(*l); FULDE.signaler(l); while(true); process skriver { s = FULDE.vent(); udskriv(*s); FRIE.signaler(s); while(true); konsument FULDE læser skriver FRIE Postkassesemafor: tilstand class PostkasseSem { void PostkasseSem() { void signaler(); ; 21 22 Postkassesemafor: operationer void PostkasseSem::vent() { void PostkasseSem::signaler() { while (ventende > 0) { 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 23 24 4
Trafiklyssemafor: tilstand class TrafiklysSem { enum Farve {rød, grøn farve; void TrafiklysSem (Farve startfarve=grøn) { farve = startfarve; void start(); void stop(); ; 25 Trafiklyssemafor:operationer void TrafiklysSem::vent() { if(farve==rød) { void TrafiklysSem::start() { farve=grøn; while(ventende > 0) { void TrafiklysSem::stop() { farve=rød; 26 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 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) 27 28 Tællesemafor ud fra binær semafor? Tællesemafor: tilstand class TælleSem { int tæller; void TælleSem(int c) { tæller = c; void signaler(); ; 29 30 5
Tællesemafor: operationer if(tæller > 0) else 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? 31 32 Tællesemafor: 1. forsøg Tællesemafor: 2. forsøg MUTEX.vent(); if(tæller > 0) KØ.vent(); MUTEX.vent() KØ.signaler(); else MUTEX.vent(); if(tæller > 0) { KØ.vent(); MUTEX.vent() KØ.signaler(); else 33 34 Tællesemafor: operationer Grænseflader til kernen KØ.vent(); MUTEX.vent(); if(tæller <> 0) KØ.signaler(); MUTEX.vent(); if(tæller == 0) KØ.signaler(); Kernekald Parameteroverførsel Repræsentation af ressourcer 35 36 6
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 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 37 38 Dynamisk lænkning Faste, absolutte adresser 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 Hvert kernekald har en fast defineret adresse, der er specificeret i f.eks. en headerfil: Besværligt at arbejde med for kerneprogrammører 39 40 Indirekte kernekald Maskinelstøttede systemkald 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 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 kaldet call_pal PAL_callsys på alphaerne Fungerer typisk som indirekte kernekald, altså via en hoptabel 41 42 7
Speficikation af handler: lda a0, syscallhandler lda a1, 5 call_pal PAL_wrent Foretag et systemkald: lda a0, CALLSYS_WRITE call_pal PAL_callsys Alpha eksempel Specifikation af hoptabel: enum SysCallId { CALLSYS_WRITE, CALLSYS_READ; Void (*jumptable[]) () = { write, read ; Handler: Void syscallhandler (SysCallId id) { (*jumptable[id])() 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); 43 44 Parameteroverførsel på Alpha erne line:.asciiz Skriv mig ud!... lda a0, CALLSYS_WRITE lda a1, line call_pal callsys... Køretidsbiblioteker Systemkald indkapsles i køretidsbiblioteker, 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); 45 46 Kerneressourcer vs. brugerressourcer Ved kernekald kan brugerprogrammer overgive brugerressourcer til kernen: Reference til fer, 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? 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 47 48 8
Opsummering Synkronisering af multiprogrammer: Udelelige operationer Forskel på højniveau operationer og lavniveau Semaforer Generelt synkroniseringsmekanisme Ingen aktiv venten Kernegrænseflade: Hvordan implementeres systemkald Kilder Disse slides er baseret på indholdet af Datalogi 1F kursusbøgerne samt Operating System Concepts 6. udgave 49 50 9