Real-Time Systems (RTSYST)

Slides:



Advertisements
Verwante presentaties

Advertisements

Objectgeoriënteerd Programmeren in C++
CIMSOLUTIONS B.V. CIMSOLUTIONS Automation for Industry & Business SIG Embedded “Proces Ellende” André Vink CDP real-time embedded 28 september 2005.

Algoritmen en Datastructuren (ALDAT)
Programmeren met Alice
Real-Time Systems (RTSYST) Week C++ concurrent programmeren C++ heeft sinds C++11 een standaard library voor concurrent programmeren. Alternatieve.
Hogeschool HZ Zeeland 19 augustus 2003augustus 2003 Data Structuren & Algoritmen Week 1.
ICT Infrastructuren 26 november 2007 David N. Jansen.

BESTURINGS SYSTEMEN Vincent Naessens.
Gestructureerd programmeren in C
1 Device driver. 2 Hardware Operating Systeem Prog1Prog2 System calls/ API Device drivers Gebruiker afschermen van de hardware.
Real-Time Systems (RTSYST) Week 1. 2 Real-Time Systems (RTSYST) Onderwerpen: Concurrent programming (threads). Real-Time OS (VxWorks, QNX, FreeRTOS).
PROS2 Les 11 Programmeren en Software Engineering 2.
Java in Space Joffrey Lambregs. Agenda Introductie Waarom van C naar Java Tekortkomingen van Java Oplossingen JSR302 DAL-Levels Data diodes Werken in.
GESPRG Les 14 Gestructureerd programmeren in C. 174 Details! The devil is in the details.
‘Inleiding programmeren in Java’ SWI cursus: ‘Inleiding programmeren in Java’ 4e college Woe 19 januari 2000 drs. F. de Vries.
Instructie Programmeren Debuggen 5JJ70. Debuggen: Wat is het probleem Je programma compileert, maar werkt niet zoals verwacht, wat nu? Vraag je af: wat.
Hoofdstuk 6: Controle structuren
Inleiding Informatica Prof. Dr. O. De Troyer Hoofdstuk 10: Omgaan met problemen.
1/1/ / faculty of Computer Science eindhoven university of technology 5B040:Computerarchitectuur 2M200:Inleiding Computersystemen Sessie 7(1): Flow of.
Verdieping Programmeren in Java - deel 1 college 6 mei 2001.
Inleidend probleem Data structuur (hiërarchie van classes)
Numerieke Natuurkunde
MICPRG Les 11 Microcontroller Programmeren in C. 112 Datastructuren in C Werkgeheugen (PC en microcontroller): Statische datastructuren (vaste grootte):
Real-Time Systems (RTSYST) Week 2. Process/Thread states Scheduler = deel van OS dat de toestanden van processen/threads bepaald. OS gebruikt timerinterrupt.
Real-Time Systems (RTSYST) Week IPC inter process communication Shared variabele based (H5) Message based (H6) Kan ook gebruikt worden in systemen.
Real-Time Systems (RTSYST) Week Priority inheritance voorbeeld taakprioexecutionrelease time d4EEQVE4 c3EVVE2 b2EE2 a1EQQQQE0.
GESPRG Les 7 Gestructureerd programmeren in C. 92 Verwisselen Schrijf een functie waarmee twee int variabelen verwisseld kunnen worden. void wissel(int.
1 Datastructuren Introductie tot de programmeeropgaven in C++ Jan van Rijn
Operating Systems Informatica.
1 Datastructuren Een informele inleiding tot Skiplists Onderwerp 13.
Concurrency en Deadlock ICT Infrastructuren David N. Jansen Stallings hoofdstukken 5 en 6.
Tircms02-p les 4 Preprocessor In- en uitvoer Diversen.
HOGESCHOOL ROTTERDAM / CMI Computersystemen 2 (TIRCCMS02 - Operating systems)
Basisfuncties Operating System.
Tircms02-p les 2 Meer operatoren Arrays en pointers Types en conversie.
Tircms03-p les 4 Klassen. Abstracte datatypes in C struct stack { char info[100]; int top; }; void reset(stack *s) { s->top = -1; } void push(stack *s,
Besturingssysteem Vaak wordt de Engelse term gebruikt: Operating System ( OS ) Plaats van het OS in een computersysteem: Hardware Applicatie Operating.
Slide 1Programmatuur voor real-time controleYolande Berbers RTPReal-Time Programmatuur hoofdstuk 8: synchronisatie en communicatie met gedeelde variabelen.
Instructie Programmeren Task 7
Programmeren.
1 PI1 week 9 Complexiteit Sorteren Zoeken. 2 Complexiteit van algoritmen Hoeveel werk kost het uitvoeren van een algoritme (efficiëntie)? –tel het aantal.
Java Objectgeoriënteerd Programmeren in Java met BlueJ
Java Objectgeoriënteerd Programmeren in Java met BlueJ Hoofdstuk 7 Polymorfie en overerving © 2014, Gertjan Laan, versie 2.
Java Objectgeoriënteerd Programmeren in Java met BlueJ Hoofdstuk 8: Gebruikersinterface © 2014, Gertjan Laan, versie 2.
Studiehouding Ergens verstand van krijgen kost tijd… Uren die je alleen in je boeken doorbrengt maken het verschil. Er is niets mis met onafhankelijkheid.
 C++ heeft een inheritance mechanisme  Manier om functionaliteit te ‘erfen’ van een parrent class ◦ Polymorphisme ◦ Zoals we het ook in C# kennen.
Hoorcollege 1: efficiëntie en complexiteitsontwikkeling.
Hoorcollege 1: efficiëntie en complexiteitsontwikkeling.
Loops en errors Array's Random try catch for loop while loop do while loop.
GUI & classes Een Gui in een class steken en het object gebruiken.
De definitie van een object. Een object is een verzameling van eigenschappen en bewerkingen. Veel voorkomende objecten zijn: D (display) Gui (user interface)
Module code: Scheduling Het verdelen van processortijd onder processen en threads 1.
Programmeren. Wat is programmeren? Het schrijven van opdrachten voor de processor De processor “spreekt” machinetaal:
Operating Systems Informatica.
Programmeren.
Besturingssystemen 1 (TINBES01-1)
Gameprogrammeren: Objecten en geheugen
Tinpro015b-les 1 C++ voor C-kenners Voor Technische Informatica.
Tinpro015b-les5 Invoer en Uitvoer.
Tinpro015b-les3 Hfdst 3,4 Meer operatoren Functies.
Tinpro015b-les4 Klassen.
Besturingssystemen Ga verder met een muisklik..
SCALABLE DATA PROCESSING MET RABBITMQ
SQL Les February 2019.
Besturingssysteem.
Software Development fundamentals
Python – For loop + strings
Transcript van de presentatie:

Inhoud RTSYST Week 1 Week 2 Week 3 Week 4 Week 5 Week 6 Week 7

Real-Time Systems (RTSYST) Week 1

Real-Time Systems (RTSYST) Onderwerpen: Concurrent programming (threads). Real-Time OS (VxWorks, QNX, FreeRTOS). Concurrent programming in C en C++. Synchronisation and Communication. Real-Time faciliteiten (clocks, timeouts). Scheduling. Werkvormen: 14 lessen theorie + 7 lessen begeleid practicum. 5 uur/week zelfstudie (inclusief onbegeleid practicum).

Leermiddelen Boeken Blackboard en http://bd.eduweb.hhs.nl/rtsyst/ Real-Time Systems and Programming Languages (Fourth Edition), Alan Burns and Andy Wellings, ISBN: 9780321417459 Hoofdstuk 1, 4 t/m 6, 9 en 11. QNX Neutino 2, Robert Krten (Staat in D1.052) Blackboard en http://bd.eduweb.hhs.nl/rtsyst/ Studiewijzer met uitgebreide planning Practicumopdrachten + uitgebreide practicumhandleiding Sourcecode van alle voorbeelden Sheets Links

Real-Time Systeem Definitie(s): Systeem waarvan de reactietijd op een onvoorspelbare inputverandering voorspelbaar is. Systeem waarbij de uitvoer niet alleen correct moet zijn maar ook op het juiste moment.

Indeling Real-Time Systemen Hard real-time Missen van een deadline is fataal. Soft real-time Missen van een deadline is ongewenst. Interactief (niet real-time) Er zijn geen expliciete deadlines maar wachten is wel irritant.

Voorbeelden Real-Time Systeem Procesbesturing (meet en regeltechniek) Productie besturingssysteem (industriële automatisering) Embedded systemen ABS (Anti-Blokeer-Systeem) Pacemaker Besturing kruisraket Kopieer apparaat DVD recorder http://www.youtube.com/watch?v=2Fww5DnhblA

Karakteristieken Real-Time Systeem Groot en complex (niet altijd) Onderhoudbaar: uitbreidbaar, aanpasbaar en herbruikbaar Betrouwbaar en veilig Intensive care apparatuur Kerncentrale Automatische piloot Concurrent gedrag Multitasking, multiprocessor, distributed RTOS of RTL moet dit ondersteunen Timing faciliteiten Taak op bepaalde tijd starten, taak binnen bepaalde tijd afronden Interactie met hardware

Concurrent programming (1) Single processor system Multitasking m.b.v. time sharing Multi processor system met gedeeld geheugen (SMP) of multi-core processor systeem Parallel (true multitasking)

Concurrent programming (2) Distributed system (wordt verder niet behandeld in RTSYST) Parallel Verschillende systemen (elk met een eigen geheugen) verbonden met een netwerk

Why Concurrent programming Programma model komt overeen met de werkelijkheid Benutten van parallellisme in applicatie Zoek je weg in een doolhof Vergelijken van vingerafdrukken Processor beter benutten op single processor systeem

Sequential Maze Search

Concurrent Maze Search

Concurrent programming Processor beter benutten op single processor systeem X W C sneller X W C time c=calculate x=transmit w=wait for ACK

Beperking van parallellisme Amdahl's Law (boek p. 96) De versnelling (speedup) van een program door het gebruik van meerdere parallellle processoren (of cores) is begrensd door het deel van het programma dat sequentieel uitgevoerd moet worden. N = aantal processoren SN = speedup met N processors (cores) P = deel van het programma dat parallel uitgevoerd kan worden Voorbeeld: Bereken de maximale speedup voor een programma waarvan 25% sequentieel uitgevoerd moet worden? Wat is de maximale speedup bij 2, 4, 8 en 16 cores? (4) (1.60, 2.29, 2.91 en 3.37)

Process versus Thread Process Thread Eigen stack = veilig Eigen (data) memory map Eigen virtueel geheugen = veilig, communicatie = traag Process switch is traag (zwaar) Cache flush, MMU TLB flush Thread Gedeelde (data) memory map binnen hetzelfde process Gedeeld geheugen = onveilig Communicatie = snel Thread switch is snel (licht) binnen hetzelfde process Geen flushes

Process versus Thread Veel GPOSs (General Purpose Operating Systems) gebruiken: Processes om verschillende applicaties van elkaar te scheiden Threads om concurrency binnen applicatie mogelijk te maken Voorbeelden: Windows en Linux Veel RTOSs (Real-Time Operating Systems) gebruiken: Threads / Tasks om concurrency mogelijk te maken Voorbeeld: FreeRTOS QNX gebruikt processes en threads Wij behandelen alleen threads

QNX (POSIX compatible RTOS)

Huiswerk Bestudeer: Boek H1 t/m 1.3. Bestudeer: Artikel uit Embedded Computer Design: RTOS versus GPOS Achtergrondinformatie: Artikel The Free Lunch Is Over Artikel TLAs: QNX, RIM, ARM, CES, RPM, and MPH. An RTOS for the Automotively Inclined Web seminar: Why do I need an RTOS anyway?

Concurrent programming Sequentiële programmeertaal (C of C++) + OS (Linux, Windows, QNX, FreeRTOS) Portable als taal en OS portable zijn(IEEE POSIX 1003 compliant) Meerdere talen combineren in 1 applicatie is mogelijk Concurrent programmeertaal (ADA, Java, C#, C++11, C11) Beter leesbaar Beter onderhoudbaar Portable als taal portable is Concurrent framework (OpenMP, OpenCL) Portable (ondersteund meerdere talen en OS-en) Middleware (RPC, RMI, CORBA) Vereenvoudigt bouwen van distributed applicaties

Fundamentele vragen Hoe kun je processen / threads beheren? Support in OS via API (= Application Programming Interface) of library Support in programmeertaal Hoe kunnen processen / threads communiceren? IPC = Inter Process Communication (term wordt ook voor communicatie tussen threads gebruikt) Hoe kun je processen / threads synchroniseren? IPC zonder dataoverdracht.

Concurrent OOP Actieve objecten Passieve objecten Object heeft eigen thread of process. Versturen zelf actief (spontaan) messages. Passieve objecten Object heeft geen eigen thread of process. Reageren op binnenkomende messages en kunnen als reactie: Zelf message versturen. Toestand van aanroepende thread of process veranderen (b.v. van running naar waiting).

Specificatie van concurrent taken System call UNIX, win32 Concurrent blok Concurrent Pascal, High Performance Fortran Expliciete declaratie ADA, Java pthread_t t; pthread_create(&t, NULL, &func, NULL) cobegin s1; s2; s3 coend; task body NAME is begin … end NAME;

Concurrent execution IEEE POSIX 1003.1-2013 fork() en wait() posix_spawn() Combinatie van fork(), exec() en wait() pthread_create() en pthread_join() Documentatie: IEEE Std 1003.1-2013 = The Open Group Base Specifications Issue 7 http://pubs.opengroup.org/onlinepubs/9699919799/ QNX documentation: http://www.qnx.com/developer/docs/

Pointers naar functies In C kun je een pointer naar een functie definiëren. De waarde van de pointer is het beginadres (van de code) van de functie. pnf is een pointer naar een functie met een int als parameter en een int returnwaarde #include <stdio.h> int kwadraat(int c) { return c * c; } int dubbel(int c) { return c + c; int main(void) { int a = 7, b; int (*pnf)(int); pnf = &dubbel; b = (*pnf)(a); Waarom haakjes?

Pointers naar functies In C kun je een pointer naar een functie definiëren. De waarde van de pointer is het beginadres (van de code) van de functie. pnf wijst naar de functie dubbel (pnf wordt gelijk aan het adres van de functie dubbel) #include <stdio.h> int kwadraat(int c) { return c * c; } int dubbel(int c) { return c + c; int main(void) { int a = 7, b; int (*pnf)(int); pnf = &dubbel; b = (*pnf)(a);

Pointers naar functies In C kun je een pointer naar een functie definiëren. De waarde van de pointer is het beginadres (van de code) van de functie. De functie waar pnf naar wijst wordt aangeroepen met de waarde van a als argument #include <stdio.h> int kwadraat(int c) { return c * c; } int dubbel(int c) { return c + c; int main(void) { int a = 7, b; int (*pnf)(int); pnf = &dubbel; b = (*pnf)(a); Waarom haakjes?

Pointers naar functies Verkorte schrijfwijze. Naam van een functie  beginadres (van de code) van de functie. #include <stdio.h> int kwadraat(int c) { return c * c; } int dubbel(int c) { return c + c; int main(void) { int a = 7, b; int (*pnf)(int); pnf = dubbel; b = pnf(a);

Pointers naar functies Wat is het nut? Functie als parameter. #include <stdio.h> /* … */ void printTabel(int (*p)(int), int van, int tot, int stap) { int x; for (x = van; x < tot; x += stap) { printf("%10d %10d\n", x, (*p)(x)); } int main(void) { printf("De kwadraten van 1 t/m 10\n"); printTabel(&kwadraat, 1, 11, 1); printf("De dubbelen van de drievouden van 0 t/m 30\n"); printTabel(&dubbel, 0, 31, 3);

Uitvoer De kwadraten van 1 t/m 10 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 9 81 10 100 De dubbelen van de drievouden van 0 t/m 30 0 0 3 6 6 12 9 18 12 24 15 30 18 36 21 42 24 48 27 54 30 60

void* Een void* kan wijzen naar elk type. Als we de waarde willen ophalen waar een void* naar wijst dan moeten we de pointer casten naar het juiste type. int main(void) { int i = 3; double d = 4.3; void* vp = &i; printf("%d\n", *(int*)vp); vp = &d; printf("%lf\n", *(double*)vp); return EXIT_SUCCESS; }

pthread (1 van 3) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <pthread.h> void check(int error) { if (error != 0) { fprintf(stderr, "Error: %s\n", strerror(error)); exit(EXIT_FAILURE); }

pthread (2 van 3) void* print1(void* par) { struct timespec ts = {0, 10000000}; int i; for (i = 0; i < 10; i++) { nanosleep(&ts, NULL); printf("print1\n"); } return NULL; void* print2(void* par) { struct timespec ts = {0, 20000000}; printf("print2\n");

pthread (1 van 3) int main(void) { pthread_t t1, t2; print1 print2 int main(void) { pthread_t t1, t2; check( pthread_create(&t1, NULL, &print1, NULL) ); check( pthread_create(&t2, NULL, &print2, NULL) ); check( pthread_join(t1, NULL) ); check( pthread_join(t2, NULL) ); return EXIT_SUCCESS; }

pthread Alternatieve implementatie typedef struct { char* msg; long ns; } par_t; void* print(void* p) { par_t* pp = p; struct timespec ts = {0, pp->ns}; int i; for (i = 0; i < 10; i++) { nanosleep(&ts, NULL); printf(pp->msg); } return NULL; int main(void) { pthread_t t1, t2; par_t p1 = {"print1\n", 10000000}; par_t p2 = {"print2\n", 20000000}; check( pthread_create(&t1, NULL, &print, &p1) ); check( pthread_create(&t2, NULL, &print, &p2) ); // ... Pas op: void*

Command line argumenten Aan een programma kunnen command line argumenten worden doorgegeven. Deze zijn in main beschikbaar via de parameters argc en argv int main(int argc, char* argv[]) { … } argv[0] is de naam van het programma. argc geeft het aantal meegegeven parameters + 1 argv[1] is de eerste meegegeven parameter. Enz. int main(int argc, char* argv[]) { int i; for (i = 0; i < argc; i++) { printf("%s\n", argv[i]); } return EXIT_SUCCESS; $ a.exe dat is leuk a.exe dat is leuk

Real-Time Systems (RTSYST) Week 2

Process/Thread states ready running Wait for I/O or … blocked / sleeping I/O or … completion Scheduler = deel van OS dat de toestanden van processen/threads bepaald. OS gebruikt timerinterrupt om Scheduler regelmatig aan te roepen. In een single processor N-core machine kunnen maximaal N processen/threads running zijn. RTOS gebruikt preemptive priority based scheduling.

Problem with shared memory volatile int aantal = 0; void* teller(void* par) { int i; for (i = 0; i < 10000000; i++) { aantal++; } return NULL; int main(void) { pthread_t t1, t2, t3; check( pthread_create(&t1, NULL, &teller, NULL) ); check( pthread_create(&t2, NULL, &teller, NULL) ); check( pthread_create(&t3, NULL, &teller, NULL) ); check( pthread_join(t1, NULL) ); check( pthread_join(t2, NULL) ); check( pthread_join(t3, NULL) ); printf("aantal = %d\n", aantal); # ./a.out aantal = 26404037 aantal = 30000000 aantal = 27118627 # time ./a.out aantal = 25570438 0.10s real 0.08s user 0.01s system Wat is de uitvoer?

Problem with shared memory De operatie aantal++ is niet ondeelbaar (in machinecode). Bijvoorbeeld: load reg, aantal inc reg store reg, aantal Wat is de minimale en de maximale waarde die geprint kan worden? 10000000 en 30000000 Wat gebeurt er als op dit moment van taak gewisseld wordt?

Oplossing? Er zijn oplossingen die gebruik maken van variabelen (2 vlaggen en 1 beurt variabele) en busy waiting. Dekker’s algoritme: http://en.wikipedia.org/wiki/Dekker's_algorithm Peterson’s algorithm (zie boek paragraaf 5.2) http://en.wikipedia.org/wiki/Peterson's_algorithm Busy waiting kost klokcycles! OSen bieden oplossingen zonder busy waiting.

IPC inter process communication Shared variabele based (H8) Busy waiting Inefficiënt Mutual exclusion is moeilijk (Dekker of Petterson algoritme) Spinlock (niet in H8 wel IEEE Std 1003.1) Mutex Semaphore Monitor Mutex en Conditionele variabelen Barrier (niet in H8 wel IEEE Std 1003.1) ReadWriteLock (niet in H8 wel IEEE Std 1003.1) Message based (H9)

Mutex Simpele manier om mutual exclusive kritisch gebied te creëren. Er kan zich maar 1 process/thread in het kritische gebied bevinden. Mutex heeft een lock en een unlock functie. OS zorgt dat deze functies ondeelbaar zijn! Aan het begin van het kritische gebied lock je de mutex en aan het einde van het kritische gebied unlock je de mutex.

Process/Thread states Lock mutex m which is not locked ready running Lock mutex m which is already locked Unlock mutex m Blocked on m

Bij RTOS afhankelijk van prioriteit! Mutex Als een thread t een mutex m probeert te locken die al locked is dan wordt de thread t blocked on m. We zeggen ook wel: Thread t wacht op mutex m. Thread t slaapt tot mutex m unlocked wordt. Volgorde van wakker maken: concurrent: random general purpose: FIFO real-time: hoogste prioriteit Bij RTOS afhankelijk van prioriteit!

Mutex with shared memory Geen volatile meer nodig! int aantal = 0; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; void* teller(void* par) { int i; for (i = 0; i < 10000000; i++) { check( pthread_mutex_lock(&m) ); aantal++; check( pthread_mutex_unlock(&m) ); } return NULL; int main(void) { // idem. # ./a.out aantal = 30000000 # time ./a.out 2.03s real 1.96s user 0.02s system 20x trager!

Deadlock (voorbeeld) Er zijn 5 filosofen. Het leven van een filosoof bestaat uit: Denken Eten Elke filosoof heeft één bord en één vork. Om te kunnen eten heeft de filosoof 2 vorken nodig.

Dining Philosophers pthread_mutex_t vork[5] = { PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER }; void* philosopher(void* par) { int i = *(int*)par; while (1) { printf("philosopher %d is sleeping\n", i); sleep(1); check( pthread_mutex_lock(&vork[i]) ); check( pthread_mutex_lock(&vork[(i + 1) % 5]) ); printf("philosopher %d is eating\n", i); check( pthread_mutex_unlock(&vork[i]) ); check( pthread_mutex_unlock(&vork[(i + 1) % 5]) ); } return NULL;

Dining Philosophers Dit programma kan vastlopen (deadlock)! int main(void) { int i; pthread_t t[5]; for (i = 0; i < 5; i++) { check( pthread_create(&t[i], NULL, &philosopher, &i) ); } check( pthread_join(t[i], NULL) ); return EXIT_SUCCESS; Dit programma kan vastlopen (deadlock)! Oplossing? Zie huiswerk verderop (uitwerking in theorieplanning).

Bij RTOS afhankelijk van prioriteit! Semaphore Bewerkingen: Psem (prolaag (probeer te verlagen), wait): ga wachten (slapen) als count == 0 anders verlaag count met 1. Vsem (verhoog, signal, post): maak een wachtend proces (of thread) wakker als count == 0 anders verhoog count met 1. Volgorde van vrijgeven (wakker maken): concurrent: random general purpose: FIFO real-time: hoogste prioriteit Voorbeeld: Zie practicum en BlackBoard. Gebruik is erg foutgevoelig. Abstractere (higher-level) oplossing nodig. Bij RTOS afhankelijk van prioriteit! Edsger Dijkstra

Uitwerking staat op BlackBoard. Huiswerk Los het probleem van de dinerende filosofen op door er m.b.v. een semaphore voor te zorgen dat er niet meer dan 4 filosofen tegelijkertijd aan tafel kunnen. Uitwerking staat op BlackBoard.

Semaphore versus Mutex Semaphore kan ook bij processes worden gebruikt. Mutex alleen bij theads. Mutex alleen voor mutual exclusion (thread die lock uitvoert moet ook unlock uitvoeren). Semaphore kan ook voor andere synchronisatie doeleinden worden gebruikt. Huiswerk: Thread a bestaat uit twee sequentiële delen a1 en a2. Thread b bestaat uit twee sequentiële delen b1 en b2. Thread c bestaat uit twee sequentiële delen c1 en c2. Zorg er voor (met behulp van een semaphoor) dat de delen b2 en c2 altijd na deel a1 worden uitgevoerd.

Bij RTOS afhankelijk van prioriteit! Monitor Een monitor is een poging om de problemen van semaphoren (zie boek 5.4.8) op te lossen. Een monitor is een taalconstructie en moet dus door de programmeertaal worden ondersteund. Een monitor is een module (verzameling functies + data). De data in de module is alleen toegankelijk via de functies van de module. De monitor zorgt automatisch voor mutual exclusion. Er kan maar 1 proces tegelijk de monitor binnengaan. Synchroniseren kan met behulp van conditionele variabelen. Bij RTOS afhankelijk van prioriteit! Tony Hoare

Conditionele variabelen Een cv bevindt zich in een monitor. Bewerkingen: wait = verlaat de monitor en wacht (slaap) tot conditie gesignaleerd wordt. signal (notify) = maak een proces wakker dat op deze conditie wacht. Mutual exclusion blijft gegarandeerd: Een proces dat wakker wordt moet wachten tot de monitor vrij is. Bij RTOS afhankelijk van prioriteit! Bij RTOS afhankelijk van prioriteit!

Monitor IEEE Std 1003.1 POSIX POSIX definieert geen monitors (monitor is een taalconstructie). Maar wel: mutex conditionele variabele Hiermee kun je zelf een (soort van) monitor maken.

Mutex voor mutual exclusion Bewerkingen: pthread_mutex_init pthread_mutex_destroy pthread_mutex_lock Bezet de mutex. Wacht (ga slapen) als de mutex al bezet is. pthread_mutex_trylock Return met EBUSY als mutex al bezet is. pthread_mutex_unlock Geef de mutex vrij (maak een proces dat op de mutex staat te wachten wakker). Bij RTOS afhankelijk van prioriteit!

Conditionele variabele Een POSIX conditionele variabele is altijd gekoppeld met een POSIX mutex. Bewerkingen: pthread_cond_init pthread_cond_destroy pthread_cond_wait Gekoppelde mutex moet bezet zijn. Wacht (ga slapen) tot conditie gesignaleerd wordt en geef gekoppelde mutex vrij. pthread_cond_signal Maakt (minstens) 1 van de threads die op deze conditie wachten wakker. Een proces dat wakker wordt wacht op de mutex voordat pthread_cond_wait verlaten wordt. pthread_cond_broadcast Maak alle threads wakker die op deze conditie wachten. Bij RTOS afhankelijk van prioriteit!

Monitor voorbeeld #include <pthread.h> int ei_teller = 0; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t c = PTHREAD_COND_INITIALIZER; // consumer thread(s) // ... pthread_mutex_lock(&m); while (ei_teller < 12) pthread_cond_wait(&c, &m); ei_teller -= 12; pthread_mutex_unlock(&m);

Monitor voorbeeld // producer thread(s) // ... pthread_mutex_lock(&m); ei_teller += n; pthread_cond_broadcast(&c); pthread_mutex_unlock(&m); Waarom moeten we pthread_cond_broadcast gebruiken in plaats van pthread_cond_signal? Omdat er meerdere consumers kunnen zijn en die moeten allemaal wakker gemaakt worden!

Uitwerking staat op BlackBoard. Huiswerk Los het probleem van de dinerende filosofen op door er m.b.v. een monitor (mutex i.c.m. conditionele variabele) voor te zorgen dat er niet meer dan 4 filosofen tegelijkertijd aan tafel kunnen. Uitwerking staat op BlackBoard.

Real-Time Systems (RTSYST) Week 3

C++ concurrent programmeren C++ heeft sinds C++11 een standaard library voor concurrent programmeren. Alternatieve libraries: Boost Thread library http://www.boost.org/ Intel Threading Building Blocks (TBB) http://www.threadingbuildingblocks.org/ Microsoft Parallel Pattern Library (PPL) http://msdn.microsoft.com/en-us/library/dd492418.aspx Open Multi-Processing (OpenMP) http://openmp.org Er zijn ook uitbreidingen van C++ die concurrency aan de taal toevoegen (met taalconstructies). μC++ voegt o.a. taalconstructies task en monitor toe. http://plg.uwaterloo.ca/~usystem/uC++.html Beschikbaar in MS VC++ ≥2012 en in GCC ≥4.7 Real-Time?

C++11 concurrency Threads Synchronisatie Asynchrone taken en Futures Mutexen Locks Conditionele variabelen Call once Asynchrone taken en Futures Atomics

C++11 Thread voorbeeld 1 (1) #include <thread> #include <iostream> using namespace std; void print1() { for (int i = 0; i < 10; ++i) { this_thread::sleep_for(chrono::milliseconds(10)); cout << "print1" << endl; } void print2() { this_thread::sleep_for(chrono::milliseconds(20)); cout << "print2" << endl;

C++11 Thread voorbeeld 1 (2) int main() { thread t1(&print1); thread t2(&print2); t1.join(); t2.join(); return 0; }

Wel type-safe (in tegenstelling tot pthreads). C++11 Thread voorbeeld 2 print1 print2 #include <thread> // ... void print(int delay, const string& msg) { for (int i = 0; i < 10; ++i) { this_thread::sleep_for( chrono::milliseconds(delay)); cout << msg << endl; } int main() { thread t1(&print, 10, "print1"); thread t2(&print, 20, "print2"); t1.join(); t2.join(); return 0; Wel type-safe (in tegenstelling tot pthreads).

C++11 Thread thread::hardware_concurrency() t.native_handle() Geeft het aantal hardware threads wat op het huidige systeem beschikbaar is (= aantal CPU’s of cores of hyperthreading units), of 0 als deze informatie niet beschikbaar is. t.native_handle() Geeft een instantie van native_handle_type wat gebruikt kan worden met de platform-specific API om de onderliggende implementatie te programmeren. Kan in een real-time pthread omgeving gebruikt worden om de prioriteit in te stellen. C++11 std: The presence of native_handle() and its semantics is implementation-defined. Actual use of this member is inherently non-portable.

C++11 Synchronization Mutexen Locks Conditionele variabelen mutex void lock(); bool try_lock(); void unlock(); recursive_mutex Idem maar telt aantal locks (en aantal unlocks). Locks Conditionele variabelen

C++11 Mutex voorbeeld y x==y x class Point { public: Point(): x(0), y(0) { } void stepNorthEast() { ++x; ++y; bool isNorthEast() const { return x == y; private: int x, y; }; y x==y x Wat gebeurt er als deze class in een multi-threaded omgeving gebruikt wordt?

C++11 Mutex voorbeeld class TestPoint { private: Point p; void thread1() { for (int i = 0; i < 20000000; ++i) p.stepNorthEast(); } void thread2() { if (!p.isNorthEast()) cout << "Probleem!" << endl; public: void test() { thread t1(&TestPoint::thread1, this); thread t2(&TestPoint::thread2, this); t1.join(); t2.join(); cout << "Einde." << endl; }; Probleem! … Einde.

Kan aangepast worden in const memberfunctie C++11 Mutex voorbeeld class Point { public: Point(): x(0), y(0) { } void stepNorthEast() { m.lock(); ++x; ++y; m.unlock(); } bool isNorthEast() const { bool res = x == y; return res; private: mutable mutex m; int x, y; }; Einde. Run-time Zonder mutex 0.265 s Met mutex 103.482 s Kan aangepast worden in const memberfunctie

Je wilt niet onnodig wachten! C++11 Mutex voorbeeld class Point { public: Point(): x(0), y(0) { } void stepNorthEast() { m.lock(); ++x; ++y; m.unlock(); } bool isNorthEast() const { m.lock(); bool res = x == y; m.unlock(); return res; bool isWithinLimits() const { m.lock(); bool res = x >= 0 && x <= 1000000 && y >= 0 && y <= 1000000; private: mutable mutex m; int x, y; }; Je wilt niet onnodig wachten!

isNorthEast() en isWithinLimits() kunnen nu parallel draaien! boost::shared_mutex class Point { public: Point(): x(0), y(0) { } void stepNorthEast() { m.lock(); ++x; ++y; m.unlock(); } bool isNorthEast() const { m.lock_shared(); bool res = x == y; m.unlock_shared(); return res; bool isWithinLimits() const { m.lock_shared(); bool res = x >= 0 && x <= 1000000 && && y >= 0 && y <= 1000000; private: mutable boost::shared_mutex m; int x, y; }; isNorthEast() en isWithinLimits() kunnen nu parallel draaien!

C++11 Mutex C++11 kent geen shared_mutex Je kunt zelf met behulp van conditionele variabelen en mutexen een multiple readers / single-writer mutex maken. Huiswerk: Implementeer zelf een shared_mutex class met de in C++11 beschikbare mutex en condition_variable.

Zie C++ exceptions (OGOPRG dictaat par.6.8). C++11 Synchronization Een lock maakt het gebruik van een mutex eenvoudiger en exception safe. Mutexen Locks lock_guard Gebruikt RAII (Resource Acquisition Is Initialization): lock() mutex in constructor, unlock() mutex in destructor unique_lock Idem als lock_guard + lock(), try_lock() en unlock() memberfuncties Conditionele variabelen Zie C++ exceptions (OGOPRG dictaat par.6.8).

C++11 Lock voorbeeld class Point { public: Point(): x(0), y(0) { } void stepNorthEast() { lock_guard<mutex> lock(m); ++x; ++y; bool isNorthEast() const { return x == y; private: mutable mutex m; int x, y; };

Wat gaat er mis als at een exception gooit? C++11 Lock voorbeeld vector<int> v; mutex m; // ... m.lock(); v.at(10) = 27; m.unlock(); m.lock(); try { v.at(10) = 27; m.unlock(); catch(...) { throw; } Niet handig! Wat gaat er mis als at een exception gooit? Oplossing ? Oplossing ! { lock_guard<mutex> l(m); v.at(10) = 27; }

C++11 Synchronization Mutexen Locks Conditionele variabelen conditional_variable void notify_one(); void notify_all(); void wait(unique_lock<mutex>& lock); void wait(unique_lock<mutex>& lock, pred_type pred); conditional_variable_any Idem maar werkt met elk type lock

C++11 Monitor voorbeeld #include <thread> #include <mutex> #include <condition_variable> int ei_teller = 0; mutex m; condition_variable c; // consumer thread(s) // ... unique_lock<mutex> lock(m); while (ei_teller < 12) c.wait(lock); ei_teller -= 12;

Waarom moeten we notify_all gebruiken in plaats van notify_one? C++ Monitor voorbeeld // producer thread(s) // ... lock_guard<mutex> lock(m); ei_teller += n; c.notify_all(); Waarom moeten we notify_all gebruiken in plaats van notify_one? Omdat er meerdere consumers kunnen zijn en die moeten allemaal wakker gemaakt worden!

Monitor voorbeeld while (ei_teller < 12) c.wait(lock); // alternatief met predicate functie: bool predicate() { return ei_teller >= 12; } // ... c.wait(lock, &predicate);

Lambda functie C++11 Een lambda functie is een anonieme functie die eenmalig gebruikt wordt als een functie object (functor). De lambda functie wordt gedefinieerd op de plaats waar het functie object nodig is. Een lambda functie kan dus als predicate gebruikt worden.

geen hergebruik mogelijk Monitor voorbeeld while (ei_teller < 12) c.wait(lock); // alternatief met predicate functie: bool predicate() { return ei_teller >= 12; } // ... c.wait(lock, &predicate); // alternatief met lambda functie c.wait(lock, []() { }); Voordeel? “eenvoudige” syntax Nadeel? geen hergebruik mogelijk

Boost Synchronization Mutexen Locks Conditionele variabelen Barrier boost::barrier barrier(unsigned count); bool wait(); Een barrier is een ontmoetingspunt (rendezvous). Pas nadat count threads een wait hebben gedaan mogen ze samen verder.

C++11 Synchronization Mutexen Locks Conditionele variabelen C++11 kent geen barrier Huiswerk: Implementeer zelf een barrier class met de in C++11 beschikbare mutex en condition_variable. barrier(unsigned count); bool wait(); Een barrier is een ontmoetingspunt (rendezvous). Pas nadat count threads een wait hebben gedaan mogen ze samen verder.

C++11 concurrency Memory model Threads Synchronisatie Mutexen Locks Conditionele variabelen Call once Asynchrone taken en Futures Atomics

async en future Bedoeld om eenvoudig gebruik van concurrency mogelijk te maken. Met behulp van async kunnen we een functie f als een asynchrone taak starten. We krijgen dan een future object terug (van hetzelfde type als het returntype van de functie f). We kunnen de memberfunctie get() van dit future object gebruiken om het resultaat van de (asynchrone) functie f op te vragen (indien nodig wordt er gewacht). De asynchrone taak kan in een aparte thread uitgevoerd worden (dat bepaalt de implementatie / de programmeur).

async voorbeeld #include <vector> #include <iostream> using namespace std; int som(const vector<int>& v) { int s = 0; for (auto e: v) s += e; return s; } int main() { vector<int> v1(10000000, 1); vector<int> v2( 5000000, 2); vector<int> v3( 5000000, 4); cout << "som=" << som(v1) + som(v2) + som(v3) << endl; cin.get(); return 0; som=40000000 Tijdsduur: 7.97 sec som(v1), som(v2) en som(v3) kunnen parallel worden uitgevoerd. Hoe vertellen we dat aan de compiler?

De implementatie bepaalt of er aparte theads worden gestart! async voorbeeld #include <future> #include <vector> #include <iostream> using namespace std; int som(const vector<int>& v) { /* idem */ } int main() { vector<int> v1(10000000, 1); vector<int> v2( 5000000, 2); vector<int> v3( 5000000, 4); future<int> s1 = async(&som, ref(v1)); future<int> s2 = async(&som, ref(v2)); future<int> s3 = async(&som, ref(v3)); cout << "som=" << s1.get() + s2.get() + s3.get() << endl; cin.get(); return 0; De implementatie bepaalt of er aparte theads worden gestart! som=40000000 Tijdsduur: 3.99 sec Waarom niet 3x zo snel?

async voorbeeld (met auto) #include <future> #include <vector> #include <iostream> using namespace std; int som(const vector<int>& v) { /* idem */ } int main() { vector<int> v1(10000000, 1); vector<int> v2( 5000000, 2); vector<int> v3( 5000000, 4); auto s1 = async(&som, ref(v1)); auto s2 = async(&som, ref(v2)); auto s3 = async(&som, ref(v3)); cout << "som=" << s1.get() + s2.get() + s3.get() << endl; cin.get(); return 0; De implementatie bepaalt of er aparte theads worden gestart!

async voorbeeld #include <future> #include <vector> #include <iostream> using namespace std; int som(const vector<int>& v) { /* idem */ } int main() { vector<int> v1(1000000, 1); vector<int> v2( 500000, 2); vector<int> v3( 500000, 4); auto s1 = async(launch::async, &som, ref(v1)); auto s2 = async(launch::deferred, &som, ref(v2)); auto s3 = async(launch::async, &som, ref(v3)); cout << "som=" << s1.get() + s2.get() + s3.get() << endl; cin.get(); return 0; De programmeur bepaald of er aparte theads worden gestart! Start aparte thread Start geen aparte thread

async voorbeeld (deferred) #include <future> #include <vector> #include <iostream> using namespace std; int som(const vector<int>& v) { /* idem */ } int main() { vector<int> v1(10000000, 1); vector<int> v2( 5000000, 2); vector<int> v3( 5000000, 4); auto s1 = async(launch::deferred, &som, ref(v1)); auto s2 = async(launch::deferred, &som, ref(v2)); auto s3 = async(launch::deferred, &som, ref(v3)); cout << "som=" << s1.get() + s2.get() + s3.get() << endl; cin.get(); return 0; De implementatie start geen aparte theads! som=40000000 Tijdsduur: 7.92 sec

C++11 concurrency Memory model Threads Synchronisatie Mutexen Locks Conditionele variabelen Call once Asynchrone taken en Futures Atomics

Atomics Een variabele van het type atomic<T> kan (zonder problemen) gedeeld worden door meerdere threads. T kan alleen een POD (Plain Old Datatype) zijn. De implementatie bepaalt of busy-waiting (lock-free) of locking wordt gebruikt. Lock-free is vaak sneller.

Mutex probleem #include <thread> #include <iostream> using namespace std; volatile int aantal = 0; void teller() { for (int i = 0; i < 100000; ++i) { ++aantal; } int main(void) { thread t1(&teller), t2(&teller), t3(&teller); t1.join(); t2.join(); t3.join(); cout << "aantal = " << aantal << endl; return 0; $ ./a.exe aantal = 177395 aantal = 190237 aantal = 151421 $ time ./a.exe aantal = 199184 0.065 s real

Mutex oplossing mutex #include <thread> #include <mutex> #include <iostream> using namespace std; int aantal = 0; mutex m; void teller() { for (int i = 0; i < 100000; ++i) { m.lock(); ++aantal; m.unlock(); } int main(void) { /* idem */ $ ./a.exe aantal = 300000 $ time ./a.exe 2.397 s real

Mutex oplossing lock_guard #include <thread> #include <mutex> #include <iostream> using namespace std; int aantal = 0; mutex m; void teller() { for (int i = 0; i < 100000; ++i) { lock_guard<mutex> l(m); ++aantal; } int main(void) { /* idem */ $ ./a.exe aantal = 300000 $ time ./a.exe 2.496 s real

Mutex oplossing atomic #include <thread> #include <atomic> #include <iostream> using namespace std; atomic<int> aantal(0); void teller() { for (int i = 0; i < 100000; ++i) { ++aantal; } int main(void) { /* idem */ $ ./a.exe aantal = 300000 $ time ./a.exe 0.610 s real

Vergelijk mutex oplossingen Programma Correct? Executietijd mutex_problem Nee 0.065 s mutex_solution_mutex Ja 2.397 s mutex_soution_guard_lock 2.496 s mutex_solution_atomic 0.610 s

Meer over C++11 concurrency... Memory model Threads Synchronisatie Mutexen Locks Conditionele variabelen Call once Asynchrone taken en Futures Atomics C++ Concurrency in Action Practical Multithreading Anthony Williams February, 2012 | 528 pages ISBN: 9781933988771

Real-Time Systems (RTSYST) Week 4

IPC inter process communication Shared variabele based (H5) Message based (H6) Kan ook gebruikt worden in systemen zonder gedeeld geheugen (gedistribueerde systemen). POSIX: message queue QNX: Neutrino kernel is volledig message based. Zie H2 QNX boek.

Messages Synchronisatie Receive: Wacht als er nog niet gezonden is. Send: Asynchroon: wacht niet. Buffer nodig, wat als buffer vol is? Bijvoorbeeld: POSIX message queue. Synchroon (rendezvous): wacht op ontvangst. Geen buffer nodig. Remote invocation (extended rendezvous): wacht op antwoord. Bijvoorbeeld: QNX messages.

Messages asyn_send receive syn_send receive ri_send receive reply

Messages Synchroon met behulp van 2 asynchrone messages Proces 1 asyn_send(mes) receive(ack) Proces 2 receive(mes) async_send(ack) Remote invocation met behulp van 4 asynchrone messages Proces 1 asyn_send(mes) receive(ack) receive(reply) async_send(ack) Proces 2 receive(mes) async_send(ack) //... construct reply async_send(reply) receive(ack)

Asynchroon Voordelen: Nadelen: Flexibeler. Buffers nodig. Complexer: Aparte message voor acknowledge en/of reply nodig. Moeilijk om correctheid van een programma te bewijzen. Asynchrone communicatie kan in een OS dat op synchrone messages is gebaseerd (QNX) worden gerealiseerd door expliciete buffer threads.

Messages Adressering Direct: sender geeft receiver proces (of thread) op. Indirect: sender geeft port, channel of mailbox op. Symmetrisch: receiver geeft sender, port, channel of mailbox op. Asymmetrisch: receiver geeft niets op.

Messages inhoud Tussen threads: Tussen processen: Tussen machines: Geen beperkingen. Tussen processen: Geen pointers (elk proces heeft zijn eigen memory map). Tussen machines: Geen pointers + mogelijk problemen met representatie: Character codering. Big-endian, Little-endian.

POSIX message queue Kenmerken: Synchronisatie: asynchroon Adressering: indirect en symmetrisch Meerdere senders en receivers kunnen dezelfde mq gebruiken. Aan een message kan een prioriteit worden meegegeven. Bij creatie wordt o.a. opgegeven: Naam Max aantal messages Max size message API: mq_open (create en open) mq_send, mq_receive mq_close, mq_unlink (destroy) mq_getattr, mq_setattr mq_notify

Voorbeeld embedded system thermocouple pressure transducer ADC ADC T P S DAC Switch Screen pump/valve heater

Beschikbare functies double readTemp(void); void writeSwitch(int i); double readPres(void); void writeDAC(double d); int tempControl(double temp); double presControl(double pres);

Sequentieel int main(void) { double temp, pres, dac; int switch_; while (1) { temp = readTemp(); switch_ = tempControl(temp); writeSwitch(switch_); pres = readPres(); dac = presControl(pres); writeDAC(dac); printf("%4.1lf, %4.1lf, %d, %5.1lf\n", temp, pres, switch_, dac); } return EXIT_SUCCESS;

Sequentieel problemen Sample rate van temperatuur en druk is gelijk. Kan wel wat aan worden gedaan met tellers maar: Wat doe je als pressureControl langer duurt dan gewenste sample rate van temperatuur? Als readTemperature niet werkt (blijft pollen) dan loopt ook de drukregeling vast. De temperatuurregeling en de drukregeling zijn twee afzonderlijke “processen”. Maar in het sequentiële programma zitten ze verweven!

POSIX Threads Zie volgende sheet… void* tempThread(void* p) { double temp; int switch_; while (1) { temp = readTemp(); printf("temperature = %4.1lf, ", temp); switch_ = tempControl(temp); printf("switch = %d\n", switch_); writeSwitch(switch_); sleep(3); } return NULL; Zie volgende sheet…

POSIX Threads Zie volgende sheet… void* presThread(void* p) { double pres, dac; while (1) { pres = readPres(); printf("pressure = %4.1lf", pres); dac = presControl(pres); printf(", DAC = %5.1lf\n", dac); writeDAC(dac); sleep(1); } return NULL; Zie volgende sheet…

POSIX Threads #include <pthread.h> void check(int error) { if (error != 0) { fprintf(stderr, "Error: %s\n", strerror(error)); exit(EXIT_FAILURE); } int main(void) { pthread_t t1, t2; check( pthread_create(&t1, NULL, tempThread, NULL) ); check( pthread_create(&t2, NULL, presThread, NULL) ); check( pthread_join(t1, NULL) ); check( pthread_join(t2, NULL) ); return EXIT_SUCCESS; pressure = 14.4, DAC = -4.4 pressure = 14.0temperature = 3.0, , DAC = -4.0 switch = 0 pressure = 13.6, DAC = -3.6

Synchronized Threads pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; void* tempThread(void* p) { double temp; int switch_; while (1) { temp = readTemp(); switch_ = tempConvert(temp); check( pthread_mutex_lock(&mutex) ); printf("temperature = %4.1lf, switch = %d\n", temp, switch_); check( pthread_mutex_unlock(&mutex) ); writeSwitch(switch_); sleep(3); } return NULL;

C++11 Synchronized Threads class Temp { private: double temp; bool switch_; mutex& display; void read(); void write(); void control(); public: Temp(mutex& m); void run(); }; class Pres { private: double pres, dac; mutex& display; void read(); void write(); void control(); public: Pres(mutex& m); void run(); };

C++11 Synchronized Threads Temp::Temp(mutex& m): temp(0.0), switch_(false), display(m) { } void Temp::run() { while (1) { read(); control(); { lock_guard<mutex> lock(display); cout << "temperature = " << fixed << setw(4) << setprecision(1) << temp << ", switch = " << switch_ << endl; write(); this_thread::sleep(chrono::seconds(3));

C++11 Synchronized Threads int main() { mutex m; Temp t(m); Pres p(m); thread t1(&Temp::run, &t); thread t2(&Pres::run, &p); t1.join(); t2.join(); return 0; }

Voorbeeld embedded system thermocouple pressure transducer ADC ADC T P S DAC Switch Screen pump/valve heater

Message Queue Zie volgende sheet… #include <mqueue.h> // ... void* tempThread(void* p) { double temp; int switch_; mqd_t m; char buffer[128]; int i; check_errno( m = mq_open("/mq_par74", O_WRONLY) ); for (i = 0; i < 10; i++) { int n = 0; temp = readTemp(); n = snprintf(buffer, sizeof buffer, "temperature = %4.1lf, ", temp); switch_ = tempControl(temp); snprintf(&buffer[n], sizeof buffer-n, "switch = %d\n", switch_); check_errno( mq_send(m, buffer, sizeof buffer, 2) ); writeSwitch(switch_); sleep(3); } check_errno( mq_close(m) ); return NULL; Zie volgende sheet…

Message Queue Zie volgende sheet… void* presThread(void* p) { double pres, dac; mqd_t m; char buffer[128]; int i; check_errno( m = mq_open("/mq_par74", O_WRONLY) ); for (i = 0; i < 10; i++) { int n = 0; pres = readPres(); n = snprintf(buffer, sizeof buffer, "pressure = %4.1lf, ", pres); dac = presControl(pres); snprintf(&buffer[n], sizeof buffer - n, "DAC = %5.1lf\n", dac); check_errno( mq_send(m, buffer, sizeof buffer, 3) ); writeDAC(dac); sleep(1); } check_errno( mq_close(m) ); return NULL; Zie volgende sheet…

Message Queue Zie volgende sheet… void* dispThread(void* p) { mqd_t m; struct mq_attr ma; char buffer[128]; int doorgaan = 1; check_errno( m = mq_open("/mq_par74", O_RDONLY) ); while (doorgaan) { do { check_errno( mq_receive(m, buffer, sizeof buffer, NULL) ); if (strcmp(buffer, "CLOSE") == 0) doorgaan = 0; else printf(buffer); check_errno( mq_getattr(m, &ma) ); } while (ma.mq_curmsgs > 0); sleep(5); putchar('\007'); check_errno( mq_close(m) ); Zie volgende sheet…

Message Queue int main(void) { pthread_t t1, t2, t3; mqd_t m; struct mq_attr ma; ma.mq_maxmsg = 40; ma.mq_msgsize = 128; check_errno( m = mq_open("/mq_par74", O_CREAT|O_RDWR, 0666, &ma) ); check( pthread_create(&t1, NULL, tempThread, NULL) ); check( pthread_create(&t2, NULL, presThread, NULL) ); check( pthread_create(&t3, NULL, dispThread, NULL) ); check( pthread_join(t1, NULL) ); check( pthread_join(t2, NULL) ); check_errno( mq_send(m, "CLOSE", 6, 1) ); check( pthread_join(t3, NULL) ); check_errno( mq_close(m) ); check_errno( mq_unlink("/mq_par74") ); return EXIT_SUCCESS; } BEEP! pressure = 15.6, DAC = -5.6 pressure = 15.2, DAC = -5.2 pressure = 14.8, DAC = -4.8 pressure = 14.4, DAC = -4.4 temperature = 2.5, switch = 0

/dev/mqueue

shared_mutex implementation shared_mutex heeft de volgende functies: lock()  unieke toegang claimen (voor schrijven) unlock()  unieke toegang vrijgeven (voor schrijven) shared_lock()  gedeelde toegang claimen (voor lezen) shared_unlock()  gedeelde toegang vrijgeven (voor lezen)

shared_mutex implementation Monitor mutex m condition_variable c lock() writers numberOfWriters unlock() shared_lock() readers numberOfReaders shared_unlock() Writers moeten wachten als: numberOfWriters == 1 || numberOfReaders > 0 Readers moeten wachten als: numberOfWriters == 1

shared_mutex implementation cclass shared_mutex { public: shared_mutex(); void lock(); void unlock(); void lock_shared(); void unlock_shared(); private: int numberOfWriters, numberOfReaders; mutex m; condition_variable c; }; shared_mutex::shared_mutex(): numberOfWriters(0), numberOfReaders(0) { }

shared_mutex implementation void shared_mutex::lock() { unique_lock<mutex> lock(m); while (numberOfWriters == 1 || numberOfReaders > 0) { c.wait(lock); } ++numberOfWriters; void shared_mutex::unlock() { lock_guard<mutex> lock(m); --numberOfWriters; c.notify_all();

shared_mutex implementation void shared_mutex::lock_shared() { unique_lock<mutex> lock(m); while (numberOfWriters == 1) { c.wait(lock); } ++numberOfReaders; void shared_mutex::unlock_shared() { lock_guard<mutex> lock(m); --numberOfReaders; c.notify_all();

Huiswerk shared_mutex Werkt de bovenstaande implementatie correct als de notify_all in shared_mutex::unlock() wordt vervangen door een notify_one? Werkt de bovenstaande implementatie correct als de notify_all in shared_mutex::shared_unlock() wordt vervangen door een notify_one?

Je kunt de prioriteit van een thread niet opvragen in standaard C++11) shared_mutex Als een schrijver zich meldt en moet wachten omdat er lezers zijn dan kunnen zich steeds nieuwe lezers melden zodat de schrijver nooit aan de beurt komt (starvation). Is dit een probleem in een RTOS? Ja! Schrijver met hoge prioriteit moet wachten als er steeds nieuwe lezers met lage prioriteit zijn. Oplossing? Nieuwe lezer moeten wachten als er een wachtende schrijver is met een hogere prioriteit dan de lezer. Je kunt de prioriteit van een thread niet opvragen in standaard C++11)

Priority correct Monitor writers readers mutex m condition_variable c numberOfWriters lock() writers unlock() waitingWriters shared_lock() readers numberOfReaders shared_unlock() Writers moeten wachten als: numberOfWriters == 1 || numberOfReaders > 0 Readers moeten wachten als: numberOfWriters == 1 || waitingWriters > 0

Priority correct class shared_mutex { public: shared_mutex(); void lock(); void unlock(); void lock_shared(); void unlock_shared(); private: int numberOfWriters, numberOfReaders, waitingWriters; mutex m; condition_variable c; }; shared_mutex::shared_mutex(): numberOfWriters(0), numberOfReaders(0), waitingWriters(0) { }

Priority correct void shared_mutex::lock() { unique_lock<mutex> lock(m); ++waitingWriters; while (numberOfWriters == 1 || numberOfReaders > 0) { c.wait(lock); } --waitingWriters; ++numberOfWriters; void shared_mutex::unlock() { lock_guard<mutex> lock(m); --numberOfWriters; c.notify_all();

Priority correct void shared_mutex::lock_shared() { unique_lock<mutex> lock(m); while (numberOfWriters == 1 || waitingWriters > 0) { c.wait(lock); } ++numberOfReaders; void shared_mutex::unlock_shared() { lock_guard<mutex> lock(m); --numberOfReaders; c.notify_one();

Real-Time Systems (RTSYST) Week 5

Real-time faciliteiten Wat willen we met tijd in een RT systeem? Gebruik van de tijd. Tijd(sduur) meten. (Tot een) bepaalde tijd slapen. Beperkte tijd wachten = time-outs. Tijdafhankelijke requirements opstellen. Specificeren van periodetijden. Specificeren van deadlines. Voldoen aan de tijdafhankelijke requirements = scheduling (zie hoofdstuk 11).

Hoe snel is tijd? Elektronica is veel sneller dan de mechanische werkelijkheid. Voorbeeld: Auto botst tegen een muur. Hoeveel instructies kan de boordcomputer nog uitvoeren? snelheid auto = 108 km/uur kreukzone = 30 cm processor freq = 200 MHz gemiddeld 2 clockcycles / instructie 1.000.000

RTC real-time clock POSIX (niet nauwkeurig, granularity = 1 s) time_t, stuct tm, time() and localtime() Zie MICPRG: http://bd.eduweb.hhs.nl/micprg/time.htm POSIX optional REALTIME (nauwkeuriger) int clock_gettime(clockid_t clock_id, struct timespec *tp) clock_id CLOCK_REALTIME is verplicht int clock_getres(clockid_t clock_id, struct timespec *res) granularity POSIX max 20 ms, QNX instelbaar (default 1 ms, minimum 10 μs) C++11 (granularity = ?) chrono::system_clock, chrono::high_resolution_clock

Slapen POSIX (niet nauwkeurig, granularity = 1 s) unsigned int sleep(unsigned int) POSIX optional REALTIME (nauwkeuriger) int nanosleep(struct timespec* rqtp, struct timespec* rmtp); Granularity van CLOCK_REALTIME QNX instelbaar (default = 1 ms, minimum = 10 μs) C++11 (granularity = ?) std::this_thread::sleep_for(… rel_time) std::this_thread::sleep_until(… abs_time)

Al deze ...timed... functies geven ETIMEDOUT terug bij een timeout POSIX timeout Semaphore int sem_timedwait(sem_t* sem, const struct timespec* abs_time); Mutex int pthread_mutex_timedlock(..., const struct timespec* abs_time); Conditionele variabele int pthread_cond_timedwait(..., Message queue ssize_t mq_timedreceive(..., const struct timespec* abs_time); int mq_timedsend(..., const struct timespec* abs_time); Al deze ...timed... functies geven ETIMEDOUT terug bij een timeout

Handig om een absolute time te gebruiken! POSIX timeout int ei_teller = 0; pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t c = PTHREAD_COND_INITIALIZER; // ... struct timespec ts; int r = 0; pthread_mutex_lock(&m); clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += 5; while (ei_teller < 12 && r == 0) { r = pthread_cond_timedwait(&c, &m, &ts); } if (r != 0) { if (r == ETIMEDOUT) else /* error */ Handig om een absolute time te gebruiken! Snap je waarom? else { ei_teller -= 12; } pthread_mutex_unlock(&m); // ...

C++ timeout timed_mutex, recursive_timed_mutex condition_variable bool try_lock_until(const chrono::time_point<C, D>& abs_time); bool try_lock_for(const chrono::duration<R, P>& rel_time); condition_variable cv_status wait_until(unique_lock<mutex>& lock, const chrono::time_point<C, D>& abs_time); bool wait_until(unique_lock<mutex>& lock, const chrono::time_point<C, D>& abs_time, … p); cv_status wait_for(unique_lock<mutex>& lock, const chrono::duration<R, P>& rel_time); bool wait_for(unique_lock<mutex>& lock, const chrono::duration<R, P>& rel_time, … p); Memberfuncties die een bool teruggeven, geven false terug bij een timeout. Memberfuncties die cv_status teruggeven, geven cv_status::timeout terug bij een timeout.

C++11 timeout // producer thread(s) // ... // ... int ei_teller(0); { // ... { lock_guard<mutex> g(m); ei_teller += n; c.notify_all(); } // ... int ei_teller(0); mutex m; condition_variable c; // consumer thread(s) { unique_lock<mutex> u(m); if (c.wait_for(u, chrono::seconds(5), []() { return ei_teller >= 12; })) { ei_teller -= 12; else cout << "Schiet eens op!" << endl; }

Time requirements Deadline  taak moet klaar voor deadline (hard, soft, firm) Minimum delay  taak mag pas starten na min delay Maximum delay  taak moet starten na max delay Maximum execution time  taak mag niet langer runnen Maximum elapse time  taak mag niet langer duren Soorten taken Periodic (vaste tijd tussen events) Aperiodic (random events) Geen worst-case analyse mogelijk. Sporadic (min tijd tussen events is gespecificeerd)

Drift cumulatieve drift lokale drift De extra vertraging bij sleep wordt lokale drift genoemd. Deze drift kan niet voorkomen worden. Je kunt wel voorkomen dat een cumulatieve drift ontstaat doordat lokale drifts bij elkaar worden opgeteld. while (1) { actie(); sleep(5); // slaap minstens 5 seconden } sigwait(&set, &signum); // slaap tot signal cumulatieve drift lokale drift Met een timer (zie 10.4.2) kan een periodiek signal (zie 7.5.1) worden opgewekt.

Timing error detectie Deadline overrun detectie Zet een POSIX timer (10.4.2) die een signal (zie 7.5.1) geeft als de deadline verstrijkt = watchdog timer Zie 13.2 en 13.2.3 Maximum execution time overrun detectie POSIX definieert clocks: CLOCK_PROCESS_CPUTIME_ID en CLOCK_THREAD_CPUTIME_ID Zie 13.3 en 13.3.1

Real-Time Systems (RTSYST) Week 6

Scheduling Dienstregeling van taken N taken kun je in N! verschillende schedules uitvoeren. Bijvoorbeeld 10 taken: 3628800 mogelijke schedules. Met preemption nog veel meer mogelijkheden. De gekozen scheduling moet aan alle time requirements voldoen. Een scheduling scheme (=plan) bestaat uit: Een algoritme om een schedule te bepalen. Een methode om het “worst-case” gedrag van een, met het algoritme bepaalde, schedule te voorspellen.

Scheduling wanneer? Statisch: schedule ligt vast voor uitvoering. Taken, worst-case executietijden en deadlines moeten van tevoren bekend zijn. Je kunt door middel van een analyse aantonen dat alle deadlines worden gehaald. Responsetijden zijn voorspelbaar! Kan niet reageren op “onvoorziene” situaties. Dynamisch: schedule bepaald tijdens uitvoeren. Gedrag minder goed vooraf voorspelbaar. Kan dynamisch inspelen op onvoorziene omstandigheden (b.v. berekening die langer duurt dan verwacht).

Scheduling RT systemen Bijna altijd wordt een statische methode gebruikt. Meest gebruikt: Preemptive Priority Based scheduling op elk moment runt de ready taak met de hoogste prio In dit geval bestaat een scheduling scheme uit: Een algoritme om de prioriteit van elke taak te bepalen. Een methode om de schedulability te voorspellen = Een methode om het “worst-case” gedrag bij de gekozen prioriteiten te voorspellen en te bekijken of aan alle time requirements wordt voldaan.

Scheduling Simpel beginnen Het aantal taken is bekend. N Alle taken zijn periodiek en de perioden zijn bekend. Ti De taken zijn onafhankelijk van elkaar (geen synchronisatie en communicatie). Systeem overhead wordt verwaarloosd. De deadline van elke taak is gelijk aan de periode. Di = Ti De worst-case executietijd van elke taak is vast en bekend. Ci Dit process model is te simpel (maar al moeilijk genoeg). Later zullen we realistische modellen bekijken.

Cyclic executive Als schedule van tevoren bepaald is kun je het uitvoeren van de schedule expliciet programmeren. Voorbeeld: // zet timer: elke 25 ms een signal while (1) { sigwait(&set, &signum); a(); b(); c(); sigwait(&set, &signum); a(); b(); d(); e(); sigwait(&set, &signum); a(); b(); d(); } Taak T C a 25 10 b 8 c 50 5 d 4 e 100 2 Hoe bepaal je de schedulability? Hoe vind je een schedule?

Cyclic executive Hoe bepaal je de schedulability? Utilization (benutting) U = 10/25+8/25+5/50+ 4/50+2/100 = 0,92 Als Ce = 4 dan geldt U = 0,94 en is er geen schedule mogelijk! Hoe bepaal je de schedulability? Hoe vind je een schedule?

Cyclic executive Eigenschappen: Problemen: Alternatieven: Er zijn geen processen (of threads) de taken zijn gewone functies. Er is shared memory voor communicatie. Protectie is niet nodig. Alle T ’s moeten een veelvoud zijn van de minor cycle time. Systeem is deterministisch. Problemen: Taken met grote verschillen in T ’s geeft lange major cycle. Sporadic taken zijn niet in te passen! Slecht onderhoudbaar, aanpasbaar en uitbreidbaar. Schedule bepalen is moeilijk! Alternatieven: Fixed-Priority Scheduling (FPS) Earliest Deadline First (EDF)

FPS Fixed-Priority Scheduling Elke taak draait als thread (of process) met een statisch bepaalde vaste prioriteit. De prioriteit wordt bepaald door de time requirements. Een thread met een hogere prioriteit krijgt ‘voorrang’ van het RTOS (zoals bijvoorbeeld bij practicumopdracht 2)

FPS Fixed-Priority Scheduling Preemptive ↔ NonPreemptive Preemptive: Als thread met hogere prioriteit ready wordt dan wordt running thread meteen onderbroken. (practicumopdracht 2) NonPreemptive: Als thread eenmaal gestart is wordt hij ook afgemaakt. Deferred Preemption: Als thread met hogere prioriteit ready wordt dan wordt running thread na een bepaalde tijd zeker onderbroken.

Rate Monotonic Priority Assignment De periode van een proces bepaalt de prioriteit van dat proces. Hoe korter de periode hoe hoger de prioriteit. Deze methode is optimaal! Dat wil zeggen dat als er een mogelijke preemptive FPS schedule is dan is rate monotonic FPS ook mogelijk.

FPS-RMPA Utilization based schedulability test: 1 U ≤ 1.000 2 U ≤ 0.828 3 U ≤ 0.780 4 U ≤ 0.757 5 U ≤ 0.743 10 U ≤ 0.718 oneindig U ≤ 0.693 Als deze test true geeft worden geen deadlines gemist! Als deze test false worden er misschien deadlines gemist!

FPS-RMPA Schedulability voorbeelden Boek: Voorbeeld A: Tabel 11.5, figuur 11.2 (time line) en figuur 11.3 (Gantt chart). Voldoet niet aan de test en haalt deadlines niet. Voorbeeld B: Tabel 11.6. Voldoet wel aan de test en haalt deadlines wel. Voorbeeld C: Tabel 11.7 en figuur 11.4. Voldoet niet aan de test maar haalt deadlines wel. Als aan de test voldaan wordt is dat voldoende bewijs dat de deadlines gehaald worden. Maar het is niet noodzakelijk dat aan de test voldaan wordt om de deadlines te kunnen halen.

FPS-RMPA Responsetijd analyse In tegenstelling tot de vorige test geeft deze analyse de exacte responsetijden. We kunnen dus exact zeggen of alle deadlines gehaald worden (en met welke marge). Ri komt zowel links als rechts voor. De vergelijking is niet eenvoudig op te lossen (door de niet inverteerbare ceiling functie) Ri is de responsetijd van taak i hp(i) is de verzameling taken met een hogere prioriteit dan taak i

FPS-RMPA Responsetijd analyse Voor de taak met de hoogste prioriteit geldt: Alle andere taken kunnen onderbroken worden en voor deze taken geldt: Waarbij Ii de maximale “interference” is. Deze treed op als alle taken met een hogere prioriteit gelijk met taak i starten. Het aantal keer dat een taak met een hogere prioriteit j gestart wordt voordat i afgelopen is: Ii,j is dus:

FPS-RMPA Responsetijd analyse De totale maximale interference is de som van de maximale interference van alle taken met een hogere prioriteit: Oplossing met behulp van recurrente betrekking: Start met = 0 en ga door tot: of

FPS-RMPA Responsetijd analyse Je kunt een programma schrijven om alle Ri ’s te berekenen: zie boek p. 376. Voorbeelden: zie boek p. 377 en 378. Verdere uitbreiding is nog nodig: Sporadic taken. Taken met D < T. Interactie tussen taken. Release jitter. Taken met D > T. Deferred preemption. Fault tolerance. Release offset.

FPS-RMPA D < T en Sporadic taken Gebruik DMPA in plaats van RMPA (geeft DMPO): Gebruik bij responsetijd analyse als stop voorwaarde: Sporadic taken: Vul voor de periodetijd de minimale tijd tussen twee “starts” van deze taak in. T = minimum inter-arrival interval. Vaak geldt voor sporadic taken D < T.

FPS-DMPO Blocking Als een taak met een hoge prioriteit moet wachten op een taak met een lagere prioriteit dan wordt deze taak blocked (priority inversion). Een taak die unblocked sluit achter de taken met dezelfde prioriteit in de readyqueue aan. Als een taak met een lagere prioriteit moet wachten op een taak met een hogere prioriteit dan wordt deze taak preempted. Een taak die preempted wordt sluit voor de taken met dezelfde prioriteit in de readyqueue aan = vooraan de readyqueue! Om het real-time gedrag te kunnen voorspellen moet de maximale tijd dat een taak blocked kan zijn voorspelbaar zijn (bound blocking).

Priority inversion voorbeeld 4 taken (a, b, c en d) delen 2 resources (Q en V). Deze resources kunnen slechts door 1 taak tegelijk gebruikt worden (en zijn dus beschermd met bijvoorbeeld een mutex). taak prio execution release time d 4 EEQVE c 3 EVVE 2 b EE a 1 EQQQQE E = taak heeft alleen processor nodig Q = taak heeft resource Q nodig V = taak heeft resource V nodig

Priority inversion voorbeeld taak prio execution release time d 4 EEQVE c 3 EVVE 2 b EE a 1 EQQQQE

FPS-DMPO Priority inversion Taak d wordt blocked door taak a, b en c (alle processen met een lagere prioriteit)! Blocking (priority inversion) is niet te voorkomen als we mutual exclusive recources delen. Blocking is wel te beperken door het toepassen van priority inheritance: Als een taak blocked voor een resource dan krijgt de taak die de resource bezit de prioriteit van de taak die blocked wordt.

Huiswerk Boek: H11 Inleiding, 11.1 tot 11.6.2 en 11.7 bestuderen. Opgaven 1, 2, 4 en 7 maken.

Real-Time Systems (RTSYST) Week 7

Priority inheritance voorbeeld taak prio execution release time d 4 EEQVE c 3 EVVE 2 b EE a 1 EQQQQE

Blocking Priority inheritance De tijd dat een taak blocked kan zijn is nu beperkt. B = maximum blocking time K = aantal gebruikte resources usage(k, i) = boolean functie 1 als er een taak is met prioriteit lager dan Pi en een taak met prioriteit hoger of gelijk aan Pi (dit kan taak i zelf zijn) die de resource k delen. C(k) = maximale tijd dat resource k gebruikt wordt.

Blocking Response time analyse

Blocking Priority inheritance Priority inheritance kan niet eenvoudig geïmplementeerd worden! Bij semaphoren en condition variabelen is vaak niet te achterhalen op wie je wacht (wie de sem_post of pthread_cond_signal zal geven)! Bij message passing is het vaak niet te achterhalen op wie je wacht (wie de mq_send zal doen waarop de mq_receive moet wachten)! Alternatief: priority ceiling Wie doet sem_post? Taak 1 Taak 2 Taak 3 Taak 4 sem_wait sem_post OS kan niet in de toekomst kijken. Wie wel?

FPS-DMPO Priority ceiling Original Ceiling Priority Protocol OCPP: Elke taak heeft een static priority. Elke resource heeft een ceiling priority = maximale prioriteit van de processen die deze resource delen. Een taak die een taak met een hogere prioriteit blocked erft de hogere prioriteit. Een taak kan alleen een resource gebruiken als zijn prioriteit hoger is dan de ceiling van alle door andere taken gebruikte (en gelockte) resources. Voordelen: Proces kan maar 1x blocked worden. Deadlock is niet mogelijk. Mutual exclusive gaat altijd “van zelf” goed. Transitive blocking is niet mogelijk.

OCPP voorbeeld ceiling Q = 4 ceiling V = 4 taak prio execution release time d 4 EEQVE c 3 EVVE 2 b EE a 1 EQQQQE

OCPP Blocking Eerste resource kan altijd worden gebruikt. Tweede resource kan alleen worden gebruikt als er geen taak is met een hogere prioriteit die beide resources gebruikt. De tijd dat een taak blocked kan zijn wordt nu: Impementatie is nog steeds net zo moeilijk! Alternatief: Immediate CPP.

FPS-DMPO Priority ceiling Immediate Ceiling Priority Protocol ICPP: Elke taak heeft een static priority. Elke resource heeft een ceiling priority = maximale prioriteit van de processen die deze resource delen. Als een taak een resource gebruikt krijgt die taak de ceiling prioriteit van de resource. Voordelen: Proces kan maar 1x blocked worden. Deadlock is niet mogelijk. Mutual exclusive gaat altijd “van zelf” goed. Transitive blocking is niet mogelijk. Ten opzichte van OCPP: Eenvoudiger te implementeren. Minder taak wisselingen.

ICPP voorbeeld ceiling Q = 4 ceiling V = 4 taak prio execution release time d 4 EEQVE c 3 EVVE 2 b EE a 1 EQQQQE

POSIX Priority Based Scheduling FIFO Een thread blijft running totdat de thread blocked of preempted wordt. Een thread die preempted wordt komt vooraan de readyqueue te staan. Round-Robbin Een thread blijft running totdat de thread blocked of preempted wordt of totdat de time-slice is verstreken. Een thread waarvan de time-slice is verstreken komt achter de threads met gelijke prioriteit op de readyqueue te staan. Sporadic Server Other

Priority Protect Protocol =ICPP int pthread_mutexattr_getprotocol(const thread_mutexattr_t* attr, int* protocol); int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol); mogelijke waarden voor protocol: PTHREAD_PRIO_NONE PTHREAD_PRIO_INHERIT PTHREAD_PRIO_PROTECT int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t* attr, int* prioceiling); int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling); Priority inheritance POSIX naam voor ICPP

Huiswerk Boek: H11 11.8 en 11.9 bestuderen. Opgaven 5 en 6 maken.

Tentamenopgave Een programma bestaat uit 5 threads T1 t/m T5. Deze threads gebruiken 4 gedeelde resources R1 t/m R4. Elke resource is mutual exclusive beveiligd met een mutex M1 t/m M4. Deze mutexen gebruiken het priority inheritance protocol. Als een thread een resource toegewezen heeft gekregen dan kan deze thread de resource voor een bepaalde maximale tijd bezetten. In de onderstaande tabel staat k voor het nummer van de resource en C(k) voor de maximale tijd dat resource k bezet kan worden.

Alle gegeven tijden zijn in ms. Tentamenopgave In de volgende tabel staat aangegeven welke resources elke thread gebruikt. In de onderstaande tabel staat i voor het nummer van de thread, T(i) voor de periodetijd van thread i en C(i) voor de maximale executietijd van thread i. Gegeven is dat de deadline van elke taak gelijk is aan zijn periodetijd. Alle gegeven tijden zijn in ms.

Tentamenopgave A. (5) Bepaal de prioriteit van de 5 processen als RMPA (Rate Monotonic Priority Assignment) wordt gebruikt. De hoogste prioriteit is 5 en de laagste prioriteit is 1. B. (15) Bereken voor elke thread i de blocking time B(i). C. (15) Bereken voor thread 1, 3 en 5 of de deadline wordt gehaald en geef, indien de deadline wordt gehaald, de responsetijd Ri.

Tentamenopgave i P(i) T(i) C(i) Gebruikt 1 5 100 50 R1, R3 2 4 200 45 R2, R3, R4 3 300 15 - 350 20 R2 400 25 R1