Tentamen
Datorteknik och realtidssystem, TSEA81
Datum 2020-03-16
Lokal TER4
Tid 14-18
Kurskod TSEA81
Provkod TEN1
Kursnamn Datorteknik och realtidssystem
Institution ISY
Antal uppgifter 5
Antal sidor
(inklusive denna sida)
17
Kursansvarig Anders Nilsson L ¨arare som bes¨oker skriv-
salen
Anders Nilsson Telefon under skrivtiden 013-28 2635 Bes¨oker skrivsalen Cirka 15 och 17
Kursadministrat¨or Eva Zurawski 013-28 6806 Till ˚atna hj ¨alpmedel Inga
Betygsgr ¨anser
Po¨ang Betyg
41-50 5
31-40 4
21-30 3
0-20 U
Viktig information
• Alla svar ska ha en motivation om inget annat anges. Om du svarar med pro- gramkod r¨aknas kommentarer i programkoden som motivation. Svar som ej ¨ar motiverade kan leda till po¨angavdrag.
• Om inget annat anges ska du anta att schemal¨aggningsmetoden som anv¨ands
¨
ar priority based preemptive scheduling.
• Om inget annat anges antas semaforer vara starka.
• Om du ¨ar os¨aker p ˚a det exakta namnet f¨or en viss funktion, skriv en kom- mentar om vad funktionen g¨or s ˚a kommer vi troligtvis att f¨orst ˚a vad du menar.
(Detsamma g¨aller syntaxen f¨or programspr ˚aket C.)
• T¨ank igenom din l¨osning NOGGRANT och anv¨and dig av de l¨osningsprinciper som kursen f¨orevisar. Okonventionella och tvetydiga l¨osningar ger po¨angavdrag.
• Svara ALDRIG med pseudokod, om det inte specifikt efterfr ˚agas. Pseudokod blir l¨att tvetydig och d¨armed inte bed¨omningsbar.
• L¨amna INTE in denna tentamen tillsammans med l¨osningarna. En inl¨amnad tentamen med eventuella anteckningar kommer inte att beaktas som en l¨osning.
• Skriv l¨asbart! Ol¨asbar text kan inte bed¨omas och ger d¨armed inga po¨ang.
Lycka till!
Uppgift 1: Schemal¨ aggning(10p)
Ett realtidssystem med ett antal processer ska schemal¨aggas p ˚a en dator som enbart har en processor/k¨arna, dvs endast en process ˚at g ˚angen kan exekvera.
F¨oljande krav g¨aller:
• P1 ska arbeta/k¨ora under n tidsenheter i tidsintervallet [i*12, (i+1)*12]
• P2 ska arbeta/k¨ora under 2 tidsenheter i tidsintervallet [i*9, (i+1)*9]
• P3 ska arbeta/k¨ora under 2 tidsenhet i tidsintervallet [i*6, (i+1)*6]
d¨ar i ¨ar ett heltal och i ≥ 0, och n ¨ar ett heltal och n ≥ 0.
Tidr¨akningen startar vid t=0 f¨or alla processer. Du kan anta att uppstart av pro- cesser och processbyte inte tar n ˚agon tid alls. Eventuellt missat arbete under n ˚agot tidsintervall ackumuleras inte till kommande tidsintervall.
(a) (5p) Antag att schemal¨aggningsmetoden Earliest Deadline First (EDF) anv¨ands.
Man vill att P1 ska k¨ora s ˚a mycket som m¨ojligt, dvs ber¨akna st¨orsta m¨ojliga v¨arde p ˚a n s ˚a att specifikationerna uppfylls. Visa sedan vad som h¨ander n¨ar programmet k¨ors genom att rita ett tidsdiagram.
Hur stor blir den faktiska utnyttjandegraden?
(b) (5p) Antag att schemal¨aggningsmetoden Rate Monotonic Scheduling (RMS) anv¨ands, samt att n har samma v¨arde som i uppgift (a). Visa vad som h¨ander n¨ar programmet k¨ors genom att rita ett tidsdiagram.
Kommer specifikationerna ovan att uppfyllas? Hur stor blir den faktiska ut- nyttjandegraden?
Uppgift 2: Teori(10p)
(a) (3p) En kritisk region kan vara relativt odelbar eller absolut odelbar. Vad ¨ar skillnaden? Ge n ˚agot exempel p ˚a var det finns en absolut odelbar kritisk region i ett realtidssystem.
(b) (2p) Beskriv tv ˚a huvudsakliga skillnader mellan en semafor och en mutex.
Beskrivningen f ˚ar inte underf¨orst ˚a n ˚agra egenskaper hos en semafor eller en mutex.
(c) (2p) Ge ett exempel p ˚a n ˚agon del i ett realtidssystem som m ˚aste skrivas i assembler, dvs som inte g ˚ar att skriva i ett h¨ogniv ˚aspr ˚ak som C, samt f¨orklara varf¨or den delen m ˚aste skrivas i assembler?
(d) (2p) Om prioritetsbaserad p ˚atvingad schemal¨aggning anv¨ands och det finns flera processer med samma h¨ogsta prioritet att v¨axla till vid ett processbyte, vilka vanliga metoder skulle schemal¨aggaren kunna anv¨anda d ˚a? Beskriv tv ˚a metoder.
(e) (1p) Om tv ˚a processer k¨or parallellt i var sin k¨arna i samma processor och exakt samtidigt f¨ors¨oker l ˚asa samma mutex, hur best¨ams det d ˚a vilken pro- cess som f ˚ar l ˚asa mutexen?
Uppgift 3: Barri¨ ar med meddelandehantering(10p)
Ett visst datorsystem inneh ˚aller ett maximalt antal ber¨akningsprocesser, MAX PROC.
Varje ber¨akningsprocess utf¨or ett ber¨akningsarbete och m¨ater sin egen k¨ortid. Nu
¨
onskar man ber¨akna medelv¨ardet av k¨ortiden f¨or ett antal av dessa ber¨aknings- processer, dvs inte n¨odv¨andigtvis alla ber¨akningsprocesser.
F¨oljande krav finns:
• F¨or att ber¨akna medelv¨ardet ska en barri¨ar anv¨andas, till vilken respektive ber¨akningsprocess proc meddelar sin k¨ortid.
• Barri¨arfunktionens header ser ut s ˚asom: void barrier(int limit)
• Antalet ber¨akningsprocesser som samtidigt kan vara i barri¨aren best¨ams av variabeln limit.
• Medelv¨ardet ska ber¨aknas n¨ar gr¨ansen limit har uppn ˚atts.
• Det ber¨aknade medelv¨ardet ska meddelas till anv¨andarinterfaceprocessen ui.
• Det ska vara m¨ojligt att n¨ar som helst, via ett meddelande fr ˚an processen ui, s¨atta ett nytt v¨arde p ˚a limit.
• Om det nya v¨ardet p ˚a limit ¨ar l¨agre ¨an det nuvarande antalet processer i barri¨aren s ˚a ska medelv¨ardet d ˚a ber¨aknas f¨or det antal processer som finns i barri¨aren.
• N¨ar medelv¨ardet ber¨aknats ska processerna i barri¨aren starta en ny omg ˚ang av sitt ber¨akningsarbete.
• Varje process f ˚ar endast bidra med sin k¨ortid en g ˚ang till ett och samma medelv¨arde.
Meddelandefunktionerna finns deklarerade s ˚asom:
/* send message function
msg : pointer to message buffer len : length of message
portid : message queue port id priority : priority of message */
void message_send(char *msg, unsigned int len, unsigned int portid, unsigned int priority)
/* receive message function msg : pointer to message
max_len : maximum length of message received portid : message queue port id */
void message_receive(char *msg, unsigned int max_len, unsigned int portid) Ber¨akningsprocessfunktionens header ser ut s ˚asom:
/* calculation process function with process id as argument */
void proc(int id)
Barri¨arprocessfunktionens header ser ut s ˚asom:
/* barrier process function with initial limit as argument */
void barrier(int limit) Huvudprogrammet ser ut s ˚asom:
/* main function */
int main(void) {
int pid;
/* initialize message system */
message_init();
/* start barrier process, and initialize limit to MAX_PROC */
pid = fork();
if (!pid) {
barrier(MAX_PROC) }
/* start calculation processes */
int i;
for (i=0; i<MAX_PROC; i++) { pid = fork();
if (!pid) { proc(i);
} }
/* start user interface process */
ui();
return 0;
}
Din uppgift ¨ar att skriva barrier-funktionen. Du m ˚aste ¨aven sj¨alv definiera hur ett meddelande ska se ut och vilka meddelandetyper och meddelandek¨oer som beh¨ovs f¨or att barrier ska fungera enligt kraven ovan.
Du f ˚ar i din l¨osning anta att ¨ovriga processer s¨ander och tar emot meddelanden p ˚a ett s¨att som passar din barrier-funktion, men kraven ovan m ˚aste f¨orst ˚as fortfarande uppfyllas. Dvs, var noga med att kommentera koden och ber¨atta vad dina meddelandetyper har f¨or betydelse.
Du beh¨over allts ˚a inte bry dig om eller visa hur du t¨anker att ber¨akningsprocessen proceller anv¨andarinterfaceprocessen ui f¨or ¨ovrigt ser ut eller fungerar.
Medelv¨ardet kan ber¨aknas som ett heltal, dvs du beh¨over inte anv¨anda flyttal i l¨osningen.
Uppgift 4: Await och Cause(10p)
F¨oljande funktioner utg¨or Await och Cause i Simple-OS f¨or att v¨anta p ˚a en h¨andelsevariabel respektive signalera p ˚a en h¨andelsevariabel.
/* Await */
void si_ev_await(si_event *ev) {
int pid;
*** ;
if (! *** ( *** , WAIT_LIST_SIZE)) {
pid = *** ( *** , WAIT_LIST_SIZE);
*** (pid);
} else
{
*** ; }
pid = process_get_pid_running();
*** (pid);
*** ( *** , WAIT_LIST_SIZE, pid);
*** ;
*** ; }
/* Cause */
void si_ev_cause(si_event *ev) {
int done;
int pid;
*** ;
done = *** ( *** , WAIT_LIST_SIZE);
while (!done) {
pid = *** ( *** , WAIT_LIST_SIZE);
*** ( *** , WAIT_LIST_SIZE, pid);
done = *** ( *** , WAIT_LIST_SIZE);
}
*** ; }
Programkod markerad med *** har dock raderats. Varje f¨orekomst av *** ska ers¨attas med n ˚agon av f¨oljande kodsnuttar:
• wait list remove lowest prio
• wait list remove highest prio
• wait list remove one
• wait list remove all
• wait list is empty
• wait list is full
• wait list insert
• ENABLE INTERRUPTS
• DISABLE INTERRUPTS
• unschedule()
• schedule()
• ready list insert
• ready list remove
• ready list is empty
• ready list is full
• ev->mutex->wait list
• ev->mutex->ready list
• ev->wait list
• ev->ready list
• ev->mutex->counter++
• ev->mutex->counter--
Din uppgift ¨ar att skriva ned de kompletta versionerna av si ev await och si ev cause.
F¨or full po¨ang m ˚aste programkoden ¨aven vara kommenterad!
Uppgift 5: Semaforer och h¨ andelsevariabler(10p)
Betrakta f¨oljande program:
#include <simple_os.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFFER_SIZE 1
#define STACK_SIZE 5000
stack_item Producer_Stack[STACK_SIZE];
stack_item Consumer_Stack[STACK_SIZE];
/* data structure for buffer */
typedef struct {
/* the buffer itself */
char buffer_data[BUFFER_SIZE];
/* position for next write */
int in_pos;
/* position for next read */
int out_pos;
/* number of elements in the buffer */
int count;
/* semaphore for protection of the buffer */
si_semaphore mutex;
/* event to indicate that the buffer has changed state, from full to non-full or from empty to non-empty */
si_condvar change;
} buffer_data_type;
typedef buffer_data_type* buffer_type;
buffer_type buffer;
/* create buffer: creates a buffer and initialises the created buffer */
buffer_type create_buffer(void) {
/* reference to the created buffer */
buffer_type buffer;
/* allocate memory */
buffer = (buffer_type) malloc(sizeof(buffer_data_type));
/* start writing at first position */
buffer->in_pos = 0;
/* start reading at first position */
buffer->out_pos = 0;
/* no elements ar stored in the buffer */
buffer->count = 0;
/* initialise semaphore and event variable */
si_sem_init(&buffer->mutex, 1);
si_cv_init(&buffer->change, &buffer->mutex);
return buffer;
}
/* put item: stores an item in buffer */
void put_item(buffer_type buffer, char item) {
/* reserve buffer */
si_sem_wait(&buffer->mutex);
/* check if the buffer is full, and if this is so, wait */
while (buffer->count == BUFFER_SIZE) {
si_cv_wait(&buffer->change);
}
/* store item in buffer */
buffer->buffer_data[buffer->in_pos] = item;
buffer->in_pos++;
if (buffer->in_pos == BUFFER_SIZE) {
buffer->in_pos = 0;
}
buffer->count++;
/* notify other processes that a change has occurred */
si_cv_broadcast(&buffer->change);
/* release buffer */
si_sem_signal(&buffer->mutex);
}
/* get_item: read an item from the buffer */
char get_item(buffer_type buffer) {
/* item to read from the buffer */
char item;
/* reserve buffer */
si_sem_wait(&buffer->mutex);
/* check if buffer is empty, and if this is so, wait */
while (buffer->count == 0) {
si_cv_wait(&buffer->change);
}
/* read item from buffer */
item = buffer->buffer_data[buffer->out_pos];
buffer->out_pos++;
if (buffer->out_pos == BUFFER_SIZE) {
buffer->out_pos = 0;
}
buffer->count--;
/* notify other processes that a change has occurred */
si_cv_broadcast(&buffer->change);
/* release buffer */
si_sem_signal(&buffer->mutex);
/* return value read */
return item;
}
void producer_task(void) {
char string_to_send[] = "123";
int i;
char item;
while(1) {
for (i=0; i<strlen(string_to_send); i++) {
item = string_to_send[i];
put_item(buffer, item);
printf("P:%c\n",item);
}
si_wait_n_ms(2000);
} }
void consumer_task(void) {
char item;
while(1) {
item = get_item(buffer);
printf("C:%c\n",item);
} }
/* main */
int main(void) {
/* initialise kernel */
si_kernel_init();
buffer = create_buffer();
/* create tasks */
// High priority:
si_task_create(producer_task, &Producer_Stack[STACK_SIZE-1], 10);
// Low priority:
si_task_create(consumer_task, &Consumer_Stack[STACK_SIZE-1], 20);
/* start the kernel */
si_kernel_start();
/* will never be here */
return 0;
}
(a) (2p) Vad skriver programmet ut fram till dess att producer task v¨antat f¨ardigt i 2000 ms, dvs under f¨orsta varvet i while-loopen? Det r¨acker med ett svar som endast visar sj¨alv utskriften.
(b) (8p) Beskriv varf¨or utskriften blir som den blir i uppgift (a). Var noggrann med att f¨orklara och motivera, g¨arna stegvis. T¨ank p ˚a att beskriva, vad som h¨ander och varf¨or med processerna vid relevanta tillf¨allen, vilka relevanta funktioner som anropas samt bufferns status och inneh ˚all.
L¨ osningsf¨ orslag fr ˚aga 1
F¨oljande notation g¨aller:
# = process running _ = process not running
. = no process running (unused time slot)
| = deadline (met) / = deadline (missed)
1a
F¨or EDF g¨aller att kraven uppfylls om utnyttjandegraden Ue≤ 1, dvs:
n/12 + 2/9 + 2/6 ≤ 1 3n/36 + 8/36 + 12/36 ≤ 1 3n ≤ 16
n ≤ 16/3
Allts ˚a, st¨orsta v¨arde p ˚a n ¨ar 5.
Med EDF schemal¨aggs alltid den process som har kortast tid kvar till deadline. D ˚a fle- ra processer har lika l ˚ang tid kvar och en av dom redan k¨or l ˚ater man den processen forts¨atta f¨or att slippa ett processbyte.
P1_ _ _ _ # # # # # _ _ _|_ _ _ # # # # # _ _ _ _|_ _ # # # # # _ _ _ _ .|
P2_ _ # # _ _ _ _ _|_ _ # # _ _ _ _ _|_ _ _ _ # # _ _ _|_ _ _ _ # # _ _ .|
P3# # _ _ _ _|_ _ _ # # _|_ # # _ _ _|_ _ # # _ _|# # _ _ _ _|_ _ _ # # .|
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 Alla processer klarar sina deadlines och den faktiska utnyttjandegraden blir 35/36.
Vid tidpunkten t=36 blir samtliga processer samtidigt redo att k¨ora igen, dvs d¨ar b¨orjar f¨orloppet om.
(Kommentar: L¨osningen beh¨over visa hela tidsf¨orloppet (inklusive deadlines) fram till t=36, att k¨orande process forts ¨atter (i f¨orekommande fall), korrekt dra slutsatsen om vilka processer som klarar sina deadlines, att v ¨ardet p ˚a n=5, samt att den faktiska utnyttjandegraden blir 35/36)
1b
MED RMS f ˚ar processerna prioriteter utefter hur ofta de ska k¨oras, dvs ju kortare tidsintervall ju h¨ogre prioritet. Prioriteten bli allts ˚a P3 > P2 > P1. D¨arefter anv¨ands schemal¨aggningsmetoden priority based preemptive scheduling.
P1_ _ _ _ # # _ _ # _ _ #/_ _ # # # # _ _ _ _ # .|_ _ # _ _ # _ _ # # # .|
P2_ _ # # _ _ _ _ _|# # _ _ _ _ _ _ _|_ _ # # _ . _ _ _|# # _ _ _ _ _ _ .|
P3# # _ _ _ _|# # _ _ _ _|# # _ _ _ _|# # _ _ _ .|# # _ _ _ _|# # _ _ _ .|
0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 P1 missar sin deadline vid tidpunkten t=12. P2 och P3 klarar sina deadlines. Den
faktiska utnyttjandegraden blir 34/36 (intervallen t=[23,24],[35,36] blir outnyttjade).
Vid tidpunkten t=36 blir samtliga processer samtidigt redo att k¨ora igen, dvs d¨ar b¨orjar f¨orloppet om.
(Kommentar: L¨osningen beh¨over visa hela tidsf¨orloppet (inklusive deadlines) fram till t=36, tala om de inb¨ordes prioriteterna f¨or P1, P2 och P3 vid RMS, korrekt dra slutsatsen om vilka processer som klarar sina deadlines (och visa var och vilka som inte g¨or det), visa outnyttjade tidsintervall, samt att den faktiska utnyttjandegraden blir 34/36.)
L¨ osningsf¨ orslag fr ˚aga 2
2a
En relativt odelbar kritisk region f ˚ar avbrytas, men ingen annan process f ˚ar anv¨anda gemensam resurs. En absolut odelbar kritisk region f ˚ar inte ens avbrytas (avbrott st¨angs av). Detta f¨orekommer i realtidssystemets k¨arnfunktioner, t ex Wait, Signal, Await, Cause.
2b
En semafor har ett v¨arde ≥ 0, medan en mutex har v¨ardet 0 (l ˚ast) eller 1 (ol ˚ast).
En semafor kan anv¨andas f¨or asymmetrisk/symmetrisk synkronisering, men det g ˚ar inte med en mutex d ˚a den m ˚aste l ˚asas/ol ˚asas inom samma tr ˚ad.
2c
De delar av realtidssystemet som v¨axlar kontext vid ett processbyte m ˚aste g¨oras i assembler d ˚a ett h¨ogniv ˚aspr ˚ak som C saknar m¨ojligheten att g¨ora saker som att spara undan och ˚aterst¨alla CPU:ns kontext p ˚a/fr ˚an processens stack. Specifikt byte av stackpekare, ˚aterst¨allande av CPU:ns registerinneh ˚all samt programr¨aknare.
2d
Tidskvanta : Den process som varit k¨orklar l¨angst tid f ˚ar k¨ora (s k Round-Robin scheduling)
K¨oordning : Den process som ligger f¨or i ready-listan f ˚ar k¨ora (FIFO: First in First Out)
2e
Det avg¨ors i CPU:ns h ˚ardvara, via speciella atomiska assemblerinstruktioner, t ex TAS (Test And Set) eller CAS (Compare And Swap).
L¨ osningsf¨ orslag fr ˚aga 3:
Eftersom antalet processer i barri¨aren kan vara f¨arre ¨an det maximala antalet pro- cesser i systemet (MAX PROC) s ˚a m ˚aste vi h ˚alla reda p ˚a vilka processer som tr¨att in i barri¨aren, f¨or att senare sl¨appa just dessa processer fr ˚an barri¨aren till en ny ber¨akningsomg ˚ang.
Skulle ett nytt v¨arde p ˚a limit vara mindre ¨an count (antalet processer i barri¨aren), eller om count uppn ˚att v¨ardet p ˚a limit s ˚a ¨ar det dags att ber¨akna medelv¨ardet och skicka resultatet till ui(), samt d¨arefter start en ny ber¨akningsomg ˚ang f¨or all processer i barri¨aren.
Problemet med att nya processer kommer in i barri¨aren samtidigt som barri¨aren redan ¨ar full eller d ˚a limit ¨andras l¨oser sig automatiskt med meddelandehantering eftersom inkommande meddelanden k¨oas och barri¨aren hanterar ett meddelande i taget.
#define NO_PID -1
#define PORT_BARRIER 0
#define PORT_UI 1
#define PORT_PROC 10 typedef enum {
ENTER, // message from proc() to barrier() when proc entering barrier
CALC, // message from barrier() to proc() when proc should start new calculation AVG, // message from barrier() to ui() with average run time data
LIMIT // message from ui() to barrier() with new limit value } message_type;
struct message {
message_type type; // message type
int pid; // process id
int data; // runtime, limit or average data };
void barrier(int limit) {
struct message *m; // message pointer char buf[4096]; // message buffer
int count = 0; // number of proc’s in barrier int sum = 0; // sum of runtimes
int pids[MAX_PROC]; // to keep track of pids in barrier int i;
/* initialize pids to NO_PID */
for (i=0; i<MAX_PROC; i++) { pids[i] = NO_PID;
}
while (1)
{
/* wait for message */
message_receive(buf, 4096, PORT_BARRIER);
m = (struct message *) buf;
switch (m->type) {
case LIMIT: // message from ui() with new limit limit = m->data;
break;
case ENTER: // message from proc() entering barrier pids[count] = m->pid;
sum = sum + m->data;
count++;
break;
default:
break;
}
if (count >= limit) {
/* send average value to ui() /*
m->type = AVG;
m->data = sum / count;
message_send((char *) m, sizeof(*m), PORT_UI, 0);
/* reset total sum */
sum = 0;
/* release all processes from barrier */
while (count > 0) {
count--;
m->type = CALC;
if (pids[count] != NO_PID) {
message_send((char *) m, sizeof(*m), PORT_PROC+pids[count], 0);
pids[count] = NO_PID;
} } } } }
L¨ osningsf¨ orslag fr ˚aga 4:
/* Await */
void si_ev_await(si_event *ev)
int pid;
/* atomic section begins */
DISABLE_INTERRUPTS;
/* among processes waiting for the mutex, make the one with highest prio ready to run */
if (!wait_list_is_empty(ev->mutex->wait_list, WAIT_LIST_SIZE)) {
pid = wait_list_remove_highest_prio(ev->mutex->wait_list, WAIT_LIST_SIZE);
ready_list_insert(pid);
} else
{
/* no processes are waiting, so unlock the mutex */
ev->mutex->counter++;
}
/* now wait on the condition variable, so remove ourself from readylist and insert into event waiting list */
pid = process_get_pid_running();
ready_list_remove(pid);
wait_list_insert(ev->wait_list, WAIT_LIST_SIZE, pid);
/* find new process to run */
schedule();
/* atomic section ends */
ENABLE_INTERRUPTS;
}
/* Cause */
void si_ev_cause(si_event *ev) {
int done;
int pid;
/* atomic section begins */
DISABLE_INTERRUPTS;
/* move all processes waiting on the condition variable to instead wait on the mutex */
done = wait_list_is_empty(ev->wait_list, WAIT_LIST_SIZE);
while (!done) {
pid = wait_list_remove_one(ev->wait_list, WAIT_LIST_SIZE);
wait_list_insert(ev->mutex->wait_list, WAIT_LIST_SIZE, pid);
done = wait_list_is_empty(ev->wait_list, WAIT_LIST_SIZE);
}
/* atomic section ends */
ENABLE_INTERRUPTS;
}
L¨ osningsf¨ orslag fr ˚aga 5:
5a
Programmet skriver ut f¨oljande under f¨orsta varvet i while-loopen f¨or producer task:
P:1 P:2 C:1 P:3 C:2 C:3 5b
Vi kallar producer task f¨or P, och consumer task f¨or C.
1. P (h¨ogst prio) anropar put item med ’1’ (buffern ledig och tom), l¨agger in ’1’ i buffern, si cv broadcast orsakar inget, si sem signal l ˚ater P (h¨ogst prio) forts¨atta.
2. P skriver ut ’P:1’
3. P anropar put item med ’2’ (buffern ledig och full), P flyttas till v¨antelistan f¨or h¨andelsevariabeln change, C blir k¨orande.
4. C anropar get item (buffern ledig och full), l¨aser ’1’, si cv broadcast flyttar P fr ˚an v¨antelistan f¨or change till v¨antelistan f¨or semaforen mutex, si sem signal flyttar P fr ˚an v¨antelistan f¨or semaforen till readylistan och P (h¨ogst prio) blir k¨orande.
5. P forts¨atter i put item (buffern ledig och tom), skriver in ’2’ i buffern. si cv broadcast orsakar inget, si sem signal l ˚ater P (h¨ogst prio) forts¨atta.
6. P skriver ut ’P:2’
7. P anropar put item med ’3’ (buffern ledig och full), P flyttas till v¨antelistan f¨or h¨andelsevariabeln change, C blir k¨orande.
8. C returnerar fr ˚an get item med ’1’.
9. C skriver ut ’C:1’
10. C anropar get item (buffern ledig och full), l¨aser ’2’, si cv broadcast flyttar P fr ˚an v¨antelistan f¨or change till v¨antelistan f¨or semaforen mutex, si sem signal flyttar P fr ˚an v¨antelistan f¨or semaforen till readylistan och P (h¨ogst prio) blir k¨orande.
11. P forts¨atter i put item (buffern ledig och tom), skriver in ’3’ i buffern, si cv broadcast orsakar inget, si sem signal l ˚ater P (h¨ogst prio) forts¨atta.
12. P skriver ut ’P:3’, P st¨aller sig och v¨antar 2000 ms, C blir k¨orande 13. C returnerar fr ˚an get item med ’2’.
14. C skriver ut ’C:2’
15. C anropar get item (buffern ledig och full), l¨aser ’3’, si cv broadcast orsa- kar inget, si sem signal l ˚ater C forts¨atta (endast C ¨ar redo).
16. C skriver ut ’C:3’, anropar get item och blir v¨antande p ˚a h¨andelsevariabeln (buffern tom).