Mandatory Assignment 1 Morten Franck Peter Hansen 9. oktober 2003 Gruppe 4, Parallelle Systemer (02220)
Indhold 1 Trin 1 Petri Net 1 1.1 Model af pass().................................... 1 1.2 Model af close().................................... 1 1.3 Model af open().................................... 1 1.4 Undgåelse af race conditions............................ 2 2 Trin 2 2 2.1 Undgåelse af unødig venten............................. 5 2.2 Beskyttelse af tælle-variable............................. 6 2.3 Udsultning....................................... 6 3 Trin 3 7 3.1 Beskrivelse af semaforløsning............................ 7 3.2 Implementering af barriere............................. 8 3.2.1 Bil nr. 0..................................... 8 4 Trin 4 8 4.1 Trin 2a Skitsering af monitorløsning....................... 9 4.2 Trin 2b Skitsering af monitorløsning....................... 9 4.3 Trin 3 Vurdering................................... 10 4.4 Barriere implementeret vha. Java-monitor..................... 10 5 Afprøvning 11 5.1 Trin 2a......................................... 11 5.2 Trin 2b.1........................................ 11 5.3 Trin 2b.2........................................ 11 5.4 Trin 3.......................................... 11 5.5 Trin 4.......................................... 11 6 Konklusion 12 A Trin 2b Skitse af monitorløsning 13 B CarControl2a.java 13 C CarTest2a.java 16 D CarControl2b.java 17 E CarTest2b.java 20 F CarControl3.java 21 G CarTest3.java 26 H CarControl4.java 27 I CarTest4.java 32
Introduktion Denne rapport svarer på trin 1-4 i opgaven Mandatory Assignment 1 stillet i kurset Concurrent Systems (02220) på DTU efterår 2003. Rapporten er inddelt i fem dele. Trin 1 er en Petri Net-model af samspillet mellem en port og en bil. Trin 2 er en semaforløsning af problemet med kritiske sektioner, hvis tre egenskaber er: ingen sammenstød mellem biler, ingen baglås (deadlock) og ingen unødig venten. Trin 3 implementerer en barriere, der skal sørge for at ingen biler kører mere end én omgang mere end nogen anden bil. Trin 4 implementerer denne barriere vha. en Javamonitor. Afsnit 5 afprøver implementeringerne af trin 2-4. Koden til implementeringerne kan findes i bilag B til I. 1 Trin 1 Petri Net I det følgende modelleres gennem brug af Petri Net, hvordan en port (gate) fungerer, samt hvordan en en bil passerer gennem en port. Modellen af dette system ses i figur 1. 1.1 Model af pass() Modellen viser, hvorledes bilen kun kan passere porten, når der er en token tilgængelig i g-semaforen. Når g-semaforen bruges til at lukke systemet, er den ikke tilgængelig for pass(), og dermed kan bilen ikke passere porten. Når open() kaldes, lægges en token i g- semaforen, pass() kan dermed køres og bilen passere porten. I figur 2 og 3 ses detaljerne i hvordan close- og open-transitionerne fungerer. For både close() og open() gælder det, at de kan kaldes uanset hvilken tilstand systemet er i, dvs. uanset om porten er åben eller lukket. 1.2 Model af close() Denne model viser de tilstande og transitioner systemet gennemgår ved kald til close(). Når close()-transitionen bliver fyret, går systemet over i en tilstand, hvor én af to ting kan ske, afhængigt af om porten på det pågældende tidspunkt er åben eller lukket: Hvis den allerede er lukket, vil der ikke være en isopen token, og den venstre transition i figuren vil blive fyret. Systemet går da over i den lukkede tilstand. Hvis porten er åben, vil der være en isopen token, og systemet vil gå over i en tilstand, hvor det venter på en token i g-semaforen. Derefter vil systemet gå over i en lukket tilstand. Det ses ud fra Figur 3, at denne token kun vil være tilgængelig, når systemet går fra en lukket til en åben tilstand. 1.3 Model af open() Denne model viser de transitioner og tilstande systemet gennemgår, når open() kaldes. Ligesom i modellen for close, går systemet først over i en tilstand hvor én af to ting kan ske, afhængigt af om porten er åben eller lukket. 1
Hvis porten allerede er åben, er der en isopen-token tilgængelig, og venstre transition kan fyres. Systemet går derefter over i en åben tilstand. Hvis porten er lukket, vil der ikke være en isopen-token, og højre transition vil blive fyret. Dette resulterer i, at der forgrenes ud, således at der lægges en token i g til rådighed og systemet går over i åben tilstand. 1.4 Undgåelse af race conditions Det er vigtigt, at open() og close() vist nedenfor kaldes af kun én kontroltråd. public void open() if (!isopen) g.v(); isopen = true; public void close() if (isopen) try g.p(); catch (InterruptedException e) isopen = false; Hvis der eksempelvis er to tråde, der kalder open() og den første tråd læser værdien af isopen og bliver afbrudt, hvorefter den anden tråd læser isopen men desuden når at lægge en token i g-semaforen og sætte isopen til true, vil den første tråd, når den får lov at køre igen, se isopen som værende false og derefter lægge endnu en token i g, hvilket er en race condition. Når close()-metoden kaldes er det meningen, at kontroltråden skal tage tokenen i g, således, at en bil, der kalder pass og dermed forsøger at snuppe tokenen i g, vil blive tvunget til at vente på g. Men, da der i ovenstående eksempel er blevet lagt to tokener i g, er resultatet, at når bilen passerer porten, tæller den antallet af tokener ned til én (og ikke nul), og denne vil derfor få lov at fortsætte forbi porten. Fordi pass()-metoden også selv lægger en token i g, vil antallet af tokener altid variere mellem et og to (og ikke et og nul), og bilen vil derfor aldrig holde ved porten. Hvis der er to eller flere kontroltråde, der skal kalde open() og close(), skal man sørge for at gøre kaldet til disse til en kritisk sektion. Dette kan eksempelvis gøres vha. enten semaforer eller monitorer og vil sørge for, at man undgår race conditions. 2 Trin 2 På dette stadium er situationen som beskrevet i opgaveteksten: bilerne er blevet opgraderet til batteridrevne biler. Deres høje pris gør, at det skal sikres, at to eller flere biler ikke støder sammen noget sted på banen. Dette resulterer i følgende invariant: I 1 : To forskellige biler optager ikke det samme felt på banen samtidig. 2
I det følgende vil det blive beskrevet, hvorledes denne invariant sikres i nærværende implementering. Invarianten I 1 sikres ved hjælp af semaforer. Det gøres ved at lave hver af de 10 12 felter, banen består af, til en kritisk sektion, således at kun én bil ad gangen får adgang til et givet felt 1. Specifikt implementeres en binær semafor for hvert felt, således at når en bil ønsker adgang til det næste felt på sin rute, kaldes P()-operationen på dette felts semafor, og når en bil har forladt et felt og opnået adgang til et nyt felt, kalder den V()-operationen på det felt den tidligere stod på. Det antages, at den udleverede semafor-klasse fungerer efter hensigten og dermed er i stand til at sikre eksklusiv adgang til en ressource (et felt). I det følgende kodeuddrag er cfs af typen Semaphore[][], således at hvert felt på banen har sin egen semafor, som beskrevet ovenfor. Det ses dermed ud af koden, at hver bil venter på adgang til den kritiske sektion (det næste felt på ruten) og derefter forlader sit nuværende felt og optager det næste felt før semaforen på det nuværende felt opgives: cfs[newpos.row][newpos.col].p(); cd.leave(curpos); cd.occupy(newpos,col,no); cfs[curpos.row][curpos.col].v(); På denne måde sikres det, at en bil er flyttet til sit næste felt før en eventuelt efterfølgende bil får adgang til feltet, og de to biler kan dermed ikke støde sammen. Dermed er I 1 sikret. Ydermere skal det gælde, at der ikke må opstå baglås (deadlock) noget sted på banen. Det bemærkes, at hvis to biler kører i modsat retning af hinanden samtidig i den kritiske sektion, vil der i dette (og kun dette) tilfælde opstå baglås i systemet. Dette er en uheldig bivirkning ved indførelsen af semaforer til forhindring af sammenstød. Der er kun én bane til rådighed, og da to biler, der kører i hver sin retning bag huset, ikke kan støde sammen, men heller ikke passere hinanden, venter de begge for evigt på adgang til det næste felt. 1 Det bemærkes, at felterne, der udgør huset samt felterne til højre for huset, hvor bilerne har deres egen bane, ikke behøves at gøres til kritiske sektioner, men alligvel er blevet det for nemheds skyld. åben tilstand g pass() close() lukket tilstand open() Figur 1: Petri Net-model af pass(), hvor open() og close() indgår som dele af systemet. I dette tilfælde er der en token tilgængelig i g-semaforen, og bilen kan derfor passere porten. 3
close()!isopen open() isopen P() g isopen!isopen isopen lukket tilstand g åben tilstand Figur 2: Petri Net-model af close() i det tilfælde hvor porten er i åben tilstand. Fordi der i dette tilfælde er en token i både isopen og g, vil porten gå fra en åben til en lukket tilstand. Figur 3: Petri Net-model af open() i det tilfælde hvor porten allerede er åben. 4
Dette fører frem til en sikkerhedsegenskab (safety property) udtrykt ved følgende invariant: I 2 : Der opstår ikke baglås i systemet. Til at sikre I 2, indføres en ny semafor, kaldet BehindHouse, som styrer adgangen til felterne bag huset, som dermed bliver endnu en kritisk sektion på banen. Når en af bilernes næste felt (givet ved newpos()) er lig med koordinaterne for et af de første felter i den kritiske sektion, kaldes P()-operationen på den BehindHouse, som giver adgang til sektionen bag huset. Dette sikrer, at to biler der kører i modsat retning af hinanden ikke mødes bag huset. Da BehindHouse er initialiseret til værdien 1, vil kun den første bil få adgang til den kritiske sektion og efterfølgende biler vil derfor vente på BehindHouse. Dette sikrer I 2, men indfører unødig venten. 2.1 Undgåelse af unødig venten Det bør være sådan, at hvis en eller flere biler venter på adgang til den kritiske sektion bag huset, og der allerede kører en eller flere biler i samme retning som dem der venter, skal de ventende biler have adgang med det samme, således at der ikke opstår unødig venten. Til at muliggøre dette, indføres to tællere, der holder styr på hvor mange biler der kører i hver retning. Lad disse tællere være kaldet InnerCounter for biler der kører mod uret, og OuterCounter for de biler, der kører med uret. Indgangsprotokollen (entry protocol) til den kritiske sektion kan skitseres således: < OuterCounter++; if (OuterCounter == 1) BehindHouse.P(); > hvor < og > omkranser en atomar operation implementeret med en semafor, Outer- CounterLock og InnerCounterLock, for hver af de to tælle-variable. Ovenstående kode udføres af alle biler som kører med uret, og tilsvarende udfører alle biler, der kører mod uret det samme, hvor OuterCounter erstattes med InnerCounter. Protokollen sikrer, at en bil atomart (vha. de to semaforer beskrevet ovenfor) tæller sin retnings tælle-variabel én op. Hvis denne variabel efter optællingen har værdien 1, betyder det, at den pågældende bil er den første i den retning, der ønsker adgang til den kritiske sektion bag huset; den skal derfor kalde P()-operationen på BehindHouse og dermed evt. vente på at få adgang til den kritiske sektion, fordi der kan være modkørende biler. Hvis dette ikke er tilfældet, kører bilen ind i den kritiske sektion. Ifald der er flere biler i samme retning, der prøver at få adgang til den kritiske sektion, tæller disse også tælle-variablen én op, men kalder ikke P()-operationen på BehindHouse, fordi der allerede er en der venter på den (eller allerede har fået den). I kraft af I 1 er det sikret, at alle biler, der kommer efter den bil der kalder P()-operationen, ikke støder ind i hinanden, men venter i kø indtil der gives den kritiske sektion bag huset. Tilsvarende følger alle biler følgende udgangsprotokol (exit protocol), når de forlader den kritiske sektion: < OuterCounter--; if (OuterCounter == 0) BehindHouse.V(); > Der opnås således først adgang til den kritiske sektion for modsatkørende biler (ved frigivelse af BehindHouse-semaforen), når den sidste bil i den anden retning kører ud af den kritiske sektion. På dette tidspunkt er den pågældende tælle-variabel 0, og den første 5
held-by CounterLock CounterLock.P() (waits-for) Bil Y Bil X BehindHouse.P() (waits-for) BehindHouse held-by Figur 4: Illustration af baglås som kan opstå, hvis der kun bruges en enkelt semafor til atomar op- og nedtælling af tælle-variable. bil i modsat retning den som har kaldt P()-operationen på BehindHouse får nu adgang til den kritiske sektion. Under forudsætning af, at der ikke må opstå baglås, er der altså ingen unødige ventetider. 2.2 Beskyttelse af tælle-variable Det bemærkes, at der skal bruges to semaforer til at styre tilgang til de to tælle-variable (InnerCounter og OuterCounter). Hvis der kun var én semafor (CounterLock) til at styre tilgang til disse variable, kunne man komme i en situation, hvor BehindHouse-semaforen var i brug af en bil i den kritiske sektion. Når denne bil skulle forlade den kritiske sektion og derfor tælle antallet af biler én ned, ville den komme til at vente på CounterLock. Denne semafor kunne være i brug af en bil på vej ind i den kritiske sektion, og bilen på vej ind ville komme til at vente på BehindHouse-semaforen. Dermed ville der være opstået en baglås (se figur 4). For at undgå baglås i forbindelse med opdatering af tælle-variable, skal følgende invariant holde: I 3 : To biler der kører i hver sin retning vil ikke forsøge at kalde P()-operationen på samme semafor. Invariant I 3 sikres ved at indføre en semafor for hver tælle-variabel, der dermed sikrer, at en bil i én retning ikke kan holde en semafor, som en bil i den anden retning kan komme til at vente på. 2.3 Udsultning I nærværende implementering eksisterer der en (teoretisk) mulighed for, at bilerne der kører i den ene retning vil blive udsultet når de prøver at køre om bag huset. Dette sker 6
i det tilfælde, hvor der på alle tidspunkter er mindst én bil bag huset som kører i modsat retning af dem der står og venter på at få lov til at køre. Disse betragtninger reflekteres i koden af, at den bil der kalder P()-operationen på semaforen BehindHouse (den første bil i køen) aldrig kommer videre; med andre ord, at V()-operationen aldrig bliver kaldt af nogen af bilerne, fordi der altid vil være mindst én bil bag huset (tælleren InnerCounter eller OuterCounter bliver aldrig 0). En mulig løsning er at indføre to tællere, som tæller hvor mange biler, der holder i kø i hver retning. Når en bil forsøger at køre om bag huset, undersøger den værdien af den anden retnings tæller. Hvis denne er tilstrækkeligt stor, skal bilen vente og lade den anden retnings biler køre. Denne teknik minder om måden Andrews 2 beskriver en fair løsning på Readers and Writers -problemet. 3 Trin 3 For at sikre, at alle børn kører det samme antal omgange på legepladsen, indføres en barriere. Først når alle biler er nået til barrieren, får de biler, der stod og ventede ved barrieren, lov at fortsætte. Dette kan udtrykkes ved følgende invariant: I 4 : 0 x 1, hvor x er forskellen i antallet af omgange mellem et hvilket som helst par af biler. Barrieren kan slås til og fra som ønsket. Hvis der er biler, der venter ved barrieren, og denne deaktiveres, får disse biler lov at fortsætte. 3.1 Beskrivelse af semaforløsning Til at implementere denne form for betingelsessynkronisering (condition synchronization) bruges semaforer. Teknikken, der bruges, minder om passing the baton-teknikken, hvor processer, når de er færdige med at eksekvere i den kritiske sektion, signalerer (rækker stafetten til) en anden proces, der dermed bliver vækket på den betingelse, som denne ventede på og herefter får lov at eksekvere eksklusivt i den kritiske sektion. I dette tilfælde er der to kritiske sektioner og en barriere, der skal sikre betingelsessynkronisering: 1. At tælle antallet af biler én op eller ned skal ske atomart og er derfor en kritisk sektion for at sikre imod race conditions hvor der går en opdatering af tælleren tabt. 2. Ligeledes er dét at give stafetten videre til den næste bil en kritisk sektion, da man derved kan sikre, at alle biler får stafetten, før nogen bil får lov at køre videre. Til at styre adgang til disse to kritiske sektioner knyttes semaforen mutex. Semaforen er binær og initialiseres til værdien 1 for at angive, at der er én ressource til rådighed som udgangspunkt. For at få bilerne til at vente ved barrieren, laves semaforen barrier. Da bilerne som udgangspunkt skal vente ved barrieren, hvis denne er slået til, initialiseres denne til værdien 0. Når alle biler er ankommet ved barrieren skal de én efter én frigive hinanden (give stafetten videre) for til sidst at forlade barrieren samtidigt. 2 Foundations of Multithreaded, Parallel, and Distributed Programming, s. 177 7
3.2 Implementering af barriere Når en bil ankommer ved barrieren, det vil sige, når bilens newpos-koordinater svarer til barrierens position, tælles først tælleren DelayedCars atomart (vha mutex) én op. Herefter undersøges det, hvilken type bil, der lige er ankommet. Der findes to typer: den sidste bil og de otte første. Hvis bilen er en af de otte første, udfører den en P()-operation på barriersemaforen, hvilket får bilen til at vente på denne semafor (og dermed vente ved barrieren). Ovenstående sker for de første otte biler. Når den niende bil ankommer og værdien af DelayedCars er 9, skal alle bilerne have lov at køre. Først skal det dog sikres, at ingen biler når at køre mere end én omgang mere end nogen anden bil. Dette gælder specielt for bil nr. 0, som er så hurtig og hvis bane er så lille, at den, hvis man ikke sikrede sig mod dette, ville køre to omgange og dermed fejlagtigt ville nå barrieren igen, vente ved denne og blive frigivet endnu engang, før en af de sidste almindelige biler ville have nået at blive frigivet bare én gang. Måden ovenstående undgåes på er, at gøre dét at give kontrollen (stafetten) videre til den næste bil til en kritisk sektion. Dette betyder altså, at så længe der er en bil i gang med at give stafetten videre til en anden bil, er der ingen biler, der får lov at køre, før den sidste har fået stafetten. Bil nr. 9 udfører en P()-operation på mutex, tæller antallet af ventende biler én ned og udfører endelig en V()-operation på barrier, hvilket svarer til at give stafetten videre til en af de ventende biler. Dermed vil der være én ressource til rådighed i barrier-semaforen, og næste gang en af de ventende bil-processer skeduleres til at køre, vil denne kunne bruge ressourcen og dermed få lov at fortsætte. Denne bil tæller nu DelayedCars én ned og giver selv stafetten videre til en anden ventende bil ved at udføre en V()-operation på barrier. Den sidste bil, der frigives, ser at der ikke er flere biler, der venter, og frigiver dermed låsen på mutex-semaforen, hvilket indikerer at alle biler er færdige ved barrieren, og næste runde kan begynde. 3.2.1 Bil nr. 0 Fordi den samme semafor, mutex, bruges til at beskytte begge kritiske sektioner (op-/nedtælling samt videregivning af stafetten), vil bil nr. 0, når den er nået barrieren anden gang, ikke kunne opnå eksklusiv adgang til at tælle antallet af ventende biler én op. Bil nr. 9 sørgede netop for at ressourcen i mutex er i brug så længe at bilerne er i gang med at give stafetten videre. Dermed vil bil nr. 0 vente, når den forsøger at udføre sin anden P()-operation på mutex, hvilket giver den ønskede effekt af, at ingen bil kører mere end én omgang mere end nogen anden. Dermed er I 4 sikret. Hvis barrieren deaktiveres, undersøges om der er nogle ventende biler. Så længe dette er tilfældet tælles antallet af ventende biler én ned og der udføres en V()-operation på barrier-semaforen. Dette vil sørge for, at eventuelle ventende biler får lov at køre. 4 Trin 4 Først vil vi for hver af opgaverne 2a, 2b og 3, analysere og vurdere, hvorvidt disse kunne have været løst nemmere vha. monitorer. Derefter beskrives og analyseres hvorledes barrieren er implementeret vha. en monitor. 8
4.1 Trin 2a Skitsering af monitorløsning For at løse Trin 2a vha. monitorer kan man ligesom med semaforer tilknytte en monitor til hvert felt. occupy()- og leave()-metoderne gøres til monitor-metoder, og disse sikrer derfor (pr. definition) eksklusiv adgang til et felt. Metoderne inkorporerer virkemåden af en semafor, idet der ventes, hvis ressourcen er i brug og der gives besked, når ressourcen igen er tilgængelig. Følgende pseudo-kode illustrerer dette: monitor CS bool isoccupied = false; occupy() if (isoccupied) wait(); isoccupied = true; leave() isoccupied = false; notify(); Man behøver kun kalde notify() og ikke notifyall(), da man ved, at der maksimalt kan være én bil, der venter på at få adgang til et felt. Vurdering Gruppens medlemmer mener ikke, at monitorer løser Trin 2.a. på en nemmere ( convenient ) måde end vha. semaforer, da løsningen fylder mere. 4.2 Trin 2b Skitsering af monitorløsning Logikken i at løse Trin 2.b. vha. monitorer er overordnet den samme som ved at løse det vha. semaforer. I stedet for at vente på BehindHouse-semaforen indføres en BehindHousemonitor. Denne har to metoder: entercs() og leavecs(). Pseudo-kode til denne kan ses i bilag A. I entercs() undersøges det om den pågældende bil er den første i den retning, og om der aktuelt er modkørende biler i den kritiske sektion. Hvis dette er tilfældet, kaldes wait(). OuterCounter++; if (OuterCounter==1 && InnerCounter > 0) wait(); Når en bil vha. leavecs() skal forlade den kritiske sektion, undersøges det, om den er den sidste i sin retning, der forlader den sektionen, og hvis dette er tilfældet, vækker den 9
vha. af notfify() den først ventende bil. De øvrige biler venter, da de ikke må støde sammen (løst i Trin 2.a.). OuterCounter--; if (OuterCounter==0) notify(); Vurdering Igen foretrækkes en semafor-løsning, da gruppens medlemmer mener, at en sådan giver en klarere kode. 4.3 Trin 3 Vurdering Barrieren implementeres nemmere vha. en monitor end vha. af semaforer. Som vi skal se i det følgende afsnit skyldes dette, at Javas monitorbegreb sørger for, at kun de biler, der venter ved barrieren, når notifyall() bliver kaldt, bliver vækket, og derfor kræves der ikke nogen eksplicit håndtering af den hurtige bil nr. 0, som i Trin 3 krævede, at man gjorde dét at give stafetten videre til den næste ventende bil til en kritisk sektion. 4.4 Barriere implementeret vha. Java-monitor Den største forskel mellem trin 3 og trin 4 kodemæssigt er fraværet af semaforer, fordi nøgleordet synchronized sørger for, at hele objektet er låst så længe en proces er i gang med at arbejde på objektet (i dette tilfælde klassen Barrier). Vi har således en metode: public synchronized void sync() som bliver kaldt i de tilfælde hvor en bil befinder sig på det felt, hvor den står lige foran barrieren og derfor skal stoppe, hvis denne er sat til. Det er med monitorer sikret, at alle biler har eksklusiv adgang til denne metode, og det er derfor ikke længere nødvendigt med semaforer til sikring af at f.eks. opdatering af variable sker atomart. Metoden fungerer således, at for hver gang den kaldes, tælles en variabel, DelayedCars én op, hvorefter en case på denne variabel afgør, hvilken af to følgende muligheder for videre programudførsel der udføres: 1. Bilen der lige har talt DelayedCars én op er den sidste bil (bil nr. 9) der er ankommet til barrieren, og alle biler der holder og venter på det tidspunkt skal derfor have lov at køre. I dette tilfælde tælles variablen DelayedCars én ned og alle biler der holder og venter signaleres med kald til notifyall(). 2. I alle andre tilfælde sættes den pågældende bil til at vente med wait() og når bilen bliver vækket ved kaldet til notifyall(), tæller den variablen DelayedCars én ned og kører videre (dvs. i koden derfra hvor sync() kaldes). Det skal bemærkes, at den superhurtige bil nr. 0 ikke kan snyde sig til en ekstra omgang på denne måde i kraft af dens hurtighed, idet kaldet til notifyall() alene vækker de processer (biler) der venter i køen på nøjagtig det tidspunkt, hvor metoden bliver kaldt. Det betyder, at uanset hvor hurtig bil nr. 0 er, vil den ikke få lov til at køre en omgang mere før næste kald til notifyall(). Der kan således ikke opstå race conditions i denne udgave af programmet. 10
5 Afprøvning Der er udført minimum én afprøvning pr. trin. Hver afprøvning skal bekræfte, at det pågældende trin er implementeret korrekt. Afprøvningerne, der er udført, er derfor funktionelle (black box) afprøvninger. Fælles for alle afprøvninger er, at bilerne startes og brugeren skal verificere visuelt, om programopførslen er som ønsket. 5.1 Trin 2a Ingen sammenstød Hvis hvert felt gøres til en kritisk sektion, vil det ikke være muligt for to biler at få adgang til det samme felt samtidigt. De steder, hvor der er mulighed for dette, undgås sammenstød vha. semaforer som beskrevet i 2. Ved kørsel af afprøvningen i bilag C bekræftes det, at der ikke forekommer sammenstød. 5.2 Trin 2b.1 Ingen baglåse Da alle felter nu kan betragtes som ressourcer, som bilerne kæmper om, kan der opstå baglås. Ved hjælp af semaforen BehindHouse gøres gyden bag huset til en kritisk sektion. Ved kørsel af afprøvningen i bilag E bekræftes det, at bilerne, når der er en modsatkørende bil i den kritiske sektion, venter udenfor gyden og først når den sidste bil har forladt den kritiske sektion, fortsætter de ventende biler. 5.3 Trin 2b.2 Ingen unødig ventetid Det skal være muligt for flere biler, der kører i samme retning, at være i den kritiske sektion på samme tid, da dette ikke kan føre til baglås. Der indføres en tæller for hver retning af biler og kun den første bil låser den kritiske sektion og kun den sidste låser den op igen. Ved kørsel af afprøvningen i bilag E bekræftes det, at der kan være flere biler, der kører i samme retning, i den kritiske sektion ad gangen. 5.4 Trin 3 Barriere Hvis barrieren er aktiveret, skal alle bilerne stoppe ved denne og først fortsætte, når den sidste bil er ankommet. Ved kørsel af afprøvningen i bilag G bekræftes det, at alle ni biler stopper ved barrieren, hvis denne er aktiveret. Ud fra uddata skrevet direkte til prompten, bekræftes det, at bil nr. 0 ikke når at køre ekstra omgange. Endeligt bekræftes det, at hvis barrieren er aktiveret, og der holder biler og venter ved den, vil disse fortsætte, hvis barrieren deaktiveres. 5.5 Trin 4 Barriere vha. Monitor Barrieren implementeret vha. Javas monitor-begreb. Ved kørsel af afprøvningen i bilag I bekræftes det, at barrieren stadig har samme ønskede virkning som i afsnit 5.4. 11
6 Konklusion Vi har besvaret trin 1-4 i opgaven, og der er foretaget afprøvninger af trin 2-4. Alle afprøvninger viser, at implementeringen af de tre trin, tilsyneladende er korrekt. Desuden er der udarbejdet tre Petri Net-modeller, som viser samspillet mellem en port og en bil. Endelig er monitor-løsninger for trin 2a og 2b er skitseret. Det konkluderes, at disse to trin implementeres nemmere vha. semaforer, men at trin 3 implementeres nemmere vha. en monitor. 12
A Trin 2b Skitse af monitorløsning //NOTE: Pseudo code monitor BehindHouse int InnerCounter=0, OuterCounter=0; entercs(bool isouter) if (isouter) OuterCounter++; if (OuterCounter==1 && InnerCounter > 0) wait(); // Car moves in CS else InnerCounter++; if (InnerCounter==1 && OuterCounter > 0) wait(); // Car moves in CS leavecs(bool isouter) if (isouter) OuterCounter--; if (OuterCounter==0) notify(); else InnerCounter--; if (InnerCounter==0) notify(); B CarControl2a.java // Prototype implementation of Car Control // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 import java.awt.color; class Gate Semaphore g = new Semaphore(0); boolean isopen = false; public void pass() throws InterruptedException g.p(); g.v(); 13
// open and close assumed to be called from a single thread public void open() if (!isopen) g.v(); isopen = true; public void close() if (isopen) try g.p(); catch (InterruptedException e) isopen = false; class Car extends Thread int basespeed = 200; int variation = 100; CarDisplayI cd; int no; Pos startpos; Pos barpos; Color col; int speed; Gate mygate; // Rather: degree of slowness // GUI part // Car number // Startpositon (provided by GUI) // Barrierpositon (provided by GUI) // Car colour // Current car speed // Gate at startposition Semaphore[][] cfs; public Car(int no, CarDisplayI cd, Gate g, Semaphore[][] cfs) this.no = no; this.cd = cd; mygate = g; startpos = cd.getstartpos(no); barpos = cd.getbarrierpos(no); // For later use col = choosecolor(); this.cfs = cfs; // do not change the special settings for car no. 0 if (no==0) basespeed=0; variation = 0; setpriority(thread.norm_priority + 2); int choosespeed() return basespeed-variation/2+(int)math.round(math.random()*variation); Color choosecolor() return Color.blue; // You can get any color, as longs as it s blue Pos nextpos(pos pos) // Fixed tracks --- not to be modified. int mycol = 3+no; Pos nxt = pos.copy(); if (no==0) // No. 0 is special, running its own tiny track if (pos.row==4 && pos.col > 2) nxt.col--; if (pos.col==2 && pos.row < 5) nxt.row++; if (pos.row==5 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 4) nxt.row--; 14
else if (no < 5) // Car going around anti-clockwise (to the left) if (pos.row==1 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row < 8) nxt.row++; if (pos.row==8 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 1) nxt.row--; else if (no >= 5) // Car going around clockwise (to the right) if (pos.row==9 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row > 0) nxt.row--; if (pos.row==0 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row < 9) nxt.row++; return nxt; public void run() try Pos curpos, // Current position newpos; // New position to go to speed = choosespeed(); curpos = startpos; cd.occupy(curpos,col,no); while (true) sleep(speed); if (Pos.equal(curpos,startpos)) mygate.pass(); speed = choosespeed(); newpos = nextpos(curpos); cfs[newpos.row][newpos.col].p(); cd.leave(curpos); cd.occupy(newpos,col,no); cfs[curpos.row][curpos.col].v(); curpos = newpos; catch (Exception e) cd.println("exception in Car no. "+no); System.out.println("Exception in Car no. "+no+":"+e); public class CarControl implements CarControlI CarDisplayI cd; Car[] car; Gate[] gate; // Reference to GUI // Cars // Gates Semaphore[][] CarFieldSemaphore = new Semaphore[10][12]; public CarControl(CarDisplayI cd) this.cd = cd; car = new Car[9]; gate = new Gate[9]; for (int i=0; i<10; i++) for (int j=0; j<12; j++) 15
CarFieldSemaphore[i][j] = new Semaphore(1); for (int no = 0; no < 9; no++) gate[no] = new Gate(); car[no] = new Car(no,cd,gate[no], CarFieldSemaphore); car[no].start(); public void startcar(int no) gate[no].open(); public void stopcar(int no) gate[no].close(); public void barrieron() cd.println("barrier On not implemented in this version"); public void barrieroff() cd.println("barrier Off not implemented in this version"); public void removecar(int no) cd.println("remove Car not implemented in this version"); public void restorecar(int no) cd.println("restore Car not implemented in this version"); C CarTest2a.java // Prototype implementation of Car Test class // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 public class CarTest extends Thread CarTestingI cars; int testno; public CarTest(CarTestingI ct, int i) cars = ct; testno = i; public void run() try // Test that cars don t crash into each other switch (testno) // This test should start the cars (all 9) and the // user should see all cars running without ever // crashing into each other. case 0: cars.startall(); cars.startcar(0); 16
break; default: cars.println("test " + testno + " not available"); cars.println("test ended"); catch (Exception e) cars.println("exception in test: "+e); D CarControl2b.java // Prototype implementation of Car Control // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 import java.awt.color; class Gate Semaphore g = new Semaphore(0); boolean isopen = false; public void pass() throws InterruptedException g.p(); g.v(); // open and close assumed to be called from a single thread public void open() if (!isopen) g.v(); isopen = true; public void close() if (isopen) try g.p(); catch (InterruptedException e) isopen = false; class Car extends Thread int basespeed = 200; int variation = 100; CarDisplayI cd; int no; Pos startpos; Pos barpos; Color col; int speed; Gate mygate; // Rather: degree of slowness // GUI part // Car number // Startpositon (provided by GUI) // Barrierpositon (provided by GUI) // Car colour // Current car speed // Gate at startposition static Semaphore BehindHouse = new Semaphore(1); static Semaphore[][] cfs = new Semaphore[10][12]; //CarFieldSemaphore: Every field is a cs 17
static Semaphore InnerCounterLock = new Semaphore(1); static Semaphore OuterCounterLock = new Semaphore(1); static int InnerCounter = 0; static int OuterCounter = 0; public Car(int no, CarDisplayI cd, Gate g) this.no = no; this.cd = cd; mygate = g; startpos = cd.getstartpos(no); barpos = cd.getbarrierpos(no); // For later use col = choosecolor(); //All fields are initially free for (int i=0; i<10; i++) for (int j=0; j<12; j++) cfs[i][j] = new Semaphore(1); // do not change the special settings for car no. 0 if (no==0) basespeed=0; variation = 0; setpriority(thread.norm_priority + 2); int choosespeed() return basespeed-variation/2+(int)math.round(math.random()*variation); Color choosecolor() return Color.blue; // You can get any color, as longs as it s blue Pos nextpos(pos pos) // Fixed tracks --- not to be modified. int mycol = 3+no; Pos nxt = pos.copy(); if (no==0) // No. 0 is special, running its own tiny track if (pos.row==4 && pos.col > 2) nxt.col--; if (pos.col==2 && pos.row < 5) nxt.row++; if (pos.row==5 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 4) nxt.row--; else if (no < 5) // Car going around anti-clockwise (to the left) if (pos.row==1 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row < 8) nxt.row++; if (pos.row==8 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 1) nxt.row--; else if (no >= 5) // Car going around clockwise (to the right) if (pos.row==9 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row > 0) nxt.row--; if (pos.row==0 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row < 9) nxt.row++; return nxt; public void run() try Pos curpos, // Current position newpos; // New position to go to 18
speed = choosespeed(); curpos = startpos; cd.occupy(curpos,col,no); while (true) sleep(speed); if (Pos.equal(curpos,startpos)) mygate.pass(); speed = choosespeed(); newpos = nextpos(curpos); //----------------Behind the house------------------- //------------------Outer rim------------------ //Entering cs... if ((newpos.row == 8 && newpos.col == 0) && (curpos.row == 9 && curpos.col == 0)) OuterCounterLock.P(); OuterCounter++; if (OuterCounter == 1) BehindHouse.P(); OuterCounterLock.V(); //Leaving cs else if (newpos.row == 0 && newpos.col == 0) OuterCounterLock.P(); OuterCounter--; if (OuterCounter == 0) //Last car behind house in this direction, release lock BehindHouse.V(); OuterCounterLock.V(); //------------------Inner rim------------------ //Entering cs... else if ((newpos.row == 1 && newpos.col == 0) && (curpos.row == 1 && curpos.col == 1)) InnerCounterLock.P(); InnerCounter++; if (InnerCounter == 1) BehindHouse.P(); InnerCounterLock.V(); //Leaving cs else if (newpos.row == 8 && newpos.col == 1) InnerCounterLock.P(); InnerCounter--; if (InnerCounter == 0) //Last car behind house in this direction, release lock BehindHouse.V(); InnerCounterLock.V(); //--------------------------------------------------- cfs[newpos.row][newpos.col].p(); //Try to get the lock cd.leave(curpos); cd.occupy(newpos,col,no); cfs[curpos.row][curpos.col].v(); //Release the lock curpos = newpos; 19
catch (Exception e) cd.println("exception in Car no. "+no); System.out.println("Exception in Car no. "+no+":"+e); public class CarControl implements CarControlI CarDisplayI cd; Car[] car; Gate[] gate; // Reference to GUI // Cars // Gates public CarControl(CarDisplayI cd) this.cd = cd; car = new Car[9]; gate = new Gate[9]; for (int no = 0; no < 9; no++) gate[no] = new Gate(); car[no] = new Car(no,cd,gate[no]); car[no].start(); public void startcar(int no) gate[no].open(); public void stopcar(int no) gate[no].close(); public void barrieron() cd.println("barrier On not implemented in this version"); public void barrieroff() cd.println("barrier Off not implemented in this version"); public void removecar(int no) cd.println("remove Car not implemented in this version"); public void restorecar(int no) cd.println("restore Car not implemented in this version"); E CarTest2b.java // Prototype implementation of Car Test class // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 public class CarTest extends Thread CarTestingI cars; int testno; public CarTest(CarTestingI ct, int i) 20
cars = ct; testno = i; public void run() try // Test that no deadlocks can occur. switch (testno) // This test should start the cars (all 9) and the // user should see all cars running without // deadlock ever occuring. case 0: cars.startall(); cars.startcar(0); break; default: cars.println("test " + testno + " not available"); cars.println("test ended"); catch (Exception e) cars.println("exception in test: "+e); F CarControl3.java // Prototype implementation of Car Control // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 import java.awt.color; class Gate Semaphore g = new Semaphore(0); boolean isopen = false; public void pass() throws InterruptedException g.p(); g.v(); // open and close assumed to be called from a single thread public void open() if (!isopen) g.v(); isopen = true; public void close() if (isopen) try g.p(); catch (InterruptedException e) isopen = false; 21
class Car extends Thread int basespeed = 200; int variation = 100; CarDisplayI cd; int no; Pos startpos; Pos barpos; Color col; int speed; Gate mygate; // Rather: degree of slowness // GUI part // Car number // Startpositon (provided by GUI) // Barrierpositon (provided by GUI) // Car colour // Current car speed // Gate at startposition static Semaphore BehindHouse = new Semaphore(1); static Semaphore[][] cfs = new Semaphore[10][12]; //CarFieldSemaphore: Every field is a cs static Semaphore InnerCounterLock = new Semaphore(1); static Semaphore OuterCounterLock = new Semaphore(1); static int InnerCounter = 0; static int OuterCounter = 0; static Barrier b; public Car(int no, CarDisplayI cd, Gate g, Barrier b) this.no = no; this.cd = cd; mygate = g; startpos = cd.getstartpos(no); barpos = cd.getbarrierpos(no); // For later use col = choosecolor(); this.b = b; //All fields are initially free for (int i=0; i<10; i++) for (int j=0; j<12; j++) cfs[i][j] = new Semaphore(1); // do not change the special settings for car no. 0 if (no==0) basespeed=0; variation = 0; setpriority(thread.norm_priority + 2); int choosespeed() return basespeed-variation/2+(int)math.round(math.random()*variation); Color choosecolor() return Color.blue; // You can get any color, as longs as it s blue Pos nextpos(pos pos) // Fixed tracks --- not to be modified. int mycol = 3+no; Pos nxt = pos.copy(); if (no==0) // No. 0 is special, running its own tiny track if (pos.row==4 && pos.col > 2) nxt.col--; if (pos.col==2 && pos.row < 5) nxt.row++; if (pos.row==5 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 4) nxt.row--; else if (no < 5) // Car going around anti-clockwise (to the left) 22
if (pos.row==1 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row < 8) nxt.row++; if (pos.row==8 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 1) nxt.row--; else if (no >= 5) // Car going around clockwise (to the right) if (pos.row==9 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row > 0) nxt.row--; if (pos.row==0 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row < 9) nxt.row++; return nxt; public void run() try Pos curpos, // Current position newpos; // New position to go to speed = choosespeed(); curpos = startpos; cd.occupy(curpos,col,no); while (true) sleep(speed); if (Pos.equal(curpos,startpos)) mygate.pass(); speed = choosespeed(); newpos = nextpos(curpos); if ( (curpos.row == 5 && curpos.col == 3 && newpos.row == 4) //Car 0 (curpos.row == 5 && curpos.col == 4 && newpos.row == 4) //Car 1 (curpos.row == 5 && curpos.col == 5 && newpos.row == 4) //Car 2 (curpos.row == 5 && curpos.col == 6 && newpos.row == 4) //Car 3 (curpos.row == 5 && curpos.col == 7 && newpos.row == 4) //Car 4 ) (curpos.row == 4 && curpos.col == 8 && newpos.row == 5) //Car 5 (curpos.row == 4 && curpos.col == 9 && newpos.row == 5) //Car 6 (curpos.row == 4 && curpos.col == 10 && newpos.row == 5) //Car 7 (curpos.row == 4 && curpos.col == 11 && newpos.row == 5) //Car 8 System.out.println("Car no: "+no); b.sync(); //----------------Behind the house------------------- //------------------Outer rim------------------ //Entering cs... if ((newpos.row == 8 && newpos.col == 0) && (curpos.row == 9 && curpos.col == 0)) OuterCounterLock.P(); OuterCounter++; if (OuterCounter == 1) BehindHouse.P(); OuterCounterLock.V(); //Leaving cs 23
else if (newpos.row == 0 && newpos.col == 0) OuterCounterLock.P(); OuterCounter--; if (OuterCounter == 0) //Last car behind //house in this //direction, release //lock BehindHouse.V(); OuterCounterLock.V(); //------------------Inner rim------------------ //Entering cs... else if ((newpos.row == 1 && newpos.col == 0) && (curpos.row == 1 && curpos.col == 1)) InnerCounterLock.P(); InnerCounter++; if (InnerCounter == 1) BehindHouse.P(); InnerCounterLock.V(); //Leaving cs else if (newpos.row == 8 && newpos.col == 1) InnerCounterLock.P(); InnerCounter--; if (InnerCounter == 0) //Last car behind //house in this //direction, release //lock BehindHouse.V(); InnerCounterLock.V(); //--------------------------------------------------- cfs[newpos.row][newpos.col].p(); //Try to get the lock cd.leave(curpos); cd.occupy(newpos,col,no); cfs[curpos.row][curpos.col].v(); //Release the lock curpos = newpos; catch (Exception e) cd.println("exception in Car no. "+no); System.out.println("Exception in Car no. "+no+":"+e); public class CarControl implements CarControlI CarDisplayI cd; Car[] car; Gate[] gate; // Reference to GUI // Cars // Gates static Barrier b = new Barrier(); public CarControl(CarDisplayI cd) this.cd = cd; car = new Car[9]; gate = new Gate[9]; for (int no = 0; no < 9; no++) gate[no] = new Gate(); 24
car[no] = new Car(no,cd,gate[no],b); car[no].start(); public void startcar(int no) gate[no].open(); public void stopcar(int no) gate[no].close(); public void barrieron() //cd.println("barrier On not implemented in this version"); b.on(); public void barrieroff() //cd.println("barrier Off not implemented in this version"); b.off(); public void removecar(int no) cd.println("remove Car not implemented in this version"); public void restorecar(int no) cd.println("restore Car not implemented in this version"); class Barrier static boolean isbarrieron = false; static int DelayedCars = 0; Semaphore mutex = new Semaphore(1); Semaphore barrier = new Semaphore(0); public void on() isbarrieron = true; public void off() isbarrieron = false; while(delayedcars>0) DelayedCars--; barrier.v(); public void sync() throws InterruptedException if (isbarrieron) mutex.p(); DelayedCars++; mutex.v(); switch(delayedcars) //The last incoming car case 9: 25
mutex.p(); //Lock while passing //the baton, so that //the fast Car0 can t //grab it several //times DelayedCars--; barrier.v(); //Pass the baton to //one of the waiting //cars break; default: barrier.p(); DelayedCars--; if (DelayedCars == 0) mutex.v(); //Last car releases baton lock else barrier.v(); //Pass the //baton to one //of the //waiting cars break; G CarTest3.java // Prototype implementation of Car Test class // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 public class CarTest extends Thread CarTestingI cars; int testno; public CarTest(CarTestingI ct, int i) cars = ct; testno = i; public void run() try // Test of barrier functionality. switch (testno) // This test should start the cars (all 9) and // activate the barrier. The user should see all // cars stopping at the barrier before going // another round. case 0: cars.startall(); sleep(3000); // Make sure the cars get past // the barrier on the first // round. cars.barrieron(); 26
cars.startcar(0); break; // This test should start the first three cars and // activate the barrier. When all three cars have // arrived at the barrier, the barrier is // deactivated and the user should see all cars // being released. case 1: cars.startcar(1); cars.startcar(2); cars.startcar(3); sleep(3000); cars.barrieron(); sleep(5000); // Make sure all cars have // arrived before deactivating // the barrier. cars.barrieroff(); break; default: cars.println("test " + testno + " not available"); cars.println("test ended"); catch (Exception e) cars.println("exception in test: "+e); H CarControl4.java // Prototype implementation of Car Control // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 import java.awt.color; class Gate Semaphore g = new Semaphore(0); boolean isopen = false; public void pass() throws InterruptedException g.p(); g.v(); // open and close assumed to be called from a single thread public void open() if (!isopen) g.v(); isopen = true; public void close() if (isopen) try g.p(); catch (InterruptedException e) isopen = false; 27
class Car extends Thread int basespeed = 200; int variation = 100; CarDisplayI cd; int no; Pos startpos; Pos barpos; Color col; int speed; Gate mygate; // Rather: degree of slowness // GUI part // Car number // Startpositon (provided by GUI) // Barrierpositon (provided by GUI) // Car colour // Current car speed // Gate at startposition static Semaphore BehindHouse = new Semaphore(1); static Semaphore[][] cfs = new Semaphore[10][12]; //CarFieldSemaphore: Every field is a cs static Semaphore InnerCounterLock = new Semaphore(1); static Semaphore OuterCounterLock = new Semaphore(1); static int InnerCounter = 0; static int OuterCounter = 0; static Barrier b; public Car(int no, CarDisplayI cd, Gate g, Barrier b) this.no = no; this.cd = cd; mygate = g; startpos = cd.getstartpos(no); barpos = cd.getbarrierpos(no); // For later use col = choosecolor(); this.b = b; //All fields are initially free for (int i=0; i<10; i++) for (int j=0; j<12; j++) cfs[i][j] = new Semaphore(1); // do not change the special settings for car no. 0 if (no==0) basespeed=0; variation = 0; setpriority(thread.norm_priority + 2); int choosespeed() return basespeed-variation/2+(int)math.round(math.random()*variation); Color choosecolor() return Color.blue; // You can get any color, as longs as it s blue Pos nextpos(pos pos) // Fixed tracks --- not to be modified. int mycol = 3+no; Pos nxt = pos.copy(); if (no==0) // No. 0 is special, running its own tiny track if (pos.row==4 && pos.col > 2) nxt.col--; if (pos.col==2 && pos.row < 5) nxt.row++; if (pos.row==5 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 4) nxt.row--; 28
else if (no < 5) // Car going around anti-clockwise (to the left) if (pos.row==1 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row < 8) nxt.row++; if (pos.row==8 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row > 1) nxt.row--; else if (no >= 5) // Car going around clockwise (to the right) if (pos.row==9 && pos.col > 0) nxt.col--; if (pos.col==0 && pos.row > 0) nxt.row--; if (pos.row==0 && pos.col < mycol) nxt.col++; if (pos.col==mycol && pos.row < 9) nxt.row++; return nxt; public void run() try Pos curpos, // Current position newpos; // New position to go to speed = choosespeed(); curpos = startpos; cd.occupy(curpos,col,no); while (true) sleep(speed); if (Pos.equal(curpos,startpos)) mygate.pass(); speed = choosespeed(); newpos = nextpos(curpos); if ( (curpos.row == 5 && curpos.col == 3 && newpos.row == 4) //Car 0 (curpos.row == 5 && curpos.col == 4 && newpos.row == 4) //Car 1 (curpos.row == 5 && curpos.col == 5 && newpos.row == 4) //Car 2 (curpos.row == 5 && curpos.col == 6 && newpos.row == 4) //Car 3 (curpos.row == 5 && curpos.col == 7 && newpos.row == 4) //Car 4 ) (curpos.row == 4 && curpos.col == 8 && newpos.row == 5) //Car 5 (curpos.row == 4 && curpos.col == 9 && newpos.row == 5) //Car 6 (curpos.row == 4 && curpos.col == 10 && newpos.row == 5) //Car 7 (curpos.row == 4 && curpos.col == 11 && newpos.row == 5) //Car 8 //System.out.println("Car no: "+no+" passed barrier."); b.sync(); //----------------Behind the house------------------- //------------------Outer rim------------------ //Entering cs... if ((newpos.row == 8 && newpos.col == 0) && (curpos.row == 9 && curpos.col == 0)) OuterCounterLock.P(); OuterCounter++; if (OuterCounter == 1) BehindHouse.P(); OuterCounterLock.V(); 29
//Leaving cs else if (newpos.row == 0 && newpos.col == 0) OuterCounterLock.P(); OuterCounter--; if (OuterCounter == 0) //Last car behind house in this direction, release lock BehindHouse.V(); OuterCounterLock.V(); //------------------Inner rim------------------ //Entering cs... else if ((newpos.row == 1 && newpos.col == 0) && (curpos.row == 1 && curpos.col == 1)) InnerCounterLock.P(); InnerCounter++; if (InnerCounter == 1) BehindHouse.P(); InnerCounterLock.V(); //Leaving cs else if (newpos.row == 8 && newpos.col == 1) InnerCounterLock.P(); InnerCounter--; if (InnerCounter == 0) //Last car behind house in this direction, release lock BehindHouse.V(); InnerCounterLock.V(); //--------------------------------------------------- cfs[newpos.row][newpos.col].p(); //Try to get the lock cd.leave(curpos); cd.occupy(newpos,col,no); cfs[curpos.row][curpos.col].v(); //Release the lock curpos = newpos; catch (Exception e) cd.println("exception in Car no. "+no); System.out.println("Exception in Car no. "+no+":"+e); public class CarControl implements CarControlI CarDisplayI cd; Car[] car; Gate[] gate; // Reference to GUI // Cars // Gates static Barrier b = new Barrier(); public CarControl(CarDisplayI cd) this.cd = cd; car = new Car[9]; gate = new Gate[9]; for (int no = 0; no < 9; no++) gate[no] = new Gate(); car[no] = new Car(no,cd,gate[no],b); car[no].start(); 30
public void startcar(int no) gate[no].open(); public void stopcar(int no) gate[no].close(); public void barrieron() //cd.println("barrier On not implemented in this version"); b.on(); public void barrieroff() //cd.println("barrier Off not implemented in this version"); b.off(); public void removecar(int no) cd.println("remove Car not implemented in this version"); public void restorecar(int no) cd.println("restore Car not implemented in this version"); class Barrier static boolean isbarrieron = false; static int DelayedCars = 0; public synchronized void on() isbarrieron = true; public synchronized void off() isbarrieron = false; while(delayedcars>0) DelayedCars--; notify(); public synchronized void sync() throws InterruptedException if (isbarrieron) DelayedCars++; System.out.println(DelayedCars); switch(delayedcars) //The last incoming car case 9: DelayedCars--; //Removes itself from queue notifyall(); //Notify all the cars //waiting in the //queue. Each car gets //a ticket so it can //pass. NOTE: Car0 31
break; //might reach the //queue again, but //there are not //tickets for it to //pass default: wait(); DelayedCars--; break; I CarTest4.java // Prototype implementation of Car Test class // Mandatory assignment 1 // Course 02220 Concurrent Systems, DTU Fall 2003 // // Hans Henrik ølvengreen Sep 17, 2003 public class CarTest extends Thread CarTestingI cars; int testno; public CarTest(CarTestingI ct, int i) cars = ct; testno = i; public void run() try // Test of barrier functionality. switch (testno) // This test should start the cars (all 9) and // activate the barrier. The user should see all // cars stopping at the barrier before going // another round. case 0: cars.startall(); sleep(3000); // Make sure the cars get past // the barrier on the first // round. cars.barrieron(); cars.startcar(0); break; // This test should start the first three cars and // activate the barrier. When all three cars have // arrived at the barrier, the barrier is // deactivated and the user should see all cars // being released. case 1: cars.startcar(1); cars.startcar(2); cars.startcar(3); 32
sleep(3000); cars.barrieron(); sleep(5000); // Make sure all cars have // arrived before deactivating // the barrier. cars.barrieroff(); break; default: cars.println("test " + testno + " not available"); cars.println("test ended"); catch (Exception e) cars.println("exception in test: "+e); 33