Örebro universitet
Institutionen för naturvetenskap och teknik
Thomas Padron-McCarthy (thomas.padron-mccarthy@oru.se)









Tentamen i

Operativsystem för civilingenjörer

fredag 29 augusti 2025

Gäller som tentamen för:
DT513G Operativsystem för civilingenjörer, provkod A001


Hjälpmedel: Ordbok för översättning.
Poängkrav: Maximal poäng är 40. För godkänt betyg krävs 24 poäng.
Resultat: Meddelas senast 15 arbetsdagar efter tentamensdatum.
Återlämning av tentor: Elektroniskt via webbportalen Studenttjänster.
Examinator och jourhavande: Thomas Padron-McCarthy, telefon 070 - 73 47 013.




LYCKA TILL!

Tabeller och formler

20 = 1 224 = 16777216 248 = 281474976710656
21 = 2 225 = 33554432 249 = 562949953421312
22 = 4 226 = 67108864 250 = 1125899906842624
23 = 8 227 = 134217728 251 = 2251799813685248
24 = 16 228 = 268435456 252 = 4503599627370496
25 = 32 229 = 536870912 253 = 9007199254740992
26 = 64 230 = 1073741824 254 = 18014398509481984
27 = 128 231 = 2147483648 255 = 36028797018963968
28 = 256 232 = 4294967296 256 = 72057594037927936
29 = 512 233 = 8589934592 257 = 144115188075855872
210 = 1024 234 = 17179869184 258 = 288230376151711744
211 = 2048 235 = 34359738368 259 = 576460752303423488
212 = 4096 236 = 68719476736 260 = 1152921504606846976
213 = 8192 237 = 137438953472 261 = 2305843009213693952
214 = 16384 238 = 274877906944 262 = 4611686018427387904
215 = 32768 239 = 549755813888 263 = 9223372036854775808
216 = 65536 240 = 1099511627776 264 = 18446744073709551616
217 = 131072 241 = 2199023255552 265 = 36893488147419103232
218 = 262144 242 = 4398046511104 266 = 73786976294838206464
219 = 524288 243 = 8796093022208 267 = 147573952589676412928
220 = 1048576 244 = 17592186044416 268 = 295147905179352825856
221 = 2097152 245 = 35184372088832 269 = 590295810358705651712
222 = 4194304 246 = 70368744177664 270 = 1180591620717411303424
223 = 8388608 247 = 140737488355328 271 = 2361183241434822606848

2x * 2y = 2x+y
2x / 2y = 2x-y

Uppgift 1 (6p)

a) Vad menas med operativsystemkärnan? Hur är den relaterad till kärnorna i en flerkärnig CPU? Är operativsystemkärnan en av CPU-kärnorna, eller vad?

b) Vad menas med en mikrokärna?

c) Vilka fördelar och nackdelar ger en mikrokärna?

Uppgift 2 (3p)

Man brukar säga att operativsystemet erbjuder en virtuell maskin. Samtidigt finns det virtualisering, som också handlar om virtuella maskiner. Vad är skillnaden? Är det helt olika saker, eller hänger de ihop på något sätt? Jämför och förklara!

Uppgift 3 (3 p)

Här är ett C-program för Linux. Vad skrivs ut när programmet körs? Förklara!

#include <stdio.h>
#include <unistd.h>

int x = 1;

int main(void) {
    int y = 1;
    fork();
    x = x + 1;
    y = y + 1;
    fork();
    fork();
    printf("x = %d, y = %d!\n", x, y);
}

Uppgift 4 (8 p)

a) Man brukar säga att en viktig skillnad mellan trådar och processer är att varje process har sin egen minnesrymd, medan flera trådar kan dela på samma minnesrymd. En annan skillnad är att operativsystemkärnan alltid måste känna till alla processer, men det kan hända att det finns trådar som operativsystemkärnan inte vet om. Förklara varför detta är olika för processer och trådar!

b) En process kan befinna sig i olika tillstånd, som "ny", "redo", "körande", "färdig" och "väntar". Rita upp ett tillståndsdiagram för hur processens tillstånd kan ändras, med de händelser som kan göra att det ändras.

c) Operativsystemkärnan innehåller att antal köer som processerna placeras i. Vilka är det? Hur hänger köerna ihop med de olika tillstånden från uppgiften ovan?

d) Processkontrollblocket (PCB) eller task-structen har bland annat plats för innehållet i processorns register. Varför det? Registerinnehållet finns väl i registren?

Uppgift 5 (5 p)

Här är programmet threads.c, som startar tre trådar som var och en ökar variabeln g med ett 100 miljoner gånger.

#include <stdio.h>
#include <pthread.h>

volatile int g = 0;

void *thread_body(void *arg) {
    int thread_number = (int)arg;
    printf("Startat tråd %d...\n", thread_number);
    for (int i = 0; i < 100 * 1000 * 1000; ++i) {
        ++g;
    }
    printf("Avslutar tråd %d...\n", thread_number);
    return NULL;
}

int main(void) {
    pthread_t thread_1, thread_2, thread_3;
    pthread_create(&thread_1, NULL, thread_body, (void*)1);
    pthread_create(&thread_2, NULL, thread_body, (void*)2);
    pthread_create(&thread_3, NULL, thread_body, (void*)3);
    printf("Trådarna kör...\n");
    pthread_join(thread_1, NULL);
    pthread_join(thread_2, NULL);
    pthread_join(thread_3, NULL);
    printf("Klart! g = %d\n", g);
}

Vid en provkörning av programmet får vi den här utskriften:

Trådarna kör...
Startat tråd 3...
Startat tråd 1...
Startat tråd 2...
Avslutar tråd 3...
Avslutar tråd 1...
Avslutar tråd 2...
Klart! g = 118428316

a) Eftersom var och en av de tre trådarna ökar variabeln g med ett 100 miljoner gånger, borde utskriften bli 300000000, men i stället blev den 118428316. Vad beror det på?

b) Utskriften av Trådarna kör står efter pthread_create-anropen i main som startar de tre trådarna. Hur är det möjligt att den kan komma före utskrifterna om att trådarna har startat?

c) Skulle även utskriften Klart! kunna komma "konstigt", dvs på en annan plats än som sista raden? Förklara!

Uppgift 6 (4 p)

Vi skriver om programmet så här i stället. Ändringarna är markerade.

#include <stdio.h>
#include <pthread.h>

volatile int g = 0;
volatile int the_lock = 0; // 0 = ledigt, 1 = låst

void lock(void) {
    // Först, vänta på att låset blir ledigt
    while (the_lock != 0) { }
    // Nu är låset ledigt, så vi låser det
    the_lock = 1;
}

void unlock(void) {
    the_lock = 0;
}

void *thread_body(void *arg) {
    int thread_number = (int)arg;
    printf("Startat tråd %d...\n", thread_number);
    for (int i = 0; i < 100 * 1000 * 1000; ++i) {
        lock();
        ++g;
        unlock();
    }
    printf("Avslutar tråd %d...\n", thread_number);
    return NULL;
}

int main(void) {
    pthread_t thread_1, thread_2, thread_3;
    pthread_create(&thread_1, NULL, thread_body, (void*)1);
    pthread_create(&thread_2, NULL, thread_body, (void*)2);
    pthread_create(&thread_3, NULL, thread_body, (void*)3);
    printf("Trådarna kör...\n");
    pthread_join(thread_1, NULL);
    pthread_join(thread_2, NULL);
    pthread_join(thread_3, NULL);
    printf("Klart! g = %d\n", g);
}

a) Fungerar låset, så resultatet i variabeln g alltid blir 300 miljoner? Förklara!

b) Det här är en variant på ett så kallat spin-lock. Vad innebär spin-lock?

c) Oavsett om just detta spin-lock fungerar eller inte, är det lämpligt att använda spin-lock här? Förklara!

Uppgift 7 (7 p)

Vi har en byteadresserad dator som arbetar med virtuellt minne. Virtuella adresser består av 48 bitar och fysiska adresser består av 16 bitar. Sidstorleken ("page size") är 256 byte.

a) Hur stor är den virtuella adressrymden?

b) Vi har satt i så mycket primärminne i datorn att hela den fysiska adressrymden kan utnyttjas. Hur mycket primärminne har datorn?

c) Hur många bitar av den virtuella adressen används för att ange offset inom en minnessida?

d) Hur många bitar av den fysiska adressen används för att ange offset inom en frame?

e) Hur många minnessidor är den virtuella minnesrymden indelad i?

f) Hur många olika ramar ("frames") är det fysiska minnet indelat i?

g) Om vi antar att sidtabellen ("page table") består av en array med en plats för varje virtuell minnessida, skulle den tabellen få plats i det fysiska minnet? Förklara!

Uppgift 8 (4 p)

På en av teoriövningarna i kursen var en av frågorna "Hur lång tid tar det att skriva en gigabyte data till en fil?"

Svaret var förstås att det beror på, särskilt på vad det är för medium man skriver till, som om det är en SSD, en mekanisk hårddisk, ett primärminnesfilsystem med hela filsystemet lagrat i primärminne, eller om man skriver till specialfilen /dev/null på Linux, som bara kastar bort alla data.

I lösningsförslagen fanns den här tabellen från en provkörning av ett Linux-program som skriver en gigabyte data, med olika tider för olika media:

Medium write-anropen close-anropet sync-anropet Total tid
SSD 0.32 0.39 0.02 0.73
Mekanisk hårddisk 0.31 6.63 0.16 7.10
Primärminnesfilsystem 0.16 0.00 0.00 0.16
/dev/null 0.00 0.00 0.00 0.00

Programmet öppnade filen som skulle skrivas med systemanropet open, skrev datat med flera anrop till write, och stängde filen med close. Därefter använde det sync, som vi känner igen från programmet flush_cache.c från en av labbarna.

a) Varför tar close-anropet ibland så lång tid, ibland mycket längre än den sammanlagda tiden för write-anropen? Förklara!

b) Varför har man gjort så det blir så?