(2) Skriv ett program som skapar ett antal processer vars relationer beskrivs av nedanstående tidsdiagram a

Relevanta dokument
2... uppvisa förmåga att skapa och/eller hantera flerprocessiga program där de ingående processerna ges

Grundprogrammen. combine

Möte 9: Relationer mellan körande processer - (PI)

Möte 7: Uppföljning av föreläsningen med Peer Instruction - (PI)

#include <pthread.h> #include <stdio.h> int p1[2]; void* char_print (void* parameter) { int fds; fds = *((int *)parameter); int i;

... Funktionsanrop. Vad händer när man kör ett program?

KTH STH TENTAMEN. HI1024:TEN2 - Praktisk tentamen Tid: 8-13, den 18 februari 2012

printenv sort pager printenv grep args sort pager

HI1025 Operativsystem, KTH Haninge, VT2012

Tentamen. Datorteknik och realtidssystem

HI1024, Programmering, grundkurs, 8hp KTH STH TENTAMEN. HI1024:TEN2 - Praktisk tentamen Tid: Fredagen den 21 oktober 2011,

Vad händer när man kör ett program? Program och processer. Funktionsanrop. Avsluta programmet

Raspberry Pi och Tellstick, ett program i C.

C++ Funktioner 1. int summa( int a, int b) //funktionshuvud { return a+b; //funktionskropp } Värmdö Gymnasium Programmering B ++ Datainstitutionen

HI1024 Programmering, grundkurs TEN

Programsystemkonstruktion med C++: Övning 1. Karl Palmskog september 2010

Del II: Systemprogrammering och Inter-Process Communication.

Om pekare och minneshantering i C, relaterat till operativsystem och särskilt konstruktionen fork() execvp().

HI1024 Programmering, grundkurs TEN

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Övning från förra gången: readword

Tellstick-15.c. Kompilering av programmet: gcc -o tellstick-15 -Wall -ltelldus-core -W -O2 -s -pipe -lm tellstick-15.c

Datorteknik 2 (AVR 2)

Att bekanta dig med NetBeans programmeringsmiljö och skriva några enkla program med programmeringsspråket Java.

Tentamen Datorteknik och realtidssystem, TSEA81 Datum Lokal

HI1024 Programmering, grundkurs TEN

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

Introduktionslaboration

C++ Lektion Tecken och teckenfält

BMI = (vikt i kg) / (längd i m) 2. Lösningsförslag

Introduktionslaboration

Tentamen i. för D1 m fl, även distanskursen. lördag 28 maj 2011

Uppgiften är att beskriva en kvadrat i ett Java program. En första version av programmet skulle kunna se ut så här:

Föreläsning 6 pekare och pekare tillsammans med arrayer

Deluppgift 17 Processhantering: exec, sleep, exit, plist

HI1024 Programmering, grundkurs TEN

Introduktion till processer

HI1024 Programmering, grundkurs TEN

Introduktion till programmering, hösten 2011

Bankkonto - övning. Övning 2 Skriv en metod, geträntan, som returnerar räntan.

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

Systemnära programmering Tentamen. Systemnära programmering, 7.5hp 5 november 2012

Tentamen i. för D1 m fl, även distanskursen. lördag 26 februari 2011

C++ Slumptalsfunktioner + switch-satsen

Tillfälle 14 (F): Fördjupat studium av parallellitet och synkronisering: processer, trådar, schemaläggning och signaler.

Objektorienterad Programkonstruktion, DD1346. Tentamen , kl

Programmeringsteknik med C och Matlab

Operativsystem ID1200/06 och ID2200/06 Tentamen TENA 6 hp :00-18:00

Instruktioner för att kunna programmera på skolans datorer

Föreläsning 9: Förprocessorn och stora program

Tentamen i. Programmering i språket C

Operativsystem ID1200/06 Tentamen :00-18:00

Recap Mera om nya typer Kort Fält. Programmering. Sommarkurs Verónica Gaspes. IDE-sektionen.

Programmering C: Tentamen of 5 Prioritet och associativitet hos operatorerna i C De viktigaste operatorerna: Prioritet Kategori Operator

Operativsystem ID1200/06 (ID2200/06 6hp) Tentamen :00-18:00

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

C-programmering, föreläsning 2 Jesper Wilhelmsson

Att använda pekare i. C-kod

Programmering, grundkurs, 8.0 hp HI1024, HI1900 etc., Tentamen TEN1. Måndagen den 10 januari 2011,

Code-Lite tutorial ( /RoJ)

TENTAMEN. Programmering Grundkurs (HI1900) Skrivtid 13:15-18:15. Tisdagen 26 april Tentamen består av 8 sidor

Tentamen ges för: Tentamensdatum: Tid:

Tentamen, EDAA10 Programmering i Java

Tentamen i Programmering

Tentamen i Programmering grundkurs och Programmering C

Vem är vem på kursen. Objektorienterad programvaruutveckling GU (DIT011) Kursbok Cay Horstmann: Big Java 3rd edition.

Posix Threads. En studie i förvirring eller Halleluja! Peter Eriksson, Signum Support AB 1

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING. Övningstentamen 1

Övningsuppgifter till föreläsning 2 Variabler och uttryck

Inledande programmering med C# (1DV402) Introduktion till C#

kl Tentaupplägg

Föreläsning 3. Programmering, C och programmeringsmiljö

Tentamen i. Programmering i språket C

Administrivia Programmering Grunderna i C Kortspel. Programmering. Sommarkurs Verónica Gaspes.

SCB :-0. Uno Holmer, Chalmers, höger 2 Ex. Induktiv definition av lista. // Basfall

Kompilera och exekvera Javakod

Tentamen i. för D1 m fl, även distanskursen. lördag 19 januari 2013

Grundläggande programmering med C# 7,5 högskolepoäng. Provmoment: Ladokkod: Tentamen ges för: TEN1 NGC011 ADAEK17, ASYST17 samt öppen för alla

Möte 10: Kommunikation mellan processer - (PI)

Operativsystem ID1200/06 (ID2200/06 6hp) Tentamen :00-18:00

DI-institutionen Sid 1 av 6 Hans-Edy Mårtensson Sten Sundin

2D1339 Programkonstruktion för F1, ht 2003

Anteckningar 1: Grundläggande saker

Föreläsning 3. Programmering, C och programmeringsmiljö

Realtidsstöd i Minix. En laborationrapport. Oktober 2012

Programmering i C++ En manual för kursen Datavetenskaplig introduktionskurs 5p

Lite mer om Javas stöd för fält. Programmering. Exempel: vad är det största talet? hh.se/db2004. Fält samt Input/Output

JAVA Mer om klasser och objektorientering

TENTAMEN I PROGRAMMERING. På tentamen ges graderade betyg:. 3:a 24 poäng, 4:a 36 poäng och 5:a 48 poäng

Systemkonstruktion LABORATION REALTIDSPROGRAMMERING

Tentamen. Datalogi I, grundkurs med Java 10p, 2D4112, Lördagen den 30 november 2002 kl , salar E33, E34

Strategier för att utnytja parallella system. Peter Kjellström NSC Upplysning

Högskolan Dalarna sid 1 av 7 DI-institutionen Hans-Edy Mårtensson Sten Sundin Micael Karlsson

Tentamen i DD2387 Programsystemkonstruktion med C++

Information Coding / Computer Graphics, ISY, LiTH CUDA. En lösning för generella beräkningar. En introduktion: Programmingsmodell och språk

Datorövningar. Grunderna i C/C++

Introduktion C-programmering

Laboration 1 Introduktion till Visual Basic 6.0

BINÄRA TRÄD. (X = pekarvärdet NULL): struct int_bt_node *pivot, *ny; X X X 12 X X 12 X X -3 X X

1.1 Runnable och Thread

Transkript:

Tentamen i Operativsystem, HI1025:LAB1-15 mars, 2017 Allmänna instruktioner. Tentamen innehåller 3 programmeringsproblem av den art vi exemplifierat på seminarier och i övningar. För godkänt betyg ska alla problem lösas. Alla processer som skapas måste inväntas och inga zombier (<defunct>) får synas i utskrifter av processers status/relationer. Uppgifter (1) Nedanstående program tar in två kommandoradsargument. Utvidga programmet så att det startar så många barnprocesser som anges av det första argumentet. Alla dessa barnprocesser ska läggas som barn underinit. Alla barnen ska göra en sleep()av en viss längd men ett av barnen, vars ordningsnummer anges av de andra kommandoradsargumentet, ska göra en kortare sleep() och alltså avslutas innan alla de andra. Systemanropet system("ps -e -o pid,ppid,pgid,sess,comm grep uppg1") ska användas vid tre tillfällen för att verifiera att programmet fungerar precis som det ska: 1. Då samtliga barn skapats och ligger under init, 2. Då ett av barnen avslutats. 3. Då samtliga barn avslutats. Dessa anrop finns i koden och får inte ändras. Programmet ser ut så här från början, sista raderna är de som inte får ändras, de ska ge den utskrift som krävs. I övrigt får vad som helst läggas till för att få programmet att fungera enligt kraven. #include <stdlib.h> main(int argc, char *argv[]) { int i, n, d; n=atoi(argv[1]); d=atoi(argv[2]); sleep(1); system("echo ============================== 1 second passed"); sleep(2); system("echo ============================== 3 seconds passed"); sleep(2); system("echo ============================== 5 seconds passed"); En godkänd testkörning: (Inga zombier!)./uppg1 4 2 ============================== 1 second passed 1944 1 1942 1695 uppg1 1946 1 1942 1695 uppg1 1948 1 1942 1695 uppg1 1950 1 1942 1695 uppg1 ============================== 3 seconds passed 1944 1 1942 1695 uppg1 1948 1 1942 1695 uppg1 1950 1 1942 1695 uppg1 ============================== 5 seconds passed och här ser vi att programmet anropas med 4 respektive 2 som kommandoradsargument, 4 barnprocesser (1944, 1946, 1948, och 1950) skapas och läggs under init och den andra barnprocessen (1946) avslutas och de andra fortsätter köra lite grann och till sist är alla avslutade. Kompilera med gcc uppg1.c -o uppg1 för att få processerna att heta just uppg1 så att de kan fångas upp av grep. Filen uppg1.c. innehåller koden ovan, redigera den och lämna in den som svar. 1

2 (2) Skriv ett program som skapar ett antal processer vars relationer beskrivs av nedanstående tidsdiagram a b k c Processen k ska defineras av följande kod i killer.c (som inte får ändras): int pid; while(read(0,&pid,sizeof(int))) { if(kill(pid,9)==0)write(1,&pid,sizeof(int)); else {pid=-pid; write(1,&pid,sizeof(int)); Processen k är alltså en killer som dödar den process vars processid den får på stdin. Hela programmet ska fungera så här: Processen a skapar processerna b och k som barn. Processen b skapar i sin tur barnet c och skickar c s processid via en pipe till k. Efter k har försökt döda c så skickar k sitt resultat via en annan pipe till a som inväntar både b och k. De fyra tjocka lodräta streckade strecken utgör checkpunkter där a ska göra anropet system("ps -o pid,ppid,comm"); för att kontrollera att processrelationerna är så som föreskrivs av tidsdiagrammet. Alltså, vid första system/ps-anropet ska a, b och c synas, vid andra anropet ska a, b, c och k synas, vid tredje ska a, k och b synas, vid fjärde (sista) anropet ska a och b synas. Du behöver experimentera med väl valda anrop till sleep() för att få det att fungera perfekt. (De tjocka heldragna pilarna representerar förstås de två pipes som behövs i programmet.) Vid ett väl valt tillfälle ska huvudprocessen a skriva ut processid på det barn som dödas, det är ju det som skickas från k till a. (Nedan ser vi det i och med Child killed: 3839..) Ledning: Det finns utförligt exemplifierat i exempelprogrammen som följer med hur man inkluderar externa program (som killer.c) inklusive omdirigeringen En provkörning kan se ut så här: (Inga zombier!)./uppg2 3838 3836 sh 3839 3837 uppg2 3840 3838 ps 3839 3837 uppg2 3841 3836 uppg2 3842 3836 sh 3843 3842 ps 3841 3836 k 3844 3836 sh 3845 3844 ps Child killed: 3839. 3846 3836 sh 3847 3846 ps Utskrifternas fullständighet kan variera något, bland annat kanske inte processen sh (som uppstår i samband med anropet till system("ps...")) finns med. Det viktiga är att er statusutskrift (som exemplifieras till vänster) ska överenstämma med tidsdiagrammet ovan så första anropet till system("ps...") verkligen visar processerna a, b och c men inte k, andra anropet ska visa alla fyra (a, b, c och k), tredje ska bara visa a, b och k och sista anropet ska bara visa a och b. Det är frågan om att lägga in sleep(...) på väl valda ställen i de olika ingående processerna för att få det att fungera.

(3) I laboration 3 studerades deadlock mellan ett godtyckligt antal körande trådar. Vi ska se på en enklare variant med bara två trådar men med en alternativ strategi för att undvika deadlock. Studera nedanstående två trådprogram (de finns förstås bland materialet): // uppg3a.c: int thread=0, run=20; pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; pthread_t t1, t2, decr_thr; int choose(int n){return rand()%n+1; void* tf1(void *par) { while(run>0) { srand(2*time(0)); pthread_mutex_lock(&m1); sleep(1); pthread_mutex_lock(&m2); dur=choose(3); while(dur--) {thread=1; sleep(1); thread=0; void* tf2(void *par) { while(run>0) { srand(3*time(0)); pthread_mutex_lock(&m2); sleep(1); pthread_mutex_lock(&m1); dur=choose(3); while(dur--) {thread=2; sleep(1); thread=0; void* decr(void* par){ while(run--)sleep(1); pthread_cancel(t1); pthread_cancel(t2); main(){ srand(time(0)); pthread_create(&t1,null,&tf1,null); pthread_create(&t2,null,&tf2,null); pthread_create(&decr_thr,null,&decr,null); while(run>0){ printf("%d:%d.\n", run, thread); sleep(1); pthread_join(t1,null); pthread_join(t2,null); pthread_join(decr_thr,null); Då programmet körs skapas ofta deadlock. Det finns två mutexar och en tråd anger att den har båda genom att sätta den globala variabeln thread till sitt nummer, antingen 1 eller 2. Denna skrivs ut av huvudprogrammet och om en 1:a skrivs ut betyder det alltså att tråd nr 1 har båda mutexarna, om en 2:a skrivs ut betyder det att tråd nr 2 har båda mutexarna. Det finns en tredje tråd också vars enda uppgift är att räkna ner variabeln run och när den når 0 så avlutas båda trådarna. Så är i alla fall tanken, men detta program fungerar inte så bra, deadlock skapas nämligen ganska ofta som sagt och det uttrycker sig genom att utskriften ofta bara blir en lång rad av nollor. Uppgiften består i att förstå och uttrycka varför detta program skapar deadlock och varför nästa program inte skapar deadlock. I uppgiften finns ett anrop till pthread cancel(), det enda det systemanropet gör här är att begära att en tråd blir avslutad. 3

4 Vi jämför detta program med nästa program som är en uppgraderad variant: // uppg3b.c int thread=0, run=20; pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER; pthread_t t1, t2, decr_thr; int choose(int n){return rand()%n+1; void* tf1(void *par) { while(run>0) { srand(2*time(0)); pthread_mutex_lock(&m1); if(!pthread_mutex_trylock(&m2)) { dur=choose(3); while(dur--) {thread=1; sleep(1); thread=0; else pthread_mutex_unlock(&m1); void* tf2(void *par) { while(run>0) { srand(3*time(0)); pthread_mutex_lock(&m2); if(!pthread_mutex_trylock(&m1)) { dur=choose(3); while(dur--) {thread=2; sleep(1); thread=0; else pthread_mutex_unlock(&m2); void* decr(void* par){ while(run--)sleep(1); pthread_cancel(t1); pthread_cancel(t2); main(){ srand(time(0)); pthread_create(&t1,null,&tf1,null); pthread_create(&t2,null,&tf2,null); pthread_create(&decr_thr,null,&decr,null); while(run>0){ printf("%d:%d.\n", run, thread); sleep(1); pthread_join(t1,null); pthread_join(t2,null); pthread_join(decr_thr,null); Båda programmen finns med i det material som kommer med själva tentan. Det finns en viktig skillnad i körningen mellan dessa båda program. På nästa sida ges ett antal provkörningar av de båda programmen och du kan själv ägna tid åt att provköra programmen. Den stora skillnaden mellan programmen är att det första programmet, som kallas uppg3a.c ofta slutar i att skriva ut en lång serie nollor, dvs ingen av de två arbetstrådarna har tillgång till båda mutexarna samtidigt. Medan det andra programmet, som kallas uppg3b.c, skriver ut både 1:or och 2:or under hela sin livstid. Därmed lyckas trådarna i uppg3b.c äga båda mutexarna under hela programmets körning.

5 Testkörning 1:./uppg3a 17:2. 16:2. 15:0. 1 12:0. 1 10:0. 8:0. 6:0. 5:0. 3:0. 2:0. Testkörning 2:./uppg3a 17:1. 16:0. 15:2. 14:2. 11:1. 10:1. 9:1. 5:1. 1:2. Testkörning 3:./uppg3b 1 16:1. 15:1. 1 1 12:0. 1 10:0. 8:1. 7:1. 6:1. 5:0. Testkörning 4:./uppg3b 1 16:2. 15:1. 14:1. 1 11:2. 10:2. 8:0. 6:1. 5:1. I de två första kolumnerna anges testkörningar av det första programmet. Som vi ser avslutas den första testkörningen med en lång serie nollor, det betyder att ingen av trådarna äger båda mutexarna. Den andra körningen, också av det första programmet, är i själva verket en ganska ovanlig körning, här skrivs det ut både ettor och tvåor under hela programmets livslängd. Men väldigt ofta när det första programmet körs, blir det till och med bara nollor! Men de andra två kolumnerna, som visar testkörningar av det andra programmet visar inte bara nollor, utan i båda körningarna finns ettor och tvåor under hela detta programs livslängd, i själva verket, då det andra programmet körs, blir det alltid ettor och tvåor under hela programmets livslängd. Din uppgift är att förklara varför det första programmet (uppg3a.c) ofta bara ger en massa nollor medan det andra programmet (uppg3b.c) alltid ger både ettor och tvåor under hela sin livslängd. Förklara detta med utgångspunkt från de båda programmens källkoder samt referenser till manualsidan för pthread mutex lock/trylock/unlock. Ge svaret i textform istället för att skriva några nya program. (Självklart kan du experimentera med att ändra i koden till programmen uppg3a/b.c men inget program kommer att bedömas som du lämnar in. Det som bedöms är din förklaring av programmens olika beteenden. (Det enda ni behöver veta om anropetpthread cancel är att det begär att en tråd avslutas, grubbla inte över det.)