TDDIU81
Processer
och
trådar
Andreas Dahlberg, Jonathan
Doherty, Tony Magnusson, Patrik
Ottosson, Rasmus Siljedahl
Sammanfattning
Den här rapporten innehåller en kort
genomgång av allmän process och
trådhantering i operativsystem. Sen beskrivs
hur detta är implementerat i
operativsystemet Pintos.
Processer
När en process skapas av parentprocess så
får den nya childprocessen ett unikt process
identifier(pid), för att underlätta
identifieringen av alla processer. När den
nuvarande childprocessen sedan skapar nya
childprocesser blir den själv en
parentprocess. När de körts klart så avslutas
dom och tas bort med systemanropet exit().
Då avallokers allting som den processen
använt av operativsystemet [1].
Det är lite skillnad på vad som händer när en
process skapas i Unix jämfört mot
Windows. I Unix skapas en ny childprocess
med systemanropet fork(). För att
parentprocessen lättare ska kunna
kommunicera med den nya processen så
innehåller den nya processen en kopia av
adressutrymmet hos föräldern. Efter fork()
så fortsätter båda två att exekveras[1].
I Windows skapas en ny process med
funktionen CreateProcess() vilket påminner
om fork() på det sätt att en ny process
skapas av en parentprocess. Skillnaden
mellan är att CreateProcess() måste ladda in
ett program till adressutrymmet av
childprocessen istället för att ärva
adressutrymmet av sin förälder[1].
För att starta en process i Pintos så måste
först en ny tråd skapas, det görs genom att
kalla på funktionen thread_create().
Thread_create() skapar i sin tur en kernel
tråd och en struct thread som sedan läggs till
i queuen. Struct thread innehåller en page
för thread stacken som är 4kb stor, samt
relevant data. Då en process består av denna
struct thread betyder det att struct thread är
processens process control block (PCB). Det
betyder även att struct thread representerar
thread control block (TCB) på samma gång.
Därav har Pintos en 1:1 mappning mellan
user trådar och kernal trådar och PCB och
TCB är representerade i samma data
struktur. Skapningen av tråden fortsätter i
funktionen start_process där en userprocess
laddas och körs. Precis som i boken så har
processen ett id men i Pintos är det samma
som trådens id.
En av de viktigaste funktionerna för att
hantera processer är ”process_execute” som
finns i pintos, denna funktion exekverar det
som står på ”command line”. Detta gör den
genom att skapa en ny process. När den ska
skapar en ny process gör den det genom att
skapa en ny ”thread” och schemalägger att
funktionen ”start_process” ska köras.
Funktionen ”start_process” är i pintos en
”thread” funktion som laddar användarens
process och kör den.
När en process ska avslutas så ska
“process_exit()” köras i pintos och returnera
statuskoden. Jämfört med boken Operating
system concept då UNIX kör “exit()” utför
den samma som pintos att returnera status
men också ser till att tömma allt minne. I
pintos utförs detta av en egen funktion
“process_cleanup”. När “exit()” körs i
UNIX, kan “parent” processen använda sig
av “wait()” för att vänta på att “child”
processen ska avslutas. I pintos finns
motsvarande funktion “process_wait()” som
väntar på att “child” processen ska dö och
returnera exit status[2].
Funktionen ”process_cleanup” är viktig när
en process är klar och ska stängas ner eller
om en process har kraschat. Den har till
uppgift att städa upp den nuvarande
processens resurser genom att befria minnet
som den tar upp.
1
Varje gång en process ska utföra en “context
switch” kallas funktionen
“process_activate”, den har som uppgift att
ställa in cpu till att köra “user code”, den
laddar in “page directory” till cpu’s “page
directory” bas register. Som de beskriver i
boken Operating system concept är det
“interrupts” som orsakar en “context
switch”. När detta sker utförs en ”state save”
som sparar den nuvarande processens
värden för att senare kunna aktivera
processen igen. När den aktiveras igen så
kör den “state restore” och detta är
motsvarigheten till “process_activate” i
pintos[3]. Det sista som sker i
“process_activate är att den ställer tillbaka
“interrupt” så att det återigen kan ske.
Schemaläggning
I Pintos initieras ready-kön i början av filen
thread/thread.c. De funktionerna som
används för att schemalägga proccesser är:

”thread_unblock()” lägger den
inmatade tråden i ready-kön och
sätter trådens läge till
THREAD_READY

”thread_block()” låter den inmatade
tråden vänta tills thread_unblock()
anropas. Trådens läge sätts till
THREAD_BLOCKED. Sen
schemaläggs en ny tråd för körning.

”running_thread()” hämtar den
tråden som körs för tillfället. För att
ta reda på vilken tråd som körs så tar
man reda på vilken sida stackpekaren
är i. Längst upp på sidan finns då
struct thread som ger den
information man vill ha.

”next_thread_to_run()” hämtar nästa
tråd att köras från ready-kön.

”schedule()” använder de två
ovanstående funktionerna och byter
till den nya tråden.

”schedule_tail()” anropas i slutet av
”schedule()” och sätter den
nuvarande trådens läge till
THREAD_RUNNING. Sen
nollställs thread_ticks och
proccessen aktiveras. Om den
föregående tråden hade läget
THREAD_DYING så frigörs dess
minne.

”thread_yield()” lägger den tråden
som körs på ready-kön och sätter
dess läge till THREAD_READY.
Sen anropas ”schedule()” för att
starta en ny tråd.

”thread_tick()” anropas via en
interupt timer. Funktionen räknar
upp en variabel som håller reda på
hur många ticks tråden körts. User,
idle och kerneltrådarna har varsin
räknare. Om tråden har kört sina
maximala tics anroppas
”thread_yield()”. Antalet tics varje
tråd får köra i ett sträck bestäms av
konstanten TIME_SLICE.
2
Bilden nedan visar vilka funktioner som
flyttar trådar mellan olika lägen.
Schemaläggningsalgoritmen som används är
Round-robin. Round-robin schemaläggning
fungerar som FIFO-schemaläggning fast
med preemption. Varje tråd körs i ordningen
som de läggs på ready-kön. Men varje tråd
får bara köra under en förutbestämd tid åt
gången. När tiden gått ut körs nästa tråd
istället. När alla trådar körts börjar man om
från början igen. Om en tråd blir färdig
innan sitt tidsfönster har gått ut så släpper
den CPUn och nästa tråd schemaläggs
direkt.
Round-robin är en simpel
schemaläggningsalgoritm som är enkel att
implementera men saknar vissa funktioner
såsom prioritering. Det är viktigt att välja
rätt storlek på tidsfönstret då det ha en stor
inverkan på algoritmens prestanda. Ett för
litet värde ger mycket overhead då byten
mellan trådar sker väldigt ofta. Med ett för
stort värde blir algoritmen i princip en FCFS
istället.
Trådhantering
De states(waiting, running etc) som finns i
pintos för trådar är liknande andra operativ
som finns. Läser man boken så ser man att
nästan alla operativ har likadana states, och
det skiljer sig väldigt lite mellan olika
operativsystem. Däremot finns det stora
skillnader mellan hantering av dessa trådar.
Kerneltrådar och usertrådar hanteras inte på
samma sätt i olika operativsystem.
I Pintos används en one-to-one model.
Structen kernal_thread anropas i funktionen
thread_create vilket ger att för varje process
som startas, så startasen kernal thread som
senare blir kopplad till en user thread som
senare kör processen. Denna metod är en av
de enklaste metoderna att implementera och
är använt av till exempel win32 och linux.
Nackdel är att det finns ett begränsat antal
kernel threads. Det kan innebära att man inte
kan starta upp vissa andra user threads,
eftersom alla kernels är upptagna.
I Pintos nuvarande implementation skapas
en ny kerneltråd varje gång man skapar en
ny tråd. Genom att modifiera nuvarande
struct thread som i nuläget representerar
både PCB och TCB och skapa en ny
datastruktur för Process Control
Block(PCB), kan man skapa nya Thread
Control Blocks och lägga till dem till sin
process(PCB) genom pekare. Då en ny user
thread skapas lägger man till referensen till
Process Control Blocket placerar den på
kön, sedan när det är denna threads tur att
exekvera använder den länken till sin
Process Control Block för att få tillgång till
processens resurser. Process Control Block
bör flyttas till filen där processer hanteras
och innehålla följande data:
3
--- PCB --+---------------+
| Tillgängligt |
| minne
|
+---------------+
| Trådar
|
+---------------+
| Öppna filer |
+---------------+
| Schemaläggn.|
| Info
|
| Prioritet
|
+---------------+
| ID
|
+---------------+
Referenslista
1. Abraham Silberschatz, Greg Gagne, Peter
Baer Galvin. Operating system concept:
3.3.1 Process Creation 90-95.
2. Abraham Silberschatz, Greg Gagne, Peter
Baer Galvin. Operating system concept:
3.3.2 Process Termination 95.
3. Abraham Silberschatz, Greg Gagne, Peter
Baer Galvin. Operating system concept:
3.2.3 Context Switch 89-90.
Thread Control Block kan vara kvar i
nuvarande struct thread med följande data:
TCB
+---------------+
| Stack
|
| "fil.txt"
|
+---------------+
| MINNE FÖR |
| RESULTAT |
+---------------+
| LÄS FIL
|
+---------------+
| CPU Context/|
| Sparade reg. |
+---------------+
4