INF3140/4140: Monitorer Uke 6, side 1.
Monitor Programmoduler med mer struktur enn semaforer Monitorer er en mekanisme for data-abstraksjon Data i monitor er innkapslet og manipuleres vha. monitorprosedyrer Inneholder variable som beskriver tilstanden Variable kan endres kun gjennom tilgjengelige prosedyrer Implisitt mutex! Betingelsessynkronisering gitt ved betingelsesvariable Uke 6, side 2.
Bruk Har aktive prosesser og passive monitorer Alle felles variable for prosessene inne i monitor Prosessene kommuniserer bare ved å kalle monitorprosedyrer Prosessene trenger ikke kjenne alle implementasjonsdetaljer Bare synlig effekt av kallet er viktig Implementasjonen kan endres hvis synlig effekt er den samme Gjør at monitorer og prosesser kan utvikles relativt uavhengig Lettere å forstå og utvikle parallelle programmer Uke 6, side 3.
Syntaks & semantikk monitor name { monitor variable initialisering prosedyrer # felles programvariable # for monitorens prosedyrer En monitor er en instans av en abstrakt datatype: Bare prosedyrenavn er synlige fra utsiden av monitoren: call name.opname(argumenter) Programsetninger inne i en monitor har ikke tilgang til programvariable utenfort monitoren. Monitorvariable blir initialisert før monitoren taes i bruk En monitorinvariant benyttes til å beskrive monitorens indre tilstander. Uke 6, side 4.
Mutex implisitt i monitorer I monitorer er mutex gitt implisitt i implementasjonen av språket En prosedyre er aktiv hvis en programsetning i prosedyren eksekveres av en eller annen prosess Maksimalt én instans av en monitorprosedyre kan være aktiv om gangen Innebærer at vi er garantert interferens-frihet for monitorprosedyrer Programmereren trenger ikke benytte noen ad hoc metode for mutex. På lavere abstraksjonsnivå kan monitorer implementeres vha. låser eller semaforer. Uke 6, side 5.
Condition variable Monitorer har en spesiell type variabel: cond (condition) Brukes til å oppholde prosesser Hver slik variabel assosieres med en ventebetingelse I realiteten har condition-variabelen ingen annen verdi en køen på ventebetingelsen Verdien til variabelen er ikke tilgjengelig for programmereren I stedet kan den manipuleres vha. spesielle operasjoner. cond cv; # deklarerer conditionvariabel cv empty (cv); # spør om køen på cv er tom wait (cv); # får prosessen til å vente på køen til cv signal (cv); # vekker en prosess på køen til cv signal all (cv); # vekker alle prosessene på køen til cv Uke 6, side 6.
Signalleringsdisipliner Et signal på en conditionvariabelcv har følgende effekt: tom kø: ingen effekt prosessen som ligger først i ventekøen tilcv vekkes wait ogsignal utgjør en FIFO signalleringsstrategi Når en prosess utførersignal(cv) er den inne i monitor. Hvis en ventende prosess vekkes, vil det dermed være to aktive prosesser i monitor. Det fins to løsninger som gir mutex: Signal and Wait: Signallør venter til siden, og den signallerte prosessen får eksekvere med en gang Signal and Continue: Signallør fortsetter og den signallerte prosessen eksekverer senere Uke 6, side 7.
Implementasjon av semafor monitor Semafor { # monitorinvariant: s>=0 int s = 0; # semaforens verdi cond pos; # ventebetingelsen procedure Psem() { while (s==0) wait(pos); s = s-1; procedure Vsem() { s=s+1; signal(pos); Uke 6, side 8.
FIFO semafor FIFO semafor med SC signallering kan oppnås ved eksplisitt overførsel av kontrollen internt i monitoren (sende betingelsen videre). monitor FIFO semafor { # monitorinvariant: s>=0 int s = 0; # semaforens verdi cond pos; # signalleres bare når s>0 procedure Psem() { if (s==0) wait(pos); else s = s-1; procedure Vsem() { if empty(pos) s=s+1; else signal(pos); Uke 6, side 9.
Eksempel: Begrenset buffer synkronisering (1) Vi har en buffer av størrelse n. En produsent utførerput-operasjoner på bufferet En konsument utførerget-operasjoner på bufferet Vi bruker en variabelcount til å telle antall elementer i bufferet put-operasjoner må vente hvis bufferet er fullt get-operasjoner må vente hvis bufferet er tomt Uke 6, side 10.
Eksempel: Begrenset buffer synkronisering (2) Når en prosess er vekket går den tilbake til monitorens inngangskø Kjemper med andre prosesser om tilgangen til monitoren Vilkårlig delay fra vekking til eksekvering starter opp Må derfor teste på ventebetingelsen igjen når eksekvering starter Eks: put-prosess vekkes når bufferet er ikke-fullt. Andre prosesser kan gjøreput-operasjoner før prosessen som er vekket starter opp Må derfor forsikre seg igjen om at bufferet ikke er fullt Uke 6, side 11.
Eksempel: Begrenset buffer synkronisering (3) monitor Bounded Buffer { typet buf[n]; int count = 0; cond not full, not empty; procedure put(typet data){ while (count == n) wait(not full); # Legg element inn i buf count = count + 1; signal(not empty); procedure get (typet &result) { while (count == 0) wait(not empty); # Hent element fra buf count = count - 1; signal(not full); Uke 6, side 12.
Monitorløsning på leser og skriver problemet (1) Problembeskrivelse Leser- og skriverprosesser deler en felles ressurs (database). Leseres transaksjoner kan lese informasjon fra DB Skriveres transaksjoner kan lese og oppdatere informasjon i DB Antar at DB er initielt konsistent og at hver transaksjon isolert sett vedlikeholder konsistens. For å unngå interferens mellom transaksjonene, krever vi at Skrivere har eksklusiv tilgang til DB. når ingen skriver har tilgang, kan et vilkårlig antall lesere utføre sine transaksjoner samtidig. Uke 6, side 13.
Monitorløsning på leser og skriver problemet (2) Databasen kan ikke innkapsles i en monitor, for da får ikke lesere felles adgang. Monitoren brukes i stedet til å tildele adgang til prosesser Baserer oss på at prosessene ikke går inn i kritisk region (DB) før de har passertrw Controller monitoren. Monitorprosedyrer request read: ber om leseradgang. release read: leser forlater KR. request write: ber om skriveradgang. release write: skriver forlater KR. Uke 6, side 14.
Monitorløsning på leser og skriver problemet (3) Monitorinvariant Anta at vi har to tellere som lokale variable i monitor: nr nw antallet lesere antallet skrivere Synkroniseringskravet kan formuleres som: RW: (nr == 0 nw == 0) nw <= 1 Vi ønsker atrw skal være en monitorinvariant Strategi for monitoren La to condition-variableoktoread ogoktowrite regulere henholdsvis ventende lesere og ventende skrivere. Uke 6, side 15.
Monitorløsning på leser og skriver problemet (4) monitor RW_Controller { int nr = 0, nw = 0; ## RW: (nr == 0 OR nw == 0) AND nw <= 1 cond oktoread; # signaled when nw == 0 cond oktowrite; # signaled when nr == 0 and nw == 0 procedure request_read() { while (nw > 0) wait(oktoread); nr = nr + 1; procedure release_read() { nr = nr - 1; if (nr == 0) signal(oktowrite); # awaken one writer procedure request_write() {... procedure release_write() {... Uke 6, side 16.
Monitorløsning på leser og skriver problemet (5) monitor RW_Controller { int nr = 0, nw = 0; ## RW: (nr == 0 OR nw == 0) AND nw <= 1 cond oktoread; # signaled when nw == 0 cond oktowrite; # signaled when nr == 0 and nw == 0 procedure request_read() {... procedure release_read() {... procedure request_write() { while (nr > 0 nw > 0) wait(oktowrite); nw = nw + 1; procedure release_write() { nw = nw - 1; signal(oktowrite); # awaken one writer and signal_all(oktoread); # all readers Uke 6, side 17.
Invariant Monitorinvariant (I) brukes til å beskrive monitorens indre tilstand Uttrykke relasjon mellom monitorvariablene Må holde etter initialisering Må holde når en prosedyre avsluttes Må holde idet vi slipper kontrollen p.g.a. kall tilwait Kan da anta at invarianten holder etter wait og når en prosedyre starter Bør være så sterk som mulig! Uke 6, side 18.
Aksiomer for Signal and Continue (1) Anta at monitorinvarianten I og predikatet P ikke omtalercv. Da kan vi sette opp følgende aksiomer: {I wait(cv) {I {P signal(cv) {P, for vilkårlig P {P signal all(cv) {P, for vilkårlig P Hva om predikatene omtaler køen tilcv? Uke 6, side 19.
Aksiomer for Signal and Continue (2) Anta at invarianten kan omtale antall prosesser til køen på en condition variabel. La#cv være antall prosesser som venter på køen tilcv. Testenempty(cv) er da identisk med #cv == 0 wait(cv) modelleres som en utvidelse av køen etterfulgt av prosessor-slipp: wait(cv) : {I #cv (#cv+1) #cv = #cv +1;{Isleep{I signal(cv) kan modelleres som reduksjon av køen: {((#cv == 0) P) ((#cv 0) P #cv (#cv 1) ) if (#cv! = 0) #cv = #cv 1 {P signal all(cv) modelleres som en løkke avsignal(cv) Uke 6, side 20.
Aksiomer for Signal and Continue (3) Tilsammen gir dette: {I #cv (#cv+1) wait(cv){i {((#cv == 0) P) ((#cv 0) P #cv (#cv 1) )signal(cv){p {P signal all(cv){p #cv == 0 Dersom vi vet at #cv 0 idet vi signalerer, så kan aksiomet for signal(cv) forenkles til {P #cv (#cv 1) signal(cv){p Uke 6, side 21.
Monitorløsning på leser og skriver problemet (6) Verifikasjon av invarianten overrequest read I : (nr == 0 nw == 0) nw 1 procedure request read() { {I while (nw > 0) { {I nw > 0 {I wait(oktoread); {I {I nw == 0 nr = nr + 1; {I Uke 6, side 22.
Tidstjener Monitor med prosedyre som muliggjør soving i en gitt tid Ressurs: en logisk klokke (tod) Tilbyr to operasjoner: delay(interval) kaller ønsker å sove iinterval klokketikk tick øker den logiske klokken med ett tikk Kalles av hardware, gjerne med høy eksekveringsprioritet Hver prosess som kallerdelay regner ut sin egen tid for oppvåkning: wake time = tod + interval; Venter så lengetod < wake time Ventebetingelsen er avhengig av lokale variable Covering condition: Alle prosessene vekkes når det er mulig at noen kan forsette Hver prosess sjekker sin betingelse og sovner igjen hvis denne ikke holder Uke 6, side 23.
Tidstjener: Covering condition Invariant: CLOCK : tod 0 tod øker monotont med 1 monitor Timer { int tod = 0; # Time Of Day cond check; # signaleres når tod er øket procedure delay(int interval) { int wake_time; wake_time = tod + interval; while (wake_time > tod) wait(check); procedure tick() { tod = tod + 1; signal_all(check); Lite effektivt hvis mange prosesser skal vente lenge Kan gi mange falske alarmer Uke 6, side 24.
Prioritert venting Kan også gi tilleggsargument tilwait: wait(cv, rank) Prosessen venter på køen tilcv ordnet i stigende rekkefølge etter argumentetrank. Vedsignal: Prosessen med lavest verdi avrank vekkes først. Kall tilminrank(cv) returnererrank-verdien til den første prosessen på køen (med lavest rank). Køen endres ikke (ingen prosesser vekkes) Kan brukes til å implementere korteste-jobb allokering (seksjon 5.2.3) Kan også brukes til å effektivisere monitorentimer Uke 6, side 25.
Tidstjener: Prioritert vent Bruker prioritert venting til å ordne prosessene påcheck Prosesser vekkes bare nårtod >= wake time Trenger derfor ikkewhile-loop idelay monitor Timer { int tod = 0; # Invariant: CLOCK cond check; # signalert når minrank(check) <= tod procedure delay(int interval) { int wake_time; wake_time = tod + interval; if (wake_time > tod) wait(check, wake_time); procedure tick() { tod = tod + 1; while (!empty(check) && minrank(check) <= tod) signal(check); Uke 6, side 26.
Den sovende barberer (1) Vi ser på en barbersalong med to dører og noen stoler. Kunder kommer inn gjennom en dør og går ut gjennom den andre. I barbersalongen kan bare én kunde bevege seg om gangen Når det ikke er kunder, sover barbereren i en av stolene. Når det kommer en kunde og barbereren sover, blir barbereren vekket og kunden setter seg i barberstolen. Hvis barbereren er opptatt, setter kunden seg til å sove i en av de andre stolene. Når kunden er betjent, slipper barbereren ham ut gjennom utgangsdøren. Hvis det er ventende kunder, blir en av disse vekket. Ellers sovner barbereren igjen. Uke 6, side 27.
Den sovende barberer (2) Denne aktiviteten modelleres ved følgende monitorprosedyrer: get haircut: kalles av kunde, returnerer når klipping er ferdig get next customer: kalles av barbereren for å betjene en kunde finish haircut: kalles av barbereren for å slippe en kunde ut av frisørsalongen Rendezvous Et rendezvous ligner på en to-prosess barriere: Begge parter må ankomme før noen kan fortsette. Barbereren må vente på en kunde Kunden må vente på at barbereren er ledig. Barbereren kan ha rendezvous med en vilkårlig kunde. Uke 6, side 28.
Den sovende barberer (3) Vi bruker 3 tellere til å synkronisere prosessene: barber, chair ogopen Vi programmerer slik at disse tre variablene veksler mellom 0 og 1. barber == 1 : barbereren er klar for ny kunde chair == 1: kunden sitter i stolen, barbereren har ikke begynt å jobbe open == 1 : utgangsdøren er åpnet, kunden har ikke rukket å gå ut. Uke 6, side 29.
Den sovende barberer (4) Synkronisering av prosessene Det er fire forskjellige synkroniseringsbetingelser: kunden må vente på at barbereren er ledig kunden må vente på at barbereren åpner utgangsdøren barbereren må vente på at en kunde setter seg i stolen barbereren må vente på at en kunde forlater salongen Prosessene signallerer når en av ventebetingelsene er oppfylt. Uke 6, side 30.
Den sovende barberer (5) monitor Barber_Shop { int barber = 0, chair = 0, open = 0; cond barber_available; # signaleres når barber > 0 cond chair_occupied; # signaleres når chair > 0 cond door_open; # signaleres når open > 0 cond customer_left; # signaleres når open == 0 procedure get_haircut() {... procedure get_next_customer() {... procedure finished_cut() {... Uke 6, side 31.
Den sovende barberer (6) procedure get_haircut() { while (barber == 0) wait(barber_available); barber = barber - 1; chair = chair + 1; signal(chair_occupied); while (open == 0) wait(door_open); open = open -1; signal(customer_left); procedure get_next_customer() { barber = barber + 1; signal(barber_available); while (chair == 0) wait(chair_occupied); chair = chair - 1; procedure finished_cut() { open = open + 1; signal(door_open); while (open > 0) wait(customer_left); Uke 6, side 32.