a) Ange en uppgift som det är operativsystemet som utför.
Svar:
Att hantera processer, som att skapa, schedulera och ta bort dem. Att hantera användaridentiteter, som att skapa dem, ta bort dem och ge dem rättigheter, och även att kontrollera de rättigheterna så de inte överskrids. Att hantera sekundärminnet med filer och filkataloger, och möjliggöra för programmen att läsa och skriva filerna. |
b) Ange en uppgift som operativsystemet inte utför.
Svar:
Redigering av text, ljud, bilder och andra data i olika program, till exempel Photoshop. Spel. |
c) Ange en uppgift där det inte är uppenbart ifall operativsystemet eller ett applikationsprogram ska lösa den.
Svar:
Här kan man ge olika svar. En känd historisk händelse är "webbläsarkriget" på 1990-talet. Webben var ganska ny, och webbläsaren Netscape Navigator var helt dominerande. Den var ett applikationsprogram som, precis som andra applikationsprogram, man fick ladda ner (eller snarare läsa in från CD-skiva, för det var ju på 1990-talet) och installera på sin dator. Microsoft hävdade då att deras konkurrerande webbläsare, Internet Explorer, var en del av operativsystemet Windows. De skickade med den med varje kopia av Windows, och hävdade att den inte gick att avinstallera eftersom den var en integrerad del av operativsystemet. Eftersom alla Windows-användare var tvungna att ha Internet Explorer, och nästan alla vanliga datorer använde Windows, lyckades Microsoft konkurrera ut Netscape, och Internet Explorer blev den dominerande webbläsaren. Andra exempel: Virusskydd (som kan vara inbyggt i operativsystemet eller ett separat program). Trådhantering (som kan ha stöd av operativsystemet och kärnan, elle vara ett separat paket med enbart user space-trådar). |
a) Det står att man "flyttat ut delar av kärnans uppgifter ut ur kärnan". Vart har man flyttat dem?
Svar:
Till vanliga processer ("user mode processes") som inte kör med de särskilda rättigheter som kärnan har ("kernel mode") utan i "user mode", och i vanligt minne ("user space"). |
b) Varför vill man göra det, dvs vilka fördelar ger en mikrokärna?
Svar:
En fördel med mikrokärnor är att om en av de funktioner som är placerade i vanliga processer utanför kärnan skulle krascha, så leder det inte till att hela systemet kraschar. Därigenom blir operativsystemet stabilare. Eftersom det blir mindre kod i kärnan, blir det också lättare att granska och testa den, vilket är tänkt att göra operativsystemet stabilare (mot krascher) och säkrare (mot angrepp). |
c) Vilka nackdelar ger det?
Svar:
Prestanda kan bli sämre, eftersom kärnan och de utflyttade delarna ibland måste kommunicera med varandra, och eftersom de utflyttade delarna kör i user mode och kärnan (förstås) i kernel mode, kan det behövas byten mellan user mode och kernel mode, och tillbaka, och kopiering av data mellan user space (användarprocessernas minne) och kernel space (kärnans minne). |
d) Ge exempel på någon uppgift som man kan flytta ut ur kärnan.
Svar:
Användargränssnitt. Hantering av filsystem. |
e) Ge exempel på någon uppgift som man inte kan flytta ut ur kärnan. Varför går det inte att flytta ut den?
Svar:
Skapande, schedulering och annan hantering av processer. Dessa kräver tillgång både till priviligierade instruktioner som processorn bara tillåter i kernel mode, och till kärnans interna datastrukturer (till exempel taskstructar och köer). |
#include <stdio.h> #include <unistd.h> int x = 0; int main(void) { int y = 0; fork(); x = x + 1; y = y + 1; fork(); x = x + 1; y = y + 1; fork(); x = x + 1; y = y + 1; printf("x = %d, y = %d\n", x, y); } |
a) Vad skrivs ut när programmet körs?
Svar:
x = 3, y = 3 x = 3, y = 3 x = 3, y = 3 x = 3, y = 3 x = 3, y = 3 x = 3, y = 3 x = 3, y = 3 x = 3, y = 3 |
b) Kan det bli olika utskrifter från gång till gång, och vad beror det i så fall på?
Svar:
Nej. Vid fork får barnprocessen en egen adressrymd, som till att börja med är en kopia av föräldraprocessens, förutom att returvärdet från fork-anropet är olika. Varje process har alltså sin egen adressrymd, så ingen av variablerna x och y är delad mellan dem. Raderna som skrivs ut kan visserligen komma i olika ordning, eftersom det inte finns någon synkronisering mellan de olika processerna, men i slutet av programmet när variablerna skrivs ut har de samma innehåll i alla processerna, så utskrifterna är identiska. Det kan förstås bli olika utskrifter, till exempel om någon stänger av datorn medan programmet körs, eller om datorn redan kör maximalt antal processer, så att fork-anropen misslyckas, eller om kosmisk strålning påverkar innehållet i minnet. |
#include <stdio.h> #include <pthread.h> volatile int x = 0; void *thread_body(void *arg) { int y = 0; x = x + 1; y = y + 1; printf("x = %d, y = %d\n", x, y); return NULL; } int main(void) { int z = 0; x = x + 1; z = z + 1; printf("x = %d, z = %d\n", x, z); pthread_t thread1, thread2; pthread_create(&thread1, NULL, thread_body, NULL); pthread_create(&thread2, NULL, thread_body, NULL); pthread_join(thread1, NULL); pthread_join(thread2, NULL); printf("x = %d, z = %d\n", x, z); } |
a) Vad skrivs ut när programmet körs?
Svar:
Det här är det resultat man kan förvänta sig:
x = 1, z = 1 x = 2, y = 1 x = 3, y = 1 x = 3, z = 1Vid en provkörning en miljon gånger fick man ovanstående resultat 999844 gånger. Man fick följande resultat 136 gånger: x = 1, z = 1 x = 3, y = 1 x = 2, y = 1 x = 3, z = 1Det blev detta resultat 20 gånger: x = 1, z = 1 x = 2, y = 1 x = 2, y = 1 x = 2, z = 1Vid en annan provkörning fick man också detta resultat: x = 1, z = 1 x = 3, y = 1 x = 3, y = 1 x = 3, z = 1 |
b) Kan det bli olika utskrifter från gång till gång, och vad beror det i så fall på?
Svar:
|
a) Hur stor är den virtuella adressrymden?
Svar:
28 adresser, dvs 256 adresser eller 256 byte |
b) Hur stor är den fysiska adressrymden?
Svar:
26 adresser, dvs 64 adresser eller 64 byte |
c) Hur stor är en virtuell minnessida ("page" på engelska)?
Svar:
24 byte, dvs 16 byte |
d) Hur stor är en fysisk frame ("ram" på svenska)?
Svar:
Lika stor som en virtuell minnessida, dvs 16 byte |
e) Hur många frames (dvs platser för minnessidor) kan man ha i datorn?
Svar:
26 / 24 = 26-4 frames, dvs 4 frames |
f) Vi tänker oss att vi har en sidtabell ("page table") för en process, och att enligt den sidtabellen är virtuell minnessida 3 lagrad i fysisk frame 2. (Båda numreras med början på noll.) Ange en adress inom denna virtuella minnessida, och visa hur den översätts till en fysisk adress. Visa både hur översättningen görs och vad resultatet blir.
Svar:
3 decimalt är 11 binärt,
och den första adressen på den virtuella minnessidan 3 (dvs den fjärde)
är 0011 0000 binärt, eller 3*16 = 48 decimalt.
Via sidtabellen översätter vi sidnummer 3 (11 binärt) till framenummer 2 (10 binärt),
och ersätter 3 (0011 binärt) i den virtuella adressen med framenummer 2 (10 binärt):
10 0000 binärt, dvs 2*16 = 32 decimalt.
På samma sätt översätts virtuell adress 49 (0011 0001 binärt) till 33 (10 0001 binärt), virtuell adress 50 (0011 0010 binärt) till 34 (10 0010 binärt), och så vidare till den sista virtuella adressen på den sidan, 63 (0011 1111 binärt), som översätts till 33 (10 1111 binärt):
|
g) Om vi vill använda den här datorn till något, som till exempel beräkningar, vilka problem kommer vi att få?
Svar:
Minnet är förstås mycket litet, så det går inte att göra särskilt komplicerade beräkningar. Dels är det virtuella minnet litet, så vi kan inte ha så mycket data, och dessutom är det fysiska minnet ännu mindre, så om vi har annat än mycket lite data kommer vi att behöva page:a ut och in från någon sorts sekundärminne, vilket blir långsamt. Om vi dessutom tänkt oss att ha körbar programkod, operativsystem och sidtabell i primärminnet, blir det verkligen svår att få plats med allt. (Men våra 256 byte virtuellt minne är mer minne än vad som från början fanns i ENIAC: 20 stycken register för 10-siffriga decimala tal!) Minnet är litet, men sidstorleken är stor jämfört med minnet. Det kan ge onödigt stor intern fragmentering. (Intern fragmentering betyder att eftersom minnessidorna har en fast storlek, kommer en del av vissa sidor att vara oanvänd.) Det finns bara plats för 4 sidor åt gången i minnet, vilket kan orsaka thrashing. (Thrashing betyder att de data som används inte alla får plats i det fysiska minnet, så datorn måste ägna mycket tid åt att flytta data fram och tillbaka mellan primärminnet och sekundärminnet.) Särskilt illa blir det om vi tänkt oss att vi ska kunna köra flera processer samtidigt. |
Svar:
Med sidindelat virtuellt minne. Man allokerar inte sammanhängande fysiskt minne, utan använder en virtuell minnesrymd som delas in i lika stora "sidor" (på engelska "pages"), exempelvis med storleken fyra kilobyte. Det fysiska minnet delas in i "frames" (på svenska kanske "ramar"), med samma storlek som sidorna, och en sida kan sedan placeras i vilken ledig frame som helst. Processens sidor behöver inte lagras sammanhängande eller i ordning i ramarna. "Sidtabellen" (på engelska "page table") översätter mellan sidnummer och ramnummer, dvs mellan virtuella och fysiska adresser. Den virtuella minnesrymden är sammanhängande, men fysiskt kan sidorna vara lagrade i en annan ordning. Man kombinerar ofta detta med "paging", som innebär att en sidas innehåll kan flyttas till sekundärminne om det inte används just då. Då kan man frigöra plats i det fysiska primärminnet, för innehåll som faktiskt ska användas. Det gör att en process kan använda mer minne än vad som fysiskt finns, och det underlättar att hitta lediga frames, men det som löser problemet med att hitta ett tillräckligt stort, sammanhängande utrymme är den sidindelade virtuella adressrymden, inte att minnesinnehåll sparas på sekundärminne. |
Om man låter två processer dela på ett gemensamt minnesutrymme, är en del av minnet alltså gemensamt för de två processerna. Har de blivit två trådar nu? Eller finns det skillnader jämfört med om de verkligen var trådar? Förklara!
Svar:
Förutom det gemensamma minnesutrymmet har varje process fortfarande eget minne, som den andra processen inte kommer åt. Trådar lever inom en process och i dess minnesutrymme, och de olika trådarna har inget eget minne som de andra trådarna inte kan komma åt. Varje tråd har en egen stack, men den skyddas inte från åtkomst från de andra trådarna. Operativsystemets data om processerna, som till exempel vilken användare det är som kör och vilka filer de har öppna, är fortfarande separata för de två processerna, inte gemensamma som om de varit trådar i samma process. En annan skillnad mot om det var trådar är att trådar kan vara "user space-trådar", vars schedulering sköts helt av vanliga programkod i det körande programmet, utan att operativsystemkärnan är inblandad eller ens vet om att de finns. Det kan inte dessa processer. |