Den som någon gång i livet vill dyka djupt in i operativsystemsteorier
som till exempel processhantering gör klokt i att köpa nedanstående
bok:
Silberschatz, Galvin, Gagne: Applied Operating System Concepts, Wiley
2000 (ISBN: 0-471-36508-4)
En bok om trådar i Java som tar upp väsentligt mer operativsystems-
och hårdvaruaspekter än våran kursbok är:
Lewis, Berg: Multithreaded Programming with Java, Prentice Hall 2000
(ISBN: 0-13-017007-0)
Innan svaret på den frågan reflekterar vi över vad som egentligen utgör ett exekverande program. Tänk till exempel på programmen du körde på exkit i kursen Digital- och datorteknik förra året. Det behövs naturligtvis en programkod, maskininstruktioner som processorn läser in och exekverar. Dessutom behövs det lite minnesutrymme för till exempel variabler och stack. Programmet är naturligtvis även i högsta grad beroende av processorns register (programräknare, stackpekare osv). Ponera nu att operativsystemet (nu har vi lämnat exkit) reserverar ett utrymme i minnet för programkoden, dataarean och stacken samt dessutom en plats där innehållet i alla processorns register sparas. Innehållet i denna minnesarea beskriver till fullo programmet och den punkt i exekveringen det befinner sig på (det senare kallas programmets tillstånd). Så länge denna minnesarea är intakt spelar det ingen roll vad som händer med datorn eller vilken kod processorn exekverar. Det är bara att lägga tillbaks det registerinnehåll vi sparade så kommer processorn att fortsätta exekvera programmet exakt där den var när registren sparades.
Nu är det dags att besvara frågan hur flera program kan exekveras samtidigt av en enda processor. Svaret är att operativsystemet lägger upp en sådan minnesarea som vi nyss pratade om för varje program som körs, sedan växlar det mellan de olika programmen så snabbt att det upplevs som att alla program exekveras samtidigt. En sådan programexekvering kallas en process och minnesarean som beskriver den kallas bland annat process control block (PCB) eller process structure. Observera att varken maskinkoden, dataarean eller stacken behöver flyttas när en annan process ska börja exekvera. Det räcker att läsa in processorns register. Programräknaren kommer då att peka på kod i den nya processen och stackpekaren kommer att peka på den nya processens stack.
En process behöver alltså inte ta någon som helst hänsyn till andra processer. Varje process/program kommer att uppleva det som att den har processorn helt för sig själv när den exekverar.
Operativsystemet exekverar många fler processer än vad användarna har startat program, till exempel finns det normalt processer som hanterar nätverket och en process som exekverar när processorn inte har något annat att göra. Om du har Windows kan du starta aktivitetshanteraren så får du en lista över alla processer på datorn (På Windows NT måste du klicka på fliken processer). Har du Linux eller någon UNIX kan du skriva ps -ax för att få en sådan lista.
Till exempel är det mycket mer än vad som ovan nämnts som måste sparas i en PCB. Bland annat måste den innehålla en lista över öppna filer, någon form av processnamn (för att den ska kunna anropas) och användarens identitet (för att avgöra vilka rättigheter den har).
Alla dessa PCB:er kommer att ligga i en massa köer och listor vilka ska struktureras och behandlas på något sätt. En stor fråga är i vilken ordning väntande processer ska få exekvera. Hur kan vi till exempel vara säkra på att viktiga processer får exekvera först? Att det inte finns processer som aldrig får exekvera? Att inte vissa användare upplever datorn som onödigt slö därför att deras processer får lite exekveringstid? När och hur länge processerna får exekvera kallas skedulering (scheduling).
Om exekverande process byts endast vid bestämda punkter i programmet (till exempel när den själv begär det eller när den utför någon form av I/O) kallas det frivilligt byte eller non-preemptive sheduling. Om processerna kan bytas när som helst (vanligtvis genom att någon tidskrets generar ett avbrott med jämna mellanrum och avbrottsrutinen byter process) kallas det ofrivilligt byte eller preemptive scheduling.
Nu förtiden är det inte ovanligt att en dator har flera processorer. Allt vad som här nämnts gäller även då men det blir ytterliggare mer komplicerat. Till exempel måste skeduleringen ske så att det inte står processer i kö till en CPU medans andra CPU:er är sysslolösa. Alla CPU:er måste jobba ungefär lika mycket (load balancing). Om alla CPU:er har en egen cache (vilket de har) är det väldigt klurigt att utarbeta rutiner för att försäkra sig om att de har samma uppfattning om hur minnet ser ut, det ska inte finnas olika värden på samma variabel i olika cacher. Dessa rutiner kallas minnesmodell. Om datorn har mer än en CPU kan flera processer verkligen exekveras i ett och samma ögonblick, detta kallas parallell exekvering. Om datorn endast har en CPU kan flera processer visserligen vara igång men i ett visst ögonblick kan endast en av dem exekveras. Det kallas concurrent (samtidig) exekvering.
En process är som sagt ett eget program som exekverar sin egen kod. Alla trådar i processen exekverar däremot samma program (eftersom de inte har något eget minnesutrymme för programkod utan alla använder processens programkod. För övrigt gäller allt sagts om minneshantering, skedulering och köer även för trådar, lika väl som för processer.
Det finns många programbibliotek som tillhandahåller metoder för att skapa och hantera trådar. Med hjälp av dessa kan trådade program skrivas i de flesta språk. Java är däremor ett av de realtivt få språk där trådhanteringen är inbyggd i själva språket och därför alltid finns tillgänglig.
En tråd kan skapas på två sätt:
Här kommer programmet, HelloWorldThread.java. Observera att metoden run() aldrig anropas. Den börjar automatiskt exekveras i sin egen tråd när vi anropar start(). Observera också att det bara finns en run(). Alla trådarna exekverar samma kod.