LUNDS TEKNISKA HÖGSKOLA Datavetenskap Realtidsprogrammering : EDA040 DAT040 Tentamensskrivning - Realtidsprogrammering 2006-06-01, kl 8.00-13.00 Anvisningar: Tillåtna hjälpmedel: inga utöver Java snabbreferens. DAT040: En uppdelning av betyg 4 för G resp VG kommer att ske, f.ö. se EDA040. EDA040: För godkänt betyg krävs att större delen av de 6 första uppgifterna (teori) samt uppgiften 7 (den första av de båda konstruktionsuppgifterna) behandlas nöjaktigt. För högre betyg krävs dessutom en acceptabel lösning till uppgift 8 (design), och för högsta betyg ett tillräckligt (c:a 30p) totalt poängantal. Uppgifter 1. Trådar kan schemaläggas statiskt eller dynamiskt. a) Nämn två fördelar med statisk schemaläggning jämfört med dynamisk schemaläggning. b) Nämn två nackdelar med schemaläggning jämfört med dynamisk schemaläggning. 2. Betrakta ett realtidssystem som är implementerat med hjälp av fyra stycken trådar, A, B, C och D, med karaktäristika enligt nedanstående tabell (C = maximal exekveringstid/period och T = periodtid): Tråd C (ms) T (ms) A 4 16 B 3 10 C 4 25 D 2 12 För samtliga trådar gäller även att deadline är lika med periodtiden. Vi antar vidare att trådarna schemaläggs enligt principen RMS (Rate Monotonic Scheduling) och att trådarna är helt oberoende av varandra, dvs de kommunicerar inte med varandra och kan således inte blockera varandra (de kan dock naturligtvis avbryta varandra genom s.k. preemption - påtvingad tidsdelning). Vi bortser också från kostnaden för trådbyten et cetera. a) Vad blir värstafallssvarstiden för var och en av de fyra trådarna? (3p) b) Är systemet schemaläggningsbart? Motivera ditt svar. c) Antag att vi använder oss av EDF (earliest deadline first) som schemaläggningsprincip i stället för RMS. Kommer systemet att vara schemaläggningsbart i detta fall? Motivera ditt svar. d) Rita ett schemaläggningsdiagram som visar schemaläggningen för de första 30 millisekunderna som systemet exekverar om EDF används. Antag att samtliga fyra trådar släpps samtidigt vid tiden 0. (2p)
3. Programmet nedan tar två stycken heltal som parametrar på kommandoraden. Dessa heltal styr hur många trådar som startas i huvudprogrammet. Trådarna kommunicerar i sin tur med varandra via tre stycken monitorer; MonitorA, MonitorB och MonitorC. För vilka värden på de två heltalsparametrarna finns det risk att programmet råkar ut för dödläge (deadlock)? Motivera ditt svar! (3p) public class MainProgram { public static void main(string[] args) { Global g = new Global(); g.a = new MonitorA(g); g.b = new MonitorB(g); g.c = new MonitorC(g); class MonitorA { public MonitorA(Global g) { int noofthreads = Integer.parseInt(args[0]); for(int i=0;i<noofthreads;i++) new ThreadOne(g).start(); noofthreads = Integer.parseInt(args[1]); for(int i=0;i<noofthreads;i++) new ThreadTwo(g).start(); class Global { public MonitorA a; public MonitorB b; public MonitorC c; class ThreadOne extends Thread { public ThreadOne(Global g) { public void run() { while(true) { g.b.fifth(); g.b.fourth(); class ThreadTwo extends Thread { public ThreadTwo(Global g) { public synchronized void first() { g.b.third(); public synchronized void second() { class MonitorB { public MonitorB(Global g) { public synchronized void third() { public synchronized void fourth() { g.c.sixth(); public synchronized void fifth() { class MonitorC { public MonitorC(Global g) { public synchronized void sixth() { public void run() { while(true) { g.a.first(); g.c.seventh(); public synchronized void seventh() { g.a.second(); 2
4. Vad innebär prioritetsinversion? Illustrera med ett enkelt exempel. 5. När man beskriver hur trådar exekverar och hur de schemaläggs brukar man tala om att en tråd kan befinna sig i ett av tre olika exekveringstillstånd. a) Vilka är de tre tillstånden och vad kännetecknar en tråd som befinner sig i respektive tillstånd? b) Vilka tillståndsövergångar är möjliga och vad kan orsaka respektive tillståndsövergång? 6. Realtids-Roger har som uppgift att implementera en tråd, P, i ett realtidssystem och har kommit fram till att tråden ibland måste vänta på ett nytt villkor som ingen tråd har behövt vänta på förut. Villkoret, B, kan dock evalueras utan att någon ny kritisk region behöver införas. Realtids-Roger skissar på följande fyra alternativa lösningar: a) while (!B) {; b) while (!B) yield(); (yield() anger att schemaläggaren tar ett nytt schemaläggningsbeslut) c) while (!B) sleep(100); d) while (!B) wait(); (som del i en operation som är deklarerad synchronized) Villkoret B kan påverkas (bli true) av en annan tråd X. Prioriteten för tråd X kan förhålla sig till prioriteten för tråd P på tre olika sätt: 1) Tråd X har lägre prioritet än P. 2) Tråd X har samma prioritet som P. 3) Tråd X har högre prioritet än P. Vi antar att strikt prioritetsbaserad schemaläggning med round-robin (vid lika prioritet) tillämpas. För vart och ett av dessa tre fall behöver Realtids-Roger tänka igenom vad de fyra föreslagna konstruktionerna (a-d) får för effekt. Hjälp Realtids-Roger genom att redogöra för vad som gäller i de 12 fallen, både vad avser effektivitet och funktionalitet. (4p) 7. Persistenta meddelanden Bakgrund: Vissa realtidssystem måste snabbt kunna startas om och återuppta arbetet efter ett strömavbrott. Ett sätt att åstadkomma detta är att lagra vissa data i ett speciellt minne med någon typ av batteribackup (eller statiskt RAM, flash-minne eller liknande). Det är däremot inte önskvärt att lagra alla data i sådant minne eftersom det är långsammare och dyrare. Vi önskar alltså en mekanism för att deklarera att vissa data ska vara persistenta, dvs att dessa data ska finnas kvar även efter ett strömavbrott. I robotprogrammeringsspråket RAPID från ABB är det till exempel så att variabler deklarerade som persistenta (med hjälp av nyckelordet PERS) har kvar sina gamla värden när programmet återstartas efter ett strömavbrott och kan användas för att låta roboten fortsätta sitt arbete där den avbröts. För att kunna lagra data persistent antar vi i det följande att vi har tillgång till en Java-klass kallad Storage som implementerar persistent lagring av data. Vi kommer att utnyttja denna klass för implementera en buffert som duplicerar vissa viktiga data som måste finnas kvar även om strömmen bryts. Således, din uppgift är att konstruera en buffertklass som lämpar dig för robotstyrning, exempelvis för bevarande av rörelsesekvenser i styrsystemet. We vill då ha en buffert med följande egenskaper: 1. För snabb återstart efter driftavbrott så vill vi att vissa buffrade instanser av RTEvent skall finnas kvar (kunna återhämtas) vid återstart (nästa gång programmet startar). 3
2. Vi vill att bufferten förhindrar att meddelanden lagras i fel tidsordning. Vi vill med andra ord att meddelandena som lagras i bufferten ska vara inlagda i den ordning de skapades (korrekt tidsordning inom rörelsesekvensen). 3. Bufferten ska tillhandahålla en mekanism för att förhindra att en för lång datasekvens (för många meddelanden eller för stort tidsintervall representerat av meddelandena i bufferten) lagras i bufferten. Avgränsningar: Begränsningar och förenklingar som antages gälla i uppgiften: Eftersom den tänkta applikationen är dataflödesorienterad och huvudsakligen använder sig av meddelandesändning för kommunikation mellan trådarna kommer vi i uppgiften att utgå från och använda oss av klassen BufferPlain (enkel variant av RTEventBuffer) som bifogas sist i tentamen. Det räcker att buffertarna i uppgiften lagrar referenser till de buffrade meddelandeobjekten, så som vi normalt gör. När strömmen bryts kommer kondensatorer att fortsätta att förse CPUn med ström i några millisekunder (normalt förfarande i industriella sammanhang) och ett avbrott genereras. Avbrottet startar en avbrottshanterare som klonar och sparar undan objekten som refereras till i den persistenta bufferten. Med andra ord kan du arbeta med referenser till objekt i samband med bufferthanteringen på vanligt sätt. Specifikationer: 1. Det finns ett (tomt) interface Persistent som anger behovet av persistent (varaktig) lagring, när interfacet i detta fall implementeras av en subklass till RTEvent. 2. Om så behövs i just din lösning, kan du införa en basklass (subklass till RTEvent och som implementerar Persistent) som alla persistenta object skall ärva från. 3. Du skall utveckla en klass BufferPersistent som ärver från BufferPlain och som för varje normalt (icke-persistent) event skall bete sig som BufferPlain. 4. Förutom ev ytterliga metoder och konstruktorer som kan behövas i din lösning, så skall implementeringen av metoderna post och fetch utgöra implementeringen. 5. BufferPersistent skall ha en intern buffring av persistenta event. Det finns en statisk metod Storage.getPersistentBuffer(len,key) som anropas för den speciella allokeringan (i rätt sorts minne) som krävs, där key är något nummer som identifierar bufferten när återställning efter driftavbrott sker. Du kan själv utforma inargument och returvärden (och typ) så att det blir meningsfullt för problemet. 6. Samtliga lagrade Persistent-event skall vara i tidsordning enligt timestamp i respektive event-objekt. Vid försök att posta ett event-objekt med en tidigare tidsstämpel än den som gäller för senast lagrade objekt, så skall event:et returneras (till anroparen av post). 7. Metoderna post och fetch skall blockera såsom för dopost och dofetch respektive, när antalet event överskrider buffertstorleken respektive om bufferten är tom. 8. Den tidsperiod som lagrade event (enligt dess tidsstämplar) omfattar får vara högst 30 sekunder. Ifall (fetch inte anropas tillräckligt ofta så att) postandet av ett ytterligare ett persistent event skulle medföra att skillnaden mellan tidsstämplarna för nyaste och äldsta eventet överstiger 30 s, så skall anroparen av post blockeras. 9. För det fall att blockering enligt punkt 8 pågått i över 5 s eller om mer än ett anrop av post samtidigt blockerats på detta sätt, så har en otillåten frödröjning (delay) inträffat. För att göra det möjligt att ha en övervakningstråd som övervakar detta, så skall din buffert (BufferPersistent) även ha en metod awaitdelay som blockerar alla anropare tills delay inträffar eller har inträffat sedan förra anropet. Du bestämmer själv vilka inargument och vilket returtyp som lämpligast ger önskad funktionalitet. Implementera klassen BufferPersistent, inklusive kommenterer i koden och förklaring av dina designval. (11 p) 4
8 Brake-by-wire Bakgrund: För att reducera kostnaden försöker man inför s.k. X-by-wire i moderna fordon, där X kan betyda steer, fly, brake, etc. I denna uppgift studeras bromsning (brake) av fyrhjuliga fordon, med en central styrdator och en distribuerad mikroprocesson per hjul. Den tillgängliga programvaran för den centrala processorn använder RTEventBuffer för att skicka styrorder till hjulen och för att ta emot svar från dessa. Eftersom det är av avgörande betydelse att fordonet förblir säkert i fallet att en nätverkskabel bryts, så vill vi använda redundant kommunikation (dubblerade nätverksförbindelser). Antag att det finns sådan redundanta dubblerat kablage mellan centraldatorn och var och en av bromsnoderna (FR, FL, RR, och RL) såsom visas i följande figur: Right FR RR Front Central Control FL RL Left Linjerna mellan bromsarna för axelgemensamma hjul anger att det dessutom finns en extra nätverksförbindelse mellan hjulen ifall förbindelsen med centraldatorn skulle förloras helt. Uppgift: Utforma det distribuerade bromssystemet så att: Den centrala styrprogramvaran (som körs av main-tråden i den datorn) skickar bromskommandon eller börvärden periodiskt till var och en av bromsregulatorerna. Varje bromsstyrning utför en periodisk regleralgoritm. Då kan även ev maskinvarufel upptäckas, vilket skall resultera i felmeddelande som skickas till centraldatorn. Om avbrott inträffar i en enda nätverkskabel mellan centralen och bromsningen så skall fordonet fungera såsom om inget fel funnits, förutom att en varning (centralt) skall visas för föraren genom anrop av Panel.brakeWarning(); Varje bromsregulator skall inom 40ms detektera ifall en eller flera av dess förbindelser med centralen är bruten. Du kan anta att all kommunikation är predikterbar och att data/objekt alltid överförs inom 2ms. Antag ytterligare att alla nätverksmetoder är potentiellt sett blockerande (vid läsning då inga data finns). Cetraldatorn skall övervaka att inget kablage brutits. Om meddelanden kan tas emot från en förbindelse så kan man antaga att alla ledningar är OK. Läsning av data kan dock forsatt vara blockerande (utan exceptions) även om förbindelsen bryts. En bromsenhet utan förbindelse med centraldatorn skall bromsa lika mycket som den andra enheten på samma axel. Om det finns något kommunikationsproblem med den andra bromsen på samma axel så skall detta hanteras likadant som om en av förbindelserna med centrladatorn är bruten. En helt bortkopplad bromsenhet skall broma med halv maxeffect efter 500ms. En återupptagen förbindelse inom denna tid är OK men skall resultera i en brakewarning. Utforma systemet i termer av trådar och förbindelserna mellan dessa. Ange tydligt (t.ex. med tillståndsgraf) vilka (fel)tillstånd de olika noderna kan befinna sig i. Enkelhet att förvissa sig om utformningens lämplighet/säkerhet premieras poängmässigt. (7 p) 5