De klassieke UNIX versies ondersteunen geen multithreading, elk

advertisement
Modelvragen Besturingssystemen I
1) Reeks A
1.1.
Vraag A1
Procesbeheer: interrupts en uitvoering van besturingssystemen
a) Beschrijf de werking en de bedoeling van interrupts:
eenbeschrijving van het mechanisme van I/O bewerkingen !),
andere interrupt optreedt.
b) Bespreek drie alternatieven waarop de relatie tussen het besturingssysteem tot processen
kan worden benaderd (cfr. §2.4 van de cursus, uitvoering van besturingssystemen): bestaat
het besturingssysteem zelf uit processen ?
c) Welke alternatieven worden gevolgd in UNIX, Linux en Windows NT ?
d) Kan men in deze besturingssystemen gebruik maken van threads ? Zo ja, welk implementatiemodel volgen deze threads ?
Werking en bedoeling van interrupts:
Een interrupt is een hardwaremechanisme dat een extern apparaat in staat stelt om de CPU een
signaal te sturen wanneer de I/O operatie voltooid is.
Een interrupt wordt gegenereerd door een I/O controller (niet door de administrator), door een
signaal op de IRQ (Interrupt Request Line) lijn te zetten.
Verwerking door de CPU:
In de interruptcyclus controleren of er interrupts zijn opgetreden door het interruptsignaal te
bekijken.
Er zijn geen interrupts:
-> De CPU gaat verder met de opvraagcyclus.
Er zijn wel wachtende interrupts:
-> De CPU onderbreekt huidige programma, slaat informatie op voor het hervatten van het
programma. De inhoud van alle registers en het adres van de volgende instructie in het
hoofdprogramma, worden op de stack geplaatst. De programmateller wordt bijgewerkt zodat hij
naar het begin van de interruptroutine verwijst.
Verwerking door het besturingssysteem:
De verwerking is afhankelijk van de computerarchitectuur en het besturingssysteem. Soms is er één
enkele routine voor de interruptafhandeling, of er is een specifieke routine voor elk type interrupt.
Soms is er één interruptlijn per I/O controller, soms is er één interruptlijn per voor meerdere
controllers, deze moeten zich dan kunnen identificeren bij het genereren van een interrupt.
De meeste architecturen maken gebruik van een interruptvector, een tabel van verwijzingen naar
gespecialiseerde routines voor specifieke interruptafhandeling. De routine voor de interrut wordt
hierbij indirect via de tabel aangeroepen. Zo moeten niet alle apparaten afgescand worden, om te
zien welk apparaat de interrupt gegenereerd heeft.
Mechanisme van I/O bewerkingen:
Om een I/O-operatie te starten, laadt de CPU gegevens in de I/O-controller. Hierdoor weet de
controller, welke gegevens moeten opgehaald worden. Bij een uitvoer, van hoofdgeheugen naar I/Oapparaat, moeten ook de buffers gevuld worden. (1) en (2).
De controller interageert dan met het apparaat, om de data in of uit de buffer te schrijven. (3).
Bij geprogrammeerde I/O moet het gebruikersprogramma nu een wachtlus uitvoeren, om te zien of
de actie is uitgevoerd. (4) en (5).
In elke wachtlus gaan 3 instructiecycli verloren:
 Het apparaatregister lezen.
 Waarde van signaleringsbit bepalen.
 Voorwaardelijke spronginstructie uitvoeren.
Na de wachtcycli kan nu de buffer naar het hoofdgeheugen geschreven worden, of is de buffer vrij
voor een nieuwe I/O-operatie. (6).
Deze synchrone benadering houdt de processor telkens op wanneer een I/O-aanvraag wordt
verwerkt.
Een I/O-bewerking bestaat uit 3 stappen:
 Een voorbereidende sectie.
 De feitelijke I/O-overdracht.
 Voltooiing van de opdracht.
De feitelijke I/O-overdracht kan enkele duizenden processorcycli in beslag nemen, dit verspilt
processorgebruik.
Interrupts en I/O-bewerkingen.
Met interrupts kan de processor andere instructies uitvoeren terwijl een I/O-bewerking bezig is.
Nadat de I/O-opdracht is gegeven, wordt de besturing teruggegeven aan het hoofdprogramma. De
I/O-bewerking wordt gelijktijdig uitgevoerd met het hoofdprogramma, als de bewerking voltooid is
wordt een interrupt naar het hoofdprogramma doorgestuurd, die de I/O-opdracht voltooit, en dan
doorgaat met het hoofdprogramma.
Hierdoor ontstaat overhead, door het verwerken van de interrupt, maar de processor verspilt geen
tijd met wachten op afhandeling van de I/O-bewerking. Toch kan het toch voorvallen dat de
processor toch moet wachten, maar dan nog is er verbetering van efficiëntie.
Een interrupt gedurende een interrupt:
Er zijn twee mogelijke manieren om dit op te lossen. Een eerste benadering is om interrupts te
blokkeren, als een interrupt verwerkt wordt. De interrupts worden in sequentiële volgorde
behandeld.
In een tweede benadering worden prioriteiten ingevoerd. Routines voor interruptafhandeling
kunnen onderbroken worden door interrupts met hogere prioriteit.
Drie alternatieven waarop de relatie tussen het besturingssysteem tot processen kan worden
benaderd. Het besturingssysteem als proces.
Kernel zonder processen:
Dit wordt vooral gebruikt in oudere besturingssystemen.
De kernel heeft een eigen geheugengebied en een eigen systeemstack.
Processen worden enkel toegepast op gebruikersprogramma’s.
De kernel werkt als een afzonderlijke entiteit, in een geprivilegieerde kernelmodus.
Bij een interrupt, trap of systeemaanroep wordt het huidige actieve proces opgeslagen en de
besturing overgedragen aan de kernel.
Besturingssysteem is een verzameling van systeem aanroepen.
De software van het besturingssysteem wordt uitgevoerd in de context van een gebruikersproces. De
procesbeelden bevatten ook programma-, gegevens- en stackgebieden voor kernelprogramma’s.
Bij een interrupt, trap of systeemaanroep wordt een moduswisseling uitgevoerd, en een routine voor
het besturingssysteem uitgevoerd. Er dient niet altijd een proceswisseling plaats te vinden. Indien
een proceswisseling noodzakelijk is, wordt binnen het proces de context opgeslagen en de besturing
overgedragen aan een routine voor proceswisseling buiten alle processen om. Binnen één proces
kunnen zowel gebruikersprogramma’s als besturingssysteemfuncties uitgevoerd worden, door de
verschillende modi, kan de gebruiker de functie van het besturingssysteem niet storen.
Microkernelbenadering.
Besturingssysteemfuncties worden gestructureerd als aparte processen, uitgevoerd in kernelmodus.
In deze benadering zijn veel meer proceswisselingen met de nodige overhead noodzakelijk.
Het besturingssysteem kan wel beschouwd worden als een verzameling verschillende modules, met
onderling eenvoudig interfaces.
De processen kunnen met aangepaste prioriteit verweven worden met andere processen.
Sommige processen hoeven niet noodzakelijk in de kernelmodus uitgevoerd worden.
Een deel van de besturingssysteemprocessen kan toegewezen worden aan specifieke processoren.
Windows NT:
Windows NT is gemodelleerd volgens de microkernelarchitectuur. NT bestaat uit een microkernel en
een aantal modules. Het verschil met een zuivere microkernelarchitectuur is dat enkele modules in
de kernelmodus worden uitgevoerd.
UNIX en Linux:
In UNIX en Linux wordt alle software van het besturingssysteem uitgevoerd in de context van een
gebruikersproces. Het besturingssysteem wordt dus beschouwd als een verzameling van
systeemaanroepen.
Gebruik van threads in besturingssystemen:
UNIX (klassiek):
De klassieke UNIX versies ondersteunen geen multithreading, elk proces komt met één thread
overeen.
Solaris:
Solaris laat in tegenstelling tot de klassieke UNIX varianten, een zeer intensief gebruik van threads
toe.
Solaris gebruikt net zoals Windows NT en Linux een combinatie van user-level en kernel-level
threads.
1.2.
Vraag A2
Procesbeheer: kenmerken van moderne besturingssystemen
a) Bespreek de (drie) meest typische kenmerken van moderne besturingssystemen.
b) In hoeverre beantwoorden UNIX, Linux en Windows NT hieraan ? Geef hierbij de
belangrijkste elementen van de detailstructuur van deze besturingssystemen.
a)
1. Multitasking en multithreading


multitasking

processoren hebben een groot deel vd tijd niets te doen: processorgebonden
perioden worden afgewisseld met I/O gebonden perioden, waarbij de CPU deze
laatste periode niet voldoende benut (zelfs niet met interrupts)

oplossing: multitasking/multiprocessing: bij onderbreking van een programma
door een interrupt, kan de routine voor interruptafhandeling na verwerken van
de interrupt de besturing onmiddellijk teruggeven aan het onderbroken
programma, of aan een ander programma overdragen.

de volgorde van verwerking van programma's door hun relatieve prioriteit.

interleaving: processorgebonden perioden van meerdere programma's met
elkaar verweven.

elk individueel programma heeft de illusie als enige de systeembronnen te
gebruiken (door transparantie van gedeeld gebruik van processortijd, geheugen
en andere bronnen door OS)
multithreading

geavanceeerde vorm van multitasking en verschilt van multiprocessing

multiprocessing:systeem bevat meerdere processoren, twee processoren kunnen
hetzelfde tijdstip elk een proces uitvoeren.

multithreading:

meerdere gelijktijdige threads voor uitvoering van instructies

proces heeft meerdere programmatellers: voor elke thread specifieke
teller

alle threads delen alle bronnen a/h proces toegewezen

alle threads binnen proces zijn evenwaardig (geen ouder-kind relatie)
2. Symmetrische multiprocessing
- assymetrische multiprocessing:

één master processor waar de kernel van het OS wordt uitgevoerd,
andere processoren voor gebruikersprogramma's en hulpprogramma's.

master verantwoordelijk voor scheduling.

indien processor een dienst nodig heeft (bvb I/O oproep): verzoek sturen
naar master, wachten tot dienst uitgevoerd is: master vormt bottleneck
voor het systeem.

vereist weinig aanpassingen aan het OS.
- symmetrische multiprocessing:

kernel uitgevoerd op elke processor.

ofwel kernel opgebouwd als meerdere processoren, waardoor
gedeelten van kernel parallel kunnen worden uitgevoerd door
verschillende processoren.

ofwel voert elke processor volledige kopie van OS uit.

in beide gevallen kan scheduling van taken op elke processor worden
uitgevoerd.

hogere eisen aan OS: communicatie tussen processoren en
synchroniseren van aanspraken op bronnen.

ruime mogelijkheden op het gebied van beschikbaarheid en
uitbreidingsmogelijkheden.

performantie stijgt niet lineair met aantal processoren:niet altijd genoeg
programma's die effectief van processor gebruik kunnen maken.
3. Modulair ontwerp
- OS software moet regelmatig aangepast worden voor verbetering van fouten,
invoeren van diensten of compatibiliteit met nieuwe hardware: noodzaak voor
modulair ontwerp.
- verschillende manieren voor verdeling in modules
- hiërarchisch gescheiden lagen:

interactie hardware op onderste niveau ; gebruikersinterface op hoogste niveau

elk niveau verzorgt diensten voor het volgende niveau en verbergt
implementatiedetails

theoretisch model voor hiërarchisch OS in 13 niveaus (cfr OSI 7 model)

volledige kernel blijft draaien in kernelmodus waardoor elke laag
rechtstreeks toegang heeft tot hardware.

Strikte volgorde bij lagenmodel onmogelijk.

correcte oplossing waarbij interactie tussen twee niveaus door elke
tussenliggende laag wordt doorgegeven: niet efficiënt.

in OS geen concrete implementaties van dit gelaagd model.

wel toegepast op schaal in bepaalde deelmodules, oa. I/O subsystemen
- microkernelarchitectuur:

client/server model: enkele essentiële functies vh OS worden toegewezen aan
kernel.

kernel wordt klein gehouden; andere diensten worden verzorgd door processen
(~servers) die in gebruikersmodus worden uitgevoerd.

serverprocessen hebben geen rechtstreekse toegang tot de hardware. Ze werken
onderling samen adhv doorgeven van berichten via kernel.

microkernel maakt modulaire ontwikkeling van kernel en servers wel mogelijk.

nieuwe servers en meerdere servers in hetzelfde functionele gebied kunnen
toegevoegd worden ; bestaande servers kunnen weggelaten worden
(gereduceerde implementaties zoals Windows XP embedded)

alle hardware afhankelijkheid zit in microkernel.

geschikt voor gedistribueerde systemen: cluster van afzonderlijke computers:
processen op verschillende computers sturen onderling berichten zonder te
weten op welke machine deze draaien.

nadeel: weinig performant door belasting van berichtenuitwisseling.

huidig systeem: hoofdmodule (kernel) zorgt voor basisdiensten ; deelmodules
geladen indien functionaliteit ervan noodzakelijk is. Deze modules hebben
afgeschermde interfaces, en kunnen zelf nieuwe modules oproepen. Er is ook
communicatie mogelijk tussen hoofdmodule en deelmodules.
b)
1) Windows NT
- volgens microkernelarchitectuur:

NT bestaat uit een microkernel en een aantal modules

Elke systeemfunctie wordt door slechts één component beheerd met een
gestandaardiseerde interface

elke module kan onafhankelijk van de anderen worden vervangen

aantal modules worden in kernelmodus uitgevoerd (performantie: snellere
toegang hardware): Executive (gelaagde structuur)

Hardware Abstraction Layer: vertaling van algemene opdrachten naar
instructies, geheugenmapping, configuratie bussen, afhandeling DMA

microkernel: scheduling, synchronisatie processen, traps en interrupts,
herstel na stroomonderbreking

executieve diensten: NT modules in kernelmodus, geïmplementeerd door
systeemthreads

I/O manager (I/O verzoeken)

Cache manager (schrijfcache beheren)

Security Reference Monitor (toegangcontrole)

Object Manager (objectbeheer)

Proces Manager (proces/threadobjectenbeheer)

Virtual Memory Manager (vertaling virtuele->fysieke
geheugenadressen)

modules in gebruikersmodus: omgevingssubsystemen en
afschermingssubsystemen

aparte adresruimte

controle identiteit

generatie toegangstokens

versleuteling gegevens

beveilingsbeleid (Local Security Authority Subsystem)

zorgt voor interactie gebruiker dmv API

elk programma: 1 omgevingssubsysteem (indien niet actief:
dynamisch opgestart)

POSIX subsysteem: UNIX compatibele software compileren en
uitvoeren

uitgevoerd als proces (Local Procedure Call: aanvraag (bericht) van
client via Executive naar juiste server en van die server via
Executive terug naar client). LPC beschikbaar via DLL's.
- objectgeörienteerde principes zonder uitsluitend objectgeörienteerde methoden te
gebruiken

grotendeels geïmplementeerd in C/Assembler

objecten krijgen een naam (padnaam in dezelfde abstracte naamruimte
met 1 enkele root)

in gebruikersruimte: toegang tot object indirect via gebruikersfuncties en
een objecthandle (beheerd door Object Manager van Executive)

objecten gebruikt voor

gegevensstructuren binnen Executive (voor toegang in
gebruikersruimte)

toegang tot gegevens die gedeeld of beveiligd zijn (via Security
Descriptors)

kernelobjecten/dispatchterobjecten (semaforen, processen,
threads)

bestanden, geheugensegmenten, I/O poorten

berichtenuitwisseling LPC mechanisme
2) UNIX
- bestaat uit twee interfaces:

kernel (isoleert hardware van gebruiker en toepassingen)

gebruikersdiensten (shell, interfacesoftware, componenten C compiler)
- kernel van oudere UNIX versies is weinig modulair opgebouwd (niets voorzien om
gegevensstructuren te beschermen tegen gelijktijdige toegang door meerdere
processoren)
- bestaat ook uit twee subsystemen:

procesbeheer: geheugenbeheer, scheduling en communicatie tussen processen

bestandbeheer en I/O: lagere niveaus binnen dit subsysteem bevat
machineafhankelijke code: routines voor interruptafhandeling en
apparaatstuurprogramma's ontwikkeld in C -> vrij eenvoudig om UNIX naar
nieuwe hardware over te brengen.
3) Linux
- modulaire architectuur (kleine kern, aangevuld met andere modules): elke module
kan onafhankelijk van elkaar worden geïmplementeerd, op voorwaarde dat externe
interfaces van de routines ongewijzigd blijven.
- hoofddoel: zoveel mogelijk functionaliteit met beperkte bronnen.
- voldoen aan POSIX compatibiliteit
- algemeen ontwerp van de kernel lijkt sterk op traditionele vorm UNIX: monolithische
kernel

modulaire benadering via Loadable Kernel Modules (stuurprogramma's,
netwerkprotocol, bestandssysteem): dynamisch linken en verwijderen aan
actieve kernel

draaien in kernelmodus en dus volledige toegang tot hardware
1.3.
Vraag A3
Procesbeheer: procestoestanden
a) Teken het algemene (onafhankelijk van een specifiek besturingssysteem) procestoestand
diagram. Beschrijf eveneens het eraan geassocieerde wachtrijsysteem. Uit welke entiteiten
bestaan deze wachtrijen ? Verduidelijk dit begrip.
b) Bespreek de zeven in a) optredende procestoestanden.
c) Bespreek alle in a) mogelijke overgangen.
d) In hoeverre wijkt het procestoestand diagram van UNIX af van het in a) beschreven algemene
diagram. Bespreek deze afwijkingen.
a)
Wachtrij = lijst met processen die wachten op toewijzing van de scheduler
Kan bestaan uit: (als er rekening wordt gehouden met prioriteiten)
 verzameling gelinkte lijsten, geïndexeerd door tabel van prioriteiten
 binaire bomen. Elke knoop in die boom verwijst naar max. 2 andere deelbomen, en
heeft een kleinere (= lagere?) prioriteit dan die van al zijn subknopen.
b) Procestoestanden:
1. Actief (running) = Enkel voor het proces dat op die moment wordt uitgevoerd op die
processor.
2. Gereed (ready) = Kunnen uitgevoerd worden wanneer de scheduler hen de
toestemming geeft.
3. Gereed–onderbroken = Het proces is gereed maar staat geswapt. (zie p.31)
4. Geblokkeerd (blocked) = Wachten op een bepaalde gebeurtenis (bv. I/O operatie)
5. Geblokkeerd–onderbroken = Een proces wachtend op een gebeurtenis wordt
geswapt
6. Nieuw (new) = Dezen zijn al aangemaakt, maar nog niet toegevoegd aan de lijst met
uitvoerbare processen.
7. Einde (exit) = Dezen zijn vrijgegeven, maar hun tabellen zijn nog niet afgebroken. Dit
geeft ondersteunende programma’s de tijd om de benodigde informatie nog te
verwerken.
c) Overgangen:
1. nieuw -> gereed: Wordt beslist door scheduler van het OS.
2. gereed -> actief: De scheduler kiest een van de klaarstaande processen.
3. actief -> einde: Proces is voltooid of wordt afgebroken.
4. acief -> gereed: Ofwel heeft OS een tijdslimiet per proces ingesteld, ofwel stopt het proces
vrijwillig. (door sleep() bv)
5. actief -> geblokkeerd: Proces moet op iets wachten (I/O, beïndigen kindproces) Meestal in
de vorm van een systeemaanroep.
6. geblokkeerd -> gereed: De gebeurtenis waarop het wachtte is opgetreden.
Na de introductie van de swap-techniek zijn er nog nieuwe overgangen:
1. geblokkeerd -> geblokkeerd–onderbroken: Als geen enkel proces op gereed staat of als er
te weinig hoofdgeheugen vrij is => swappen
2. geblokkeerd–onderbroken -> gereed – onderbroken: Gebeurtenis waarop het geswapte
proces wachtte, is opgetreden (OS detecteert dit dan zelf)
3. gereed–onderbroken -> gereed: Proces wordt teruggeswapt. Ofwel is er geen ready
proces meer voorhanden in MEM, ofwel heeft dat proces hogere prioriteit dan al de
andere ready processen.
4. gereed -> gereed–onderbroken: Soms enige optie om groot genoeg geheugenblok vrij te
hebben. Of omdat een met hogere priotiteit voorhanden is.
5. actief -> gereed–onderbroken: bij preëmptief ingrijpen, om MEM vrij te maken.
6. geblokkeerd-onderbroken -> geblokkeerd: Pro-actief vanwege hoge prioriteit of omdat er
juist MEM is vrijgekomen.
7. nieuw -> gereed-onderbroken en nieuw -> gereed: twee opties voor activeren nieuwe
processen. Bij de eerste wijst men direct adresruimte en tabellen voor het beheer toe,
maar swapt men onmiddelijk. Bij de tweede optie volgt men meer een just-in-time
principe. Keuze tussen beide opties: job-scheduler (Windows NT and Unix hebben deze
niet, plaatsen elk proces gwn in het geheugen)
d)
Procestoestand diagram van UNIX: afwijkingen
1. Twee verschillende soorten actief, om aan te geven of het om gebruikers- of kernelmodus
gaat. Om naar een andere toestand te gaan moet elk proces eerst overgaan naar de
kernelmodus.
2. Maakt voor gereed onderscheid tussen 2 deeltoestanden (worden echter door de scheduler als
1 behandeld). Preempted: Proces wordt in deze toestand geplaatst als de uitvoering in
kernelmode door een interrupt wordt verstoord.
1.4.
Vraag A4
Procesbeheer: creatie en wisselen van processen
a) Verduidelijk het begrip PCB.
b) Uit welke opeenvolgende stappen bestaat de creatie van een nieuw proces.
c) Hoe worden in UNIX en Linux nieuwe processen of threads gecreëerd ?
d) Bij welke diverse gebeurtenissen krijgt een besturingssysteem de controle over het
computersysteem ? Leiden deze steeds tot een proceswisseling ?
e) Bespreek stapsgewijs welke veranderingen aan de omgeving aangebracht worden bij een
proceswisseling, en hoe dit gerealiseerd wordt.
a) PCB (= Process Control Block) p.33
Een verzameling informatie over het beheer van een proces, bijgehouden in de geheugenruimte van
het proces zelf. Het moet altijd beschikbaar blijven in het hoofdgeheugen (of het proces zelf nu
geswapt is of niet bijv.)
Ze kunnen enkel door instructies in de kernelmodus gemanipuleerd worden.
De informatie die het bevat kan in drie categorieën ondergebracht worden:

procesidentificatie(pid) = unieke numerieke code eigen aan elk proces, toegewezen door
OS.
 processortoestandinformatie(tss) = Bevat de inhoud van alle processorregisters (oa
programmateller). Wordt gebruikt bij het hervatten van het proces.
 Procesbesturingsinformatie = Extra informatie dat het OS nodig heeft voor het beheren van
de verschillende processen.
Bijv:
-> scheduling- en toestandsinformatie (prioriteit, procestoestand, welke gebeurtenis
het op aan het wachten is, ...)
-> structurele informatie (hiermee worden procesblokken aan elkaar gekoppeld.)
-> bronnen (welke zijn aangevraagd en welke al verkregen)
-> privileges van het proces
b) Stappen voor procescreatie: p.35





Toewijzing unieke procesidentificatie en nieuwe ingang in de primaire procestabel.
Toewijzing voor alle elementen van het procesbeeld.
Initialisatie van het procesbesturingsblok.
Instelling van de juiste koppelingen (bv plaatsen in wachtrij gereed of gereed-onderbroken)
Eventueel het aanmaken of uitbreiden van andere gegevensstructuren.
c) Implementatie in UNIX en Linux: p.49 en p.51
Unix
Alle processen stammen af van het ouderproces (init). De kindprocessen worden gecreërd in een
boomstructuur met vertakkingen.Een kindproces wordt gecreëerd met de systeemaanroep fork(),
en uitgevoerd met execve(). (Details hierover zie p.49-50, ik weet niet of we het zo gedetailleerd
moeten kennen)
Threads: Unix ondersteund geen multithreading
Linux
fork() wordt vervangen door clone(). Veel meer parameters mogelijk voor kopieren van ouder dan
bij Unix.
Threads: Linux maakt geen onderscheid tussen processen en threads. Ze worden beide 'tasks'
genoemd Een Linux thread is een nieuwe task die dezelfde adresruimte heeft als de oudertask.
d) Wanneer krijgt het OS de touwtjes in handen? p. 35 ev.
1. Interrupts: Veroorzaakt door gebeurtenis die zich buiten het op dat moment actieve
proces afspeelt. Er wordt eerst overgeschakeld naar kernelmodus voor routine van
interuptafhandeling.
Belangrijste types interrupts:
-> periodieke klokinterrupts (limiet op tijdsduur voor een proces)
-> I/O-interrupts (verwittiging dat een I/O operatie is uitgevoerd)
-> paginafouten (verwijzingen naar elementen die niet meer in hoofdgeheugen zitten)
2. Trap (= exception): Speciaal soort interrupt. Hangt samen met een fout die wordt
gegenereerd binnen het op dat moment actieve proces. (bv als een prog in usermode iets
probeert dat enkel in kernelmode mag)
3. Systeemaanroepen (= software-interrupts): Manier voor gebruikersprogramma's om
geprivilegeerde instructies uit te voeren, door via systeemaanroepen diensten aan het OS te
vragen.Ze worden veroorzaakt op expliciet verzoek van het actieve proces.
(kunnen ofwel berichtgestuurd of proceduregestuurd zijn, hiervoor zie p. 37)
Wanneer leidt dit nu tot proceswisseling? (zoiezo altijd: context- en moduswisseling)
Dit hangt af van het type interrupt dat is opgetreden, de relatieve prioriteit van processen, ...
(meer heb ik hier niet over gevonden, zie p.39 bovenaan)
e) Stappen en realisatie van proceswisseling p.39

Opslaan van context van het proces dat wordt uitgevoerd. (= processortoestandinformatie
van het PCB). Wordt in de hardware uitgevoerd, één van de processorregisters verwijst
naar het geheugenadres van de processortoestandinformatie van dit proces.
 (ondertussen zit men in kernelmodus, was zoiezo al nodig voor de interruptafhandeling die
aan de proceswisseling vooraf ging)
 Verplaatsen van het PCB van dit proces naar de juiste wachtrij.
 Selectie van ander proces als volgend actief proces.


Bijwerken van PCB van nieuw proces (bv met betrekking tot procestoestand)
Bijwerken van gegevensstructuren voor het geheugenbeheer, afhankelijk van hoe de
virtuele adresvertaling beheerd wordt. (zie H4)
 Terugschakelen naar de gebruikersmodus en laden van processortoestandinformatie van
het geselecteerde proces in de registers van de processor.
1.5. Vraag A5
a) Thread = eenheid van verdeling van processorinstructies.
Binnen elk proces kunnen meerdere threads gebruikt worden, en dezen delen allemaal de bronnen
die aan dat proces toegewezen zijn.
Waarom zijn ze efficiënter?
1. Alle threads delen de toestand en de bronnen van dat proces. Ook de code wordt gedeeld
(het voordeel hiervan is dat toepassingen meer actieve threads hebben binnen dezelfde
adresruimte, waardoor de processor beter bezig gehouden kan worden). Dit komt zeker
van pas bij multi- processorarchitecturen.
2. Communicatie tussen threads kan eenvoudig om gedeeld geheugengebruik worden
gebaseerd zonder tussenkomst van de kernel.
3. Creëren en wisselen van threads binnen een proces vraagt aanzienlijk minder overhead
dan de overeenkomstige handelingen op processen.
4. Blokeert één thread op een gebeurtenis, dan hoeft het proces daarom niet geblokeerd te
worden. Hierdoor kan een programma ook verdergaan terwijl een deel ervan bezig is met
een langdurige bewerking.
b) Implementatie: Hoe? Nadelen, voordelen?

User-level threads: Al het werk voor het threadbeheer wordt door de toepassing zelf
uitgevoerd, met gebruik van een threadbibliotheek (= een verzameling routines waarmee
threads kunnen worden gecreërd, vernietigd en gewisseld, en waarmee de uitvoering van
threads gescheduled kan worden.)
De kernel herkent user-level threads niets en blijft het proces als een geheel
beschouwen.Het proces kan tijdens een threadwisseling met code in uitvoering door het
OS onderbroken worden en later terug worden hervat.
Voordelen:
a. ondersteund op elk besturingssysteem
b. threadwisselingen worden eficienter uitgevoerd omdat er niet naar kernelmodus
moet worden overgeschakeld. Zo wordt de overhead van contextwisselingen
vermeden.
c. het scheduling algoritme kan specifiek aan de toepassing worden aangepast, zonder
de scheduler van het besturingssysteem te storen.
Nadelen:
a. Wordt een thread geblokeerd door een langdurige aanroep, dan zijn alle threads van dat
proces tegelijk geblokkeerd. (een groot voordeel van threads gaat hier dus verloren)
b. Er kan maar een thread telkens actief zijn binnen het proces. Dus dit heeft geen nut op
multi-processorsystemen
-
Kernel-level threads: Scheduling wordt door de kernel uitgevoerd op basis van threads,
niet op bass van processen. Kernel houdt informatie bij voor het proces in het geheel en
voor de individuele threads apart.
Voordeel: Een geblokkeerde thread blokeert de andere threads van dat proces niet.
Nadeel: Wel een modus- en contextwisseling vereist telkens. Hierdoor moeten
ontwikkelaars oppassen met het aantal threads dat ze in een proces steken (soms op
kernel-level al gelimiteerd).
Opmerking:
threadpool = als een proces start wordt niet meteen één, maar een bepaald aantal threads
al aangemaakt en in een pool geplaatst waar ze wachten op werk. Is beter dan dat er
telkens een nieuwe thread moet worden aangemaakt en afgebroken. (bv: Apache v2)
-
Combinatie van de vorige 2: Verschillende user-lever threads worden in groep gekoppeld
aan een aantal kernel-level threads. Hiervoor moet de user-level bibliotheek
communiceren met de kernel. Dit gaat via 'lichtgewicht processen'. Dit is een soort
virtuele processor, waaraan een user-level thread gebonden kan worden.
Voor-/Nadelen:
a) Het creëren en wisselen van threads wordt uitgevoerd in de gebruikersruimte, en is
dus efficiënter.
b) Het blokkeren van een thread kan leiden tot blokkering van een aantal threads binnen
dat proces, maar niet noodzakelijk van het hele proces.
c) Meerdere threads van hetzelfde proces kunnen parallel uitgevoerd worden op multiprocessoren.
c) Bespreek figuur p.47
Zie pagina 47(gewoon hiertussen voegen, is gewoon helemaal hetzelfde)
d) Toestandsdiagrammen van Solaris
tekeningen zie figuur 2.35 p.52
Solaris ondersteunt zowel processen als user-level threads en kernel-level threads.
De user-level threads vormen op gebruikersniveau de basisinterface voor parallelle toepassingen,
terwijl kernel-level thrads de entiteiten zijn die kunnen worden gescheduled op een van de
processoren van het systeem. Er zijn ook verschillende systeemfuncties in Solaris die gebouwd
zijn op specifieke kernel-lvel threads zonder aan lichtgewicht processen gekoppeld te zijn. (bv
routines voor interruptafhandeling)
Indien de user-level thread niet gebonden is aan één enkel lichtgewicht proces, dan wordt die
enkel in de actieve toenstand effectief aan een lichtgewicht proces gekoppeld.Wanneer deze
thread de status actief verlaat, wordt de thread die daarna actief wordt gemaakt aan het
vrijgekomen lichtgewichtproces gebonden.
User-level threads verlaten de status actief door:

Een primitieve voor synchronisatie aan te roepen, hierdoor gaat de thread in slaapstand
tot wanneer de voorwaarde voor synchronisatie is voldaan.
 Gestopt te worden door een ander actieve user-level thread (of door zichzelf)
 Preëmptief onderbroken te worden wanneer een andere thread met hogere prioriteit
uitvoerbaar wordt.
 Zichzelf preëmptief te onderbreken en de controle over te dragen aan een andere
(uitvoerbare)thread met dezelfde prioriteit.
In de toestand actief van de user-level thread kan ook het corresponderende lichtgewicht proces
verschillende toestanden aannemen. (zie tweede deel figuur)
De actieve user-level thread zal enkel worden uitgevoerd als zijn bijhorend lichtgewicht proces
ook in de status actief staat. Voert die thread een blokkerende handel uit, blijft die thread actief
maar is het het lichtgewicht proces dat blokkeert.
1.6.
Vraag A6
Gelijktijdigheid: algoritmes van Dekker en Peterson
a) Construeer het algoritme van Dekker: behandel hierbij de opeenvolgende pogingen, en hun
tekortkomingen.
b) Construeer, vertrekkend van het algoritme van Dekker, het algoritme van Peterson, voor twee
gelijktijdige processen.
c) Toon stapsgewijs aan hoe het algoritme van Peterson kan aangepast worden om in wederzijdse
uitsluiting door meer dan twee gelijktijdige processen te voorzien. Analyzeer de werking van dit
algoritme.
a)
Eerste poging
Proces P0
Proces P1
…
…
while(1){
while(1){
while(beurt != 0){
while(beurt != 1){
}
}
kritieke_sectie();
kritieke_sectie();
beurt = 1;
beurt = 0;
niet_kritieke_sectie();
niet_kritieke_sectie();
}
}
 Wederzijdse uitsluiting voor één gedeelde globale variabele (beurt)
 Principe van co-routine: ontworpen om onderling de besturing van uitvoering te kunnen
uitwisselen.
o  processen kunnen uitsluitend om beurt hun kritieke sectie gebruiken (tempo dus
bepaald door langzaamste proces)
o  een proces wordt permanent geblokkeerd, indien het ander proces zou crashen
vooraleer de beurtvlag gewijzigd wordt
o  tegengehouden proces doet niets productief totdat het toestemming krijgt zijn
kritieke sectie uit te voeren (verbruikt processortijd tijdens wachten)
 Voortdurend testen tot deze variabele een welbepaalde variabele krijgt: ‘actief wachten’
Tweede poging
Proces P0
Proces P1
…
…
while(1){
while(1){
while(vlag[1] != 0){
while(vlag[0] != 0){
}
}
vlag[0] = 1;
vlag[1] = 1;
kritieke_sectie();
kritieke_sectie();
vlag[0] = 0;
vlag[1] = 0;
niet_kritieke_sectie();
niet_kritieke_sectie();
}
}
 globale variabele (beurt) vervangen door een tabel van globale variabelen (vlag)
 elk proces heeft zijn eigen vlag en kan de vlag van een ander proces controleren maar niet
wijzigen (vlag: in kritieke sectie of niet)
  een proces wordt permanent geblokkeerd, indien het ander proces zou crashen in zijn
kritieke sectie
  niet onafhankelijk van relatieve snelheden van uitvoering van processen (tegelijkertijd
vaststellen dat het ander proces zich niet in kritieke sectie bevindt: geen wederzijdse
uitsluiting)
Derde poging
Proces P0
Proces P1
…
…
while(1){
while(1){
vlag[0] = 1;
vlag[1] = 1
while(vlag[1] != 0){
while(vlag[0] != 0){
}
}
kritieke_sectie();
kritieke_sectie();
vlag[0] = 0;
vlag[1] = 0;
niet_kritieke_sectie();
niet_kritieke_sectie();
}
}
 tabel van globale variabelen (vlag): vlag wordt gewijzigd vooraleer de vlag van het ander
proces wordt getest.
  het proces blijft geblokkeerd indien het ander proces zou crashen in zijn kritieke sectie.
  niet onafhankelijk van relatieve snelheden van uitvoering van processen
o De beslissing om de kritieke sectie te mogen betreden wordt hierdoor continu
uitgesteld (actief wachten op een gebeurtenis die nooit vervuld wordt: livelock
situatie (vorm van deadlock waarbij de CPU voortdurend belast wordt)
Vierde poging
Proces P0
Proces P1
…
…
while(1){
while(1){
vlag[0] = 1
vlag[1] = 1;
while(vlag[1] != 0){
while(vlag[0] != 0){
vlag[0] = 0;
vlag[1] = 0;
sleep(random());
sleep(random());
vlag[0] = 1;
vlag[1] = 1;
}
}
kritieke_sectie();
kritieke_sectie();
vlag[0] = 0;
vlag[1] = 0;
niet_kritieke_sectie();
niet_kritieke_sectie();
}
}
 elk proces stelt zijn vlag opnieuw in ten gunste van het ander proces
  elke verandering van de relatieve snelheid van de twee processen doorbreekt de
deadlocksituatie: kans op deadlock geminimaliseerd maar niet uitgesloten
Uiteindelijke oplossing
Proces P0
Proces P1
…
…
while(1){
while(1){
vlag[0] = 1
vlag[1] = 1;
while(vlag[1] != 0){
while(vlag[0] != 0){
if (beurt == 1){
if (beurt == 0){
vlag[0] = 0;
vlag[1] = 0;
while(beurt == 1){
while(beurt == 0){
sleep(random());
sleep(random());
}
}
vlag[0] = 1;
vlag[1] = 1;
}
}
}
}
kritieke_sectie();
kritieke_sectie();
vlag[0] = 0;
vlag[1] = 0;
niet_kritieke_sectie();
niet_kritieke_sectie();
}
}
 volgorde aanbrengen in de activiteiten van de twee processen (probleem van wederzijdse
beleefdheid te voorkomen)
 globale variabele beurt geeft aan in welke volgorde de processen het recht hebben hun
kritieke sectie te mogen binnengaan
  moeilijk uitbreidbaar tot meer dan twee processen
b)
Proces P0
Proces P1
…
…
while(1){
while(1){
vlag[0] = 1
vlag[1] = 1;
beurt = 1;
beurt = 0;
while(vlag[1] != 0 && beurt == 1){
while(vlag[0] != 0 && beurt == 0){
sleep(random());
sleep(random());
}
}
kritieke_sectie();
kritieke_sectie();
vlag[0] = 0;
vlag[1] = 0;
niet_kritieke_sectie();
niet_kritieke_sectie();
}
}
 vereenvoudiging van algoritme van Peterson.
  wederzijdse uitsluiting behouden: proces kan zijn kritieke sectie niet uitvoeren indien de
vlag van het ander proces is gezet
  niet mogelijk dat beide processen tegelijkertijd in de while lus geblokkeerd geraken
o beide processen hebben gemeld geïnteresseerd te zijn in het uitvoeren van de
kritieke sectie
o beide hebben de variabele beurt gezet (diegene die dat als laatste gedaan heeft,
verleent voorrang aan het ander proces)
  proces kan ook niet de kritieke sectie monopoliseren: het laatste proces dat de kritieke
sectie uitgevoerd heeft, verleent steeds voorrang aan het ander proces indien dit zou staan
te wachten
c)
 versie van twee processen aanpassen zodat beide processen dezelfde code gebruiken
n=2
while(1){
// Proces i (0 ≤ i < n)
j = 1;
vlag[i] = j;
last[j] = i;
for(k = 0; k < n; k++){
if(k == i) continue;
while(vlag[k] >= vlag[i] && last[j] == i){
sleep(random());
}
}
kritieke_sectie();
vlag[i] = 0;
niet_kritieke_sectie();
}
o
één enkele wachtrij: processen die hebben aangegeven de kritieke sectie te willen
betreden komen in de wachtrij terecht.
 vlag[i]: geeft aan of proces in wachtrij is opgenomen
 last[j] : proces dat als laatste toegevoegd is aan de wachtrij (vroeger beurt)
o elk proces dat de kritieke sectie wil betreden moet zijn positie in de wachtrij
vergelijken met de positie van het enige andere proces.
o eerste element in de wachtrij: proces dat de kritieke sectie mag betreden of er zich
nog in bevindt. Proces is eerste element in wachtrij als:
 een ander proces het laatste in de wachtrij is
 geen enkel ander proces zich in de wachtrij bevindt
 uitbreid naar een willekeurig aantal (n) concurrerende processen:
while(1){
// Proces i (0 ≤ i < n)
for(j = 1; j < n; j++){
vlag[i] = j;
last[j] = i;
for(k = 0; k < n; k++){
if(k == i) continue;
while(vlag[k] >= vlag[i] && last[j] == i){
sleep(random());
}
}
kritieke_sectie();
vlag[i] = 0;
niet_kritieke_sectie();
}
o
variabele j laten gaan van 1 tot n: n-1
 n-1 opeenvolgende wachtrijen: niveau aangegeven door j
 processen die aangegeven hebben de kritieke sectie te willen betreden: in
wachtrij 1
 eerste element van wachtrij op hoogste niveau (n-1) mag kritieke sectie
betreden of bevindt er zich in.
 Vlag[i]: geeft voor elk proces aan in welke wachtrij het zich bevindt






Last[j]: geeft voor elke wachtrij j aan welk proces als laatste de wachtrij is
binnengegaan
Een proces mag de wachtrij van een bepaald niveau j verlaten (indien in
eerste wachtrij: kritieke sectie uitvoeren) indien:
 Een ander proces het laatste in de wachtrij is
 Geen enkel ander proces zich in de wachtrij zelf of in één van de
wachtrijen van de hogere niveaus bevindt
 waarborgt wederzijdse uitsluiting
 vermijdt livelocks en deadlocks
 vermijdt uitstel van onbepaalde duur
 geen garantie dat de processen in volgorde van aanvraag de kritieke sectie
kunnen betreden
2. Reeks B
2.1.
Vraag B1
Gelijktijdigheid: softwarebenaderingen voor wederzijdse uitsluiting
a) Construeer het algoritme van Eisenberg & McGuire. Doe dit stapsgewijs, waarbij je de
bedoeling van elke regel verduidelijkt.
b) Construeer het algoritme van Lamport. Doe dit stapsgewijs, waarbij je de bedoeling van elke
regel verduidelijkt.
c) Waarom zijn softwarebenaderingen in de praktijk niet de aangewezen technieken voor
wederzijdse uitsluiting ?
d) Welke andere benaderingen zijn mogelijk ? Beschrijf kort hoe wederzijdse uitsluiting met
behulp van deze benaderingen kan verzekerd worden.
a)
while(1){
// Proces i (0 ≤ i < n)
repeat{
// (4)
vlag[i] = -1;
for(j = beurt ; j != i ; j = (j+1)%n){
// (1)
while(vlag[j] != 0){
sleep(random());
}
vlag[i] = 1;
for (j = 0 ; j < n ; j++){
// (2)
if (vlag[j] == 1 && j != i)
break;
}
if (j == n && vlag[beurt] == 0)
// (6)
beurt = i;
// (3)
} until (j == n && beurt == i)
// (6)
kritieke_sectie();
j = (j+1)%n;
// (5)
while (vlag[j] == 0)
// (5)
j = (j+1)%n;
// (5)
beurt = j;
// (5)
vlag[i] = 0;
niet_kritieke_sectie();
}
De concurrerende processen worden cyclisch genummerd, met als doel de processen in volgorde de
kans te geven de kritieke sectie te gebruiken. Het tabelelement vlag[i] geeft voor proces i aan of het
proces niet in de kritieke sectie geïnteresseerd is (waarde 0), moet wachten om de kritieke sectie te
mogen betreden (waarde -1) of er toelating voor heeft (waarde 1).
De identificatie van het proces dat van de kritieke sectie gebruik maakt of dit als laatste heeft gedaan
wordt bijgehouden door de variabele beurt. Hoe dichter de processen zich in de cyclische rij
bevinden ten opzichte van dit proces, hoe groter de prioriteit is waarmee ze behandeld zullen
worden.
Een proces dat in de kritieke sectie geïnteresseerd is blijft in lus (1) wachten zolang een van de
processen met een hogere prioriteit de kritieke sectie wil of mag binnengaan, of er effectief gebruik
van maakt. Afhankelijk van de opgetreden proceswisselingen kan het zijn dat er meerdere processen
de illusie krijgen dat ze de kritieke sectie mogen betreden. Dit wordt gecontroleerd in lus (2). Als dit
niet het geval is mag het als enige proces doorgaan na aanpassing van de variabele beurt. Indien
meerdere processen de toelating werd gegeven, dan moet elk van deze processen de volledige
procedure herhalen (lus (4) ). Na deze herhaling zullen de minder prioritaire processen opnieuw in
lus (1) opgehouden worden tot het meest prioritaire proces de kritieke sectie verlaat. Op het
ogenblik dat een proces van de kritieke sectie gebruik maakt, is het met zekerheid het enige proces
waarvan het vlag element de waarde 1 heeft.
De optimalisatie (5) in het exit protocol, die men soms toepast, laat elk proces, na beëindiging van de
kritieke sectie, zelf op zoek gaan naar de beste kandidaat voor de volgende cyclus. Indien die niet
gevonden wordt blijft de beurt variabele ongewijzigd. Een 2e optimalisatie, aangeduid in het vet bij
(6) geeft het beurt proces een laatste kans om (eventueel opnieuw) als eerste van de kritieke sectie
gebruik te maken, ook al werd de intentie hiervoor laattijdig kenbaar gemaakt.
b)
while(1){
// Proces i (0 ≤ i < n)
vlag[i] = 1;
ticket[i] = ++nummer;
// (1)
vlag[i] = 0;
// (4)
for(j = 0 ; j <n ; j++){
if(j == i)
continue;
while(vlag[j] != 0)
sleep(random());
// (2)
while(ticket[j] != 0 && ticket[j] < ticket[i])
sleep(random());
// (5)
if(ticket[j] == ticket[i] && j < i)
// (3)
while(ticket[j] == ticket[i])
sleep(random());
}
kritieke_sectie();
ticket[i] = 0;
niet_kritieke_sectie();
}
Elk process I dat in de kritieke sectie geinteresseerd is, verhoogt het volgnummer, en kent zichzelf
een kopie ervan toe (zie (1)), in het tabelelement ticket [i]. Het volgnummer van het proces wordt
pas gewist na het verlaten van de kritieke sectie. Zolang er processen in het systeem zijn met een
kleiner volgnummer, moet het proces blijven wachten (lus (2)). Vandaar ook de merkwaardige naam
het bakkerij algoritme. Afhankelijk van de optredende proceswisselingen, kan hetzelfde volgnummer
ten onrechte toegekend worden aan meerdere processen. Om deze situatie op te vangen, is er een
afspraak nodig om de dan geldende volgorde vast te leggen. In (3) gebeurt dit, bij wijze van
voorbeeld, op basis van procesidentificatie.
Het verhogen van het volgnummer, en het nemen van een locale kopie ervan vereist een aantal
machine instructies, waarbij ondermeer geheugenelementen van en naar registers gekopieerd
worden. Dankzij de processorinformatie in het PCB blok heeft elk proces trouwens de illusie van een
individuele set processorregisters. Indien precies tijdens verwerking van (1) een proceswisseling
uitgevoerd wordt, dan bestaat de mogelijkheid dat opeenvolgende nieuwe aanvragen beschikken
over foutieve volgnummerinformatie van het onderbroken proces. zo kan zelf aan een proces met
hoger volgnummer, dan dit van het onderbroken proces, toegang verleend worden tot de kritieke
sectie. Indien het onderbroken proces dan uiteindelijk geactiveerd wordt, krijgt ook dit de toelating
tot de kritieke sectie, en is van wederzijdse uitsluiting geen sprake meer. Om dergelijk probleem te
vermijden, worden nieuwe aanvragen opgehouden (lus (5)) zolang een vorige aanvraag de
berekening van zijn volgnummer niet volledig afgewerkt heeft ( (4) ).
c)




ze laten de verantwoordelijkheid over aan de processen
o in alle oplossingen met kritieke secties moeten alle processen zich houden aan de
uitgewerkte regels van het protocol
o als één proces vals speelt: mislukt wederzijdse uitsluiting
o programmafouten moeilijk op te sporen (resultaten meestal niet reproduceerbaar
door geen strikte volgorde van gebeurtenissen)
hoge overhead door principe ‘actief wachten’
o er zouden bewerkingen moeten zijn die blokkeren in plaats van processortijd te
verspillen wanneer de toegang tot een kritieke sectie ontzegt wordt
deadlocks door ‘actief wachten’: stel dat P0 gedurende zijn kritieke sectie onderbroken
wordt door P1 (dat in een actieve wachtlus zit EN een hogere prioriteit heeft als P0) dan zou
P1 niet meer geactiveerd kunnen worden.
Uithongering niet uitgesloten: indien een proces de kritieke sectie verlaat, wordt er
willekeurig een ander proces geselecteerd: een proces zou de toegang oneindig lang ontzegd
kunnen worden
d)

hardwarebenaderingen
o uitschakelen interupts
 tijdens uitvoeren kritieke sectie: tijdelijk uitschakelen interrupts (geen
proceswisseling mogelijk): alleen mogelijk als alle processen dit doen (uit: CLI
en aan: STI instructie op Intel)
  geeft gebruikersprocessen de macht het systeem te bevriezen
  werkt niet voor meerdere processoren
o atomaire instructies:
 voor meerdere processoren
 minimum twee acties kunnen uitvoeren die niet onderbroken kunnen
worden): geen enkele andere processor mag de geheugenlocatie kunnen
gebruiken, vooraleer de instructie klaar is
 veel overhead: bij wijziging eigen cache op processor moet deze op de
andere cache ook gemerkt worden (cache invalidation)
 testset instructies
 test de waarde van het één enkel argument (bezet)
o 0: vervangen door 1 en 1 als resultaat geven
o Niet 0: niet wijzigen en 0 als resultaat geven
 Via testset instructie waarde controleren; in eerste geval kan dit
proces zijn kritieke sectie uitvoeren
  Alle andere processen gaan over tot ‘actief wachten’
 Atomaire instructie: uittesten van waarde van een geheugenlocatie
en het manipuleren ervan
 exchange instructies


atomaire instructie: wisselen van inhoud van twee geheugenlocaties,
waarvan de adressen als argumenten vermeld zijn
 gedeelde globale variabele bezet ; lokale variabelen vlagi
(geïnitialiseerd op 1: geen enkel proces vooralsnog de kritieke sectie
mag benutten)
 bezet + ∑ vlagi = n
 vlag met waarde 0 geeft aan welk proces in zijn kritieke sectie
bevindt (alleen als bezet gelijk is aan 0: bij uitvoeren zet het bezet
gelijk aan 1)
 verlaat een proces zijn kritieke sectie: bezet terug op 0, zijn eigen
vlag op 1.
  wederzijdse uitsluiting
  voor een willekeurig aantal processen
primitieven in het operating systeem
o signalen
 ter ondersteuning van wederzijdse uitsluiting en synchronisatie
 koppel van twee primitieven
 slaap() systeemaanroep: het aanroepende proces wordt geblokkeerd
tot wanneer een willekeurig ander proces het wekt met behulp van
de tweede systeemaanroep.
 wek(proces)
 algoritme zie cursus p 71
 deze systeemaanroepen worden geïmplementeerd als signalen: drie
systeemaanroepen ter beschikking gesteld:
 kill(proces,signaalcode): een proces kan een ander proces
asynchroon melden dat er een specifieke gebeurtenis is opgetreden
(31 verschillende gebeurtenis in POSIX-compatibele implementatie)
 signal(signaalcode,functie):
o processen kunnen hiermee signalen registreren, waarmee ze
aangeven wat er gedaan moet worden als een bepaald
signaal gemeld wordt.
o Alle threads ontvangen hetzelfde signaal: thread kan een
signaal met een bepaalde code maskeren (alleen afgeleverd
aan threads die ze niet gemaskeerd hebben)
 Pause(): proces stopt met uitvoering tot het een willekeurig nietgenegeerd signaal ontvangt.
o Vermijden van actief wachten
o Sigsuspend() en sigwait(): wachten tot een specifiek signaal
ontvangen wordt
o sequencers en eventtellers
 ticketsysteem
 twee types objecten aanbieden: sequencers en eventtellers
o sequencer: incrementele teller (werking niet verstoord door
proceswisselingen)
o eventteller: wachtrij van geblokkeerde processen die op een
bepaalde gebeurtenis wachten en vermijdt hierbij dat het
proces actief moet wachten
 aantal systeemaanroepen om deze objecten te manipuleren
 operaties
 await(E,x): blokkeert de thread tot de eventteller >= waarde x




o
advance(E): incrementeert de eventteller met 1, brengt eventuele
processen uit de wachtrij waarvoor de voorwaarde eventteller >= x
nu wel vervuld zou zijn, over naar gerede toestand
ticket(S): geeft de huidige waarde terug van de sequencer, en
verhoogt nadien de waarde zodat bij een volgende operatie read of
ticket een hogere waarde wordt teruggegeven.
read(S/E): geeft de huidige waarde terug van een eventteller of van
een sequencer.
algoritme zie cursus p 73 (eerste algoritme)
semaforen
 variabele (semafoor) gebruiken die het aantal weksignalen voor toekomstig
gebruik kan tellen (oplossing raceprobleem)
 houdt net als eventteller een geheel getal en een wachtrij van geblokkeerde
processen bij
 postieve waarde: één of meer weksignalen staan te wachten op
verwerking
 negatieve waarde: aantal elementen in de corresponderen wachtrij
van geblokkeerde processen
 slaap() en wek() zijn nu neer() en op()
 enkel door primitieve operaties aangesproken worden
 operatie neer() op een semafoor verlaagt de waarde van de
semafoor met 1
o indien waarde negatief: proces opgenomen in wachtrij van
geblokkeerde processen
o inspecteren, veranderen en eventueel blokkeren: atomaire
instructie
 operatie op() verhoogt de waarde met 1
o één proces uit de wachtrij gekozen en wordt deze uit zijn
geblokkeerde neer() verlost
o verhogen van semafoorwaarde en wekken van één proces:
atomaire instructie
 verschillen met sequencers en eventtellers waardoor de eenvoud ervan niet
altijd benaderd kan worden
 op() verwijdert slechts één proces uit de wachtrij  advance() een
selectieve deelverzameling
 semaforen: niet vastgelegd in welke volgorde de processen uit de
wachtrij verwijderd worden  await() systeemaanroep volledige
controle over sortering wachtrij
o priority inversion: processen met lagere prioriteit houden
processen met hogere prioriteit op
o FIFO queue bij systemen zonder prioriteitsniveaus
 Geen manier om de huidige waarde van een semafoor te weten te
komen  read() systeemaanroep
 tellende semaforen
 kunnen willekeurige waarde  0 aannemen
 gebruikt voor synchronisatie
 Linux: geïmplementeerd door kernel semaphores
o op() en neer(): up() en down() systeemaanroepen
 Solaris:
o sema_init() en sema_destroy()
o neer(): sema_wait() en sema_trylock()

o op(): sema_post()
binaire semaforen (mutexen)
 kunnen enkel 0 of 1 zijn
 gebruikt voor wederzijdse uitsluiting
 Linux: geïmplementeerd door spin locks
o spin_unlock, spin_lock en spin_trylock macro’s
 Solaris:
o mutex_init() en mutex_destroy()
o neer(): mutex_wait() en mutex_trylock()
o op(): mutex_post()
2.2.
Vraag B2
Gelijktijdigheid: hardwarebenaderingen wederzijdse uitsluiting / slapende kapper probleem
a) Geef drie alternatieve hardwarebenaderingen voor wederzijdse uitsluiting, en hun voor- en
nadelen. Verduidelijk de gebruikte concepten (ook al worden deze in een ander hoofdstuk in de
cursus behandeld).
b) Waarom zijn hardwarebenaderingen in de praktijk voor gebruikersprocessen niet de
aangewezen technieken om wederzijdse uitsluiting te realiseren ? Worden de hardwarebenaderingen voor wederzijdse uitsluitingen dan nooit aangewend ?
c) Hoe kan vermeden worden dat gebruikersprocessen rechtstreeks een beroep doen op
hardwarebenaderingen ?
d) Behandel in detail het probleem van de slapende kapper. Waarvoor staat dit probleem model ?
Construeer de oplossing (op basis van semaforen) stapsgewijs (± 5 stappen), waarbij je de
bedoeling van elke regel (in het bijzonder van de operaties op semaforen) verduidelijkt. Waarom
wordt het probleem van de slapende kapper ook soms het probleem van de onrechtvaardige
kapper genoemd
a) zie B1 puntje d (hardwarebenaderingen)
b) zie B2 puntje c




OS kan beslissen om wachtlussen te vervangen door blokkerende threads
Spinlock: threadwisselingen belastend: OS kiest om gedurende korte periodes toch actief
wachten toe te passen
Delayed lock: indien spin lock toch langer blijkt te duren dan verwacht: toch overgegaan tot
blokkeren
Adaptive locks: afhankelijk van de systeembelasting resulteren in threadwisselingen of
spinlocks met eventuele uitgestelde threadwisseling

ze worden voorzien omdat het besturingssysteem er primitieven (in de vorm van
systeemaanroepen) voor wederzijdse uitsluiting en synchronisatie op zou kunnen baseren.
 Ze zijn eenvoudig en makkelijk uitbreidbaar: meerdere kritieke secties kunnen ondersteund
worden, door elke kritieke sectie te definiëren met een eigen variabele
 Corresponderende instructies zijn geprivilegieerd zodat ze enkel rechtstreeks vanuit
kernelmodus of onrechtstreeks via systeemaanroepen kunnen uitgevoerd worden.
c) zie B1 puntje d (primitieven in het operating systeem)
d)

servertoepassing die slechts één aanvraag tegelijkertijd kan behandelen, en een wachtrij met
beperkte grootte in stand houdt voor volgende aanvragen
1) Toestand kapper bijgehouden door binaire semafoor kappers, zodat klanten kunnen blokkeren
indien kapper niet beschikbaar is.
2) Aantal wachtende klanten bijgehouden door variabele aantal en semafoor klanten die dezelfde
waarde hebben.
3) Variabele aantal bewaakt door binaire semafoor w_u om wederzijdse uitsluiting te garanderen.
4) Kapper blokkeert de semafoor klanten tot er iemand binnenkomt.
5) Indien de binnenkomende klant mag wachten voert hij een op() instructie uit op de semafoor
klanten om de kapper eventueel te wekken, vooraleer zelf te blokkeren op de semafoor kappers.

STOELEN = 8;
void geknipt();
semafoor w_u = 1;
semafoor klanten = 0;
void klant(void){
semafoor kappers = 0;
neer(&w_u);
aantal = 0;
if(aantal < STOELEN){
void kapper() {
aantal++;
while(1){
op(&klanten);
neer(&klanten);
op(&w_u);
neer(&w_u);
neer(&kappers);
aantal--;
geknipt;
op(&kappers);
else{
op(&w_u);
op(&w_u);
knippen();
)
}
}
}
Onrechtvaardige kapper: op(): één proces uit de wachtrij gekozen en wordt deze uit zijn
geblokkeerde neer() verlost , dus klanten worden niet in volgorde afgehandeld.
2.3.
Vraag B3
Gelijktijdigheid: alternatieve oplossingen voor het probleem van de eindige buffer
a) Formuleer het probleem van de eindige buffer (producenten en consumenten) ? Welke
problemen van gelijktijdige processen moeten hier opgelost worden ? Toon aan dat het probleem
niet correct kan opgelost worden door gebruik te maken van eenvoudige besturingssysteem
primitieven zoals signalen.
b) Geef correcte oplossingen voor het probleem van de eindige buffer:
sequencers en eventtellers,
semaforen,
monitors,
doorgeven van berichten.
Construeer de oplossingen telkens stapsgewijs, waarbij je de bedoeling van elke regel (in het
bijzonder van de primitieve operaties) verduidelijkt. Hoe komt het dat deze verschillende
technieken allen in staat zijn om een basisoplossing van een dergelijk probleem op te leveren ?
c) Wat zijn sequencers en eventtellers, en welke operaties zijn er aan geassocieerd ? Waarom is
een oplossing op basis van sequencers en eventtellers, niet alleen voor het probleem van de
eindige buffer maar ook algemeen, superieur ten opzichte van de andere oplossingen ? Welke
problemen (beschrijf deze !) kunnen hierbij vermeden worden ?
a)



twee parallelle processen gebruiken gemeenschappelijk een buffer met vaste grootte N, als
een circulaire opslag.
o 1e proces (producent) plaatst informatie in de buffer
o 2e proces (consument) haalt die informatie eruit
o Twee cursors geven de indices aan van het eerste vrije element in de buffer en het
eerste element dat nog verwerkt moet worden
Of: verzameling van N elementen
o verdeeld in twee groepen (een groep ingevulde elementen, een groep vrije
elementen)
o waarbij de beide processen elementen van de ene groep overbrengen naar de
andere.
o De producent en consument processen werken aan individueel tempo onafhankelijk
van elkaar: opslaan en opvragen niet strikt afwisselend
Problemen:
o Wederzijdse uitsluiting van de volledige circulaire buffer zou hier tot een veel te
restrictieve oplossing leiden
o Consument mag geen leeg element inlezen
o Producent mag geen data opslaan als de buffer vol is
o Synchronisatie
 Dwingend opleggen van een zodanige volgorde van gebeurtenissen die door
concurrente processen uitgevoerd worden, dat de integriteit van de
gegevens kan gegarandeerd worden
 Synchronisatie tussen de processen moet verzekeren dat cruciale operaties
in de juiste volgorde uitgevoerd worden

Signalen:
Proces producent
Proces consument
…
…
while(1){
while(1){
produceer(&p)
if(aantal == 0) slaap();
if(aantal == N) slaap();
c = b[out++]
b[in++] = p;
out %= N
in %= N;
aantal--;
aantal++;
if (aantal + 1 == N) wek(producent);
if (aantal == 1) wek(concument);
consumeer(c);
}
}
o Wordt verstoord door een raceprobleem: omdat de toegang tot de gedeelde globale
variabele niet afgeschermd is
 Indien consument proces geblokkeerd wordt nadat het getest heeft op
aantal==0, zal hij zichzelf niet meer doen inslapen. Het producent proces
ontwaakt, vult de buffer, wekt de consument (maar de consument gaat
direct slapen) en de producent gaat zelf slapen. Ze zijn nu alle twee aan het
slapen.

sequencers van eventtellers
Op basis van 2 eventtellers IN(geeft cumulatief aantal elementen weer dat in de buffer werd
opgeslagen) en OUT (houdt het totaal aantal verwerkte elementen bij)
Proces producent
Proces consument
in = 0;
out = 0;
while(1){
while(1){
produceer(&p)
await(IN, out+1);
await(OUT, in + 1 – N);
c = b[out%N];
b[in%N] = p;
out++;
in++;
advance(OUT);
advance(IN);
consumeer(c);
}
}
semaforen
Op basis van 3 semaforen: gevuld (aantal gevulde elementen in de buffer, geïnitialiseerd op
0), leeg (aantal lege elementen in de buffer, geïnitialiseerd op N) en binaire semafoor w_u
(geïnitialiseerd op 1, niet nodig als er maar 1 consument en producent zijn).
Proces producenti
Proces consumenti
…
…
while(1){
while(1){
produceer(&p);
neer(&gevuld);
neer(&leeg);
neer(&w_u);
neer(&w_u);
c = b[out++];
b[in++] = p;
out %= N;
in %= N;
op(&w_u);
op(&w_u);
op(&leeg);
op(&gevuld);
consumeer(c);
}
}
b)


monitors
Proces producent
…
while(1){
produceer(&p);
pc_monitor.plaats();
}
plaats(){
if(aantal == k) wait(vol);
b[in++] = p;
in %= k;
aantal++;
if(aantal == 1) signal(leeg);
}


doorgeven van berichten
Proces producent
…
…
while(1){
produceer(&p);
receive(consument);
…
send(consument, &p);
}
Proces consument
…
while(1){
pc_monitor.neem();
consumeer();
}
Pc_monitor
neem(){
if(aantal == 0) wait(leeg);
c = b[out++];
out %= k;
aantal--;
if(aantal + 1 == k) signal(vol);
}
Proces consument
…
for(i = 0 ; i < k ; i++) send(producent);
while(1){
receive(consument, &c);
…
send(producent);
consumeer(c);
}
Semaforen gebruiken atomaire instructies, die een ondeelbaar geheel vormen. Tijdens het
uitvoeren van deze instructies kan het proces niet onderbroken worden.
o Monitors werken intern met semaforen
o Doorgeven van berichten is volkomen equivalent aan gebruik van
semaforen/monitoren
o Oplossing raceprobleem: gebruik van een variabele die in staat is om het aantal
weksignalen voor toekomstig gebruik te tellen
o Sequencers en eventtellers: verstoring van volgorde van uitvoering wordt hier
vermeden door een incrementele teller aan te bieden (die slechts via
systeemaanroepen gemanipuleerd kunnen worden): in de praktijk nooit toegepast in
OS’s: semaforen.
c)




ticketsysteem
twee types objecten aanbieden: sequencers en eventtellers
o sequencer: incrementele teller (werking niet verstoord door proceswisselingen)
o eventteller: wachtrij van geblokkeerde processen die op een bepaalde gebeurtenis
wachten en vermijdt hierbij dat het proces actief moet wachten
aantal systeemaanroepen om deze objecten te manipuleren
operaties
o await(E,x): blokkeert de thread tot de eventteller >= waarde x
o advance(E): incrementeert de eventteller met 1, brengt eventuele processen uit de
wachtrij waarvoor de voorwaarde eventteller >= x nu wel vervuld zou zijn, over naar
gerede toestand
o



ticket(S): geeft de huidige waarde terug van de sequencer, en verhoogt nadien de
waarde zodat bij een volgende operatie read of ticket een hogere waarde wordt
teruggegeven.
o read(S/E): geeft de huidige waarde terug van een eventteller of van een sequencer.
algoritme zie cursus p 73 (eerste algoritme)
verschillen met sequencers en eventtellers waardoor de eenvoud ervan niet altijd benaderd kan
worden
o op() verwijdert slechts één proces uit de wachtrij  advance() een selectieve
deelverzameling
o semaforen: niet vastgelegd in welke volgorde de processen uit de wachtrij
verwijderd worden  await() systeemaanroep volledige controle over sortering
wachtrij
 priority inversion: processen met lagere prioriteit houden processen met
hogere prioriteit niet op
 FIFO queue bij systemen zonder prioriteitsniveaus
o Geen manier om de huidige waarde van een semafoor te weten te komen  read()
systeemaanroep
‘actief wachten’ probleem wordt vermeden door wachtrij van geblokkeerde processen
2.4.
Vraag B4
Gelijktijdigheid: het probleem van de lezers en schrijvers.
a) Formuleer het probleem van de lezers en schrijvers. Waarvoor staat dit probleem model ?
b) Construeer de oplossing (op basis van semaforen) stapsgewijs (± 10 stappen), waarbij je de
bedoeling van elke regel (in het bijzonder van de operaties op semaforen) verduidelijkt. Zorg
eerst voor een oplossing waarbij lezer processen voorrang hebben op schrijver processen. Wijzig
daarna deze oplossing zodat schrijver processen voorrang krijgen. Waarom is dit noodzakelijk ?
a) Model voor toegang tot een databank, met een groot aantal processen die proberen erin te lezen
en te schrijven. Het is aanvaardbaar dat er meer dan één proces tegelijkertijd in de databank leest,
maar als er één proces in de databank aan het schrijven is, mag geen enkel ander proces toegang
krijgen.
b)
1) Specifieke toegang wederzijds uitgesloten door binaire semafoor bd.
2) Aantal lezers wordt bijgehouden door een globale variabele aantal_l, die voor wederzijdse
uitsluiting beschermd wordt door andere binaire semafoor wu_aantal_l.
3) We maken gebruik van turnstile constructies waar een eerste wachtende proces staat
geblokkeerd op de inwendige semafoor, terwijl alle andere wachtende processen geblokkeerd staan
op een uitwendige semafoor.
4) Met een eerste turnstile legt men op dat het eerste geblokkeerde proces (lezer) ook als eerste
terug wordt geactiveerd
5) Proberen voorrang geven aan schrijver processen.
6) Globale variabele aantal_s houdt aantal schrijvers bij, beschermd voor wederzijdse uitsluiting door
binaire semafoor wb_aantal_s.
7) Tegenhouden van lezers indien tenminste 1 schrijver toegang wil hebben tot het gegevensgebied
(mbv een turnstile en semafoor lees)
8) Invoeren van andere turnstile constructie met semafoor queue zorgt ervoor dat schrijvers slechts
met 1 enkele lezer proces moeten concurreren. Slechts 1 lezer kan wachten op de lees semafoor
terwijl de anderen moeten wachten op de queue semafoor vooraleer ze kunnen wachten op lees.
int aantal_l = 0 aantal_s = 0;
semafoor wu_aantal_l = 1, wu_aantal_s = 1;
semafoor db = 1, lees = 1, queue = 1;
void schrijver(void){
while(1){
produceer_data();
neer(&wu_aantal_s);
aantal_s++;
if (aantal_s == 1) neer(&lees)
op(&wu_aantal_s);
neer(&db);
schrijf_db();
op(&db);
neer(&wu_aantal_s);
aantal_s--;
if(aantal_s == 0) op(&lees);
op(&wu_aantal_s);
}}
void lezer(void){
while(1){
neer(&queue);
neer(&lees);
neer(&wu_aantal_l);
aantal_l++;
if(aantal_l == 1) neer(&db);
op(&wu_aantal_l);
op(&lees);
op(&queue);
lees(&db);
neer&wu_aantal_l();
aantal_l--;
if(aantal_l==0) op(&db);
op(q&wu_aantal_l);
verwerk_data();
}
}
// (3)
// (2)
// (1)
// (1)
// (2)
// (3)
2.5. Vraag B5
Gelijktijdigheid: semaforen en het probleem van de dining philosophers
a) Waarom worden semaforen ingevoerd ? Wat zijn semaforen, en welke operaties zijn er aan
geassocieerd ? Je hoeft het probleem van de eindige buffer (producenten en consumenten) niet te
behandelen.
b) Welke types semaforen zijn er, en waarvoor zijn deze specifiek bestemd ?
c) In welk opzicht zijn semaforen als elementaire bouwstenen inferieur ten opzichte van
sequencers en eventtellers ? Welke problemen (beschrijf deze !) kunnen bij het gebruik van
semaforen optreden ?
d) Behandel in detail het probleem van de dining philosophers. Waarvoor staat dit probleem
model ? Construeer de oplossing (op basis van semaforen) stapsgewijs (± 5 stappen), waarbij je
de bedoeling van elke regel (in het bijzonder van de operaties op semaforen) verduidelijkt.
a)




variabele (semafoor) gebruiken die het aantal weksignalen voor toekomstig gebruik kan tellen
(oplossing raceprobleem)
houdt net als eventteller een geheel getal en een wachtrij van geblokkeerde processen bij
o postieve waarde: één of meer weksignalen staan te wachten op verwerking
o negatieve waarde: aantal elementen in de corresponderen wachtrij van
geblokkeerde processen
slaap() en wek() zijn nu neer() en op()
enkel door primitieve operaties aangesproken worden
o operatie neer() op een semafoor verlaagt de waarde van de semafoor met 1
 indien waarde negatief: proces opgenomen in wachtrij van geblokkeerde
processen
 inspecteren, veranderen en eventueel blokkeren: atomaire instructie
o operatie op() verhoogt de waarde met 1
 één proces uit de wachtrij gekozen en wordt deze uit zijn geblokkeerde
neer() verlost
 verhogen van semafoorwaarde en wekken van één proces: atomaire
instructie
b)


tellende semaforen
o kunnen willekeurige waarde  0 aannemen
o gebruikt voor synchronisatie
o Linux: geïmplementeerd door kernel semaphores
 op() en neer(): up() en down() systeemaanroepen
o Solaris:
 sema_init() en sema_destroy()
 neer(): sema_wait() en sema_trylock()
 op(): sema_post()
binaire semaforen (mutexen)
o kunnen enkel 0 of 1 zijn
o gebruikt voor wederzijdse uitsluiting
o Linux: geïmplementeerd door spin locks
 spin_unlock, spin_lock en spin_trylock macro’s
o Solaris:
 mutex_init() en mutex_destroy()

neer(): mutex_wait() en mutex_trylock()
c)

verschillen met sequencers en eventtellers waardoor de eenvoud ervan niet altijd benaderd kan
worden
o op() verwijdert slechts één proces uit de wachtrij  advance() een selectieve
deelverzameling
o semaforen: niet vastgelegd in welke volgorde de processen uit de wachtrij
verwijderd worden  await() systeemaanroep volledige controle over sortering
wachtrij
 priority inversion: processen met lagere prioriteit houden processen met
hogere prioriteit op
 FIFO queue bij systemen zonder prioriteitsniveaus
o Geen manier om de huidige waarde van een semafoor te weten te komen  read()
systeemaanroep
d) probleem van de etende filosofen




processen die in concurrentie met elkaar, exclusieve toegang proberen te
krijgen tot een beperkt aantal verschillende bronnen.
Een aantal filosofen, met evenveel vorken, zitten aan een ronde tafel. Om te
eten heeft een filosoof twee vorken nodig. Elke filosoof probeer eerst de
linker en dan de rechter vork te nemen. Heeft de filosoof beide vorken, dan
eet hij een tijdje, legt hierna beide vorken neer om vervolgens na te denken.
Deadlock: indien alle vijf de filosofen tegelijkertijd de linkervork opnemen,
dan kan geen enkele meer de rechtervork krijgen
Verhongering: indien de filosofen gesynchroniseerd dezelfde acties blijven
ondernemen
Oplossing:
1) Geen enkele vork wordt opgenomen zolang ze niet beiden beschikbaar zijn, hiervoor wendt men
tabel aan van binaire semaforen, met één element per filosoof.
2) Een globale tabel toestand houdt bij wie aan het eten is, aan het denken is of de vorken poogt te
nemen.
3) Een filosoof mag enkel naar de etende toestand overgaan als geen van de buurtfilosofen aan het
eten is. Dit realiseert men door op de individuele semafoor van de filosoof een op() operatie uit te
voeren op voorwaarde dat de noodzakelijke voorwaarden zijn vervuld. Onmiddellijk daarna wordt
een neer() operatie uitgevoerd op dezelfde semafoor. Indien de bronnen beschikbaar zijn, heeft deze
opvolging van semafooroperaties geen negatief gevolg: De filosoof kan eten. Als ze niet allemaal
beschikbaar zijn dan wordt enkel de neer() uitgevoerd, en blokkeert de filosoof hierop.
4) Beide buren moeten na het beëindigen van hun eetperiode controleren of ze hun buren kunnen
laten ontsnappen aan hun eventueel geblokkeerde toestand.
5) De binaire semafoor w_u zorgt er voor dat elke manipulatie van de gedeelde tabel toestand als
een kritieke sectie beschouwd wordt.
N = 5;
LINKS = (i-1)%N;
RECHTS = (i+1)%N;
DENKT = 0;
HONGER = 1;
EET = 2;
void test(int i){
if( toestand[i] == HONGER
&& toestand [LINKS] != EET
&& toestand [RECHTS] != EET){
toestand [i] = EET;
op(&vlag[i]);
}
}
void neem_vork(int i){
neer(&w_u);
toestand[i] = HONGER;
test(i);
op(&w_u);
neer(&vlag[i]);
}
void vork_neer(int i){
neer(&w_u);
toestand [i] = DENKT;
test(LINKS);
test(RECHTS);
op(&w_u);
}
void filosoof(int i){
while(1){
denkt();
neem_vork(i);
eet();
vork_neer(i);
}
}
2.6. Vraag B6
Gelijktijdigheid: monitors en het liftalgoritme
a) Waarom worden monitors ingevoerd ? Wat zijn monitors, en welke operaties zijn er aan
geassocieerd ?
b) Welke conventies voor (bepaalde) monitor primitieven zijn er ? Welke conventie volgt de Java
implementatie ? Geef enkele karakteristieken van de Java implementatie.
c) Geef enkele varianten van (bepaalde) monitor primitieven en hun voor- en nadelen.
d) Formuleer het liftalgoritme. Waarvoor (behalve in liften) wordt dit algoritme gebruikt ?
e) Construeer stapsgewijs een implementatie van het liftalgoritme, op basis van monitors. Het is
hierbij de bedoeling dat je de betekenis van elke regel (in het bijzonder van de monitor
primitieven) verduidelijkt.
a) Monitors worden ingevoerd om het correct schrijven van programma's te
vereenvoudigen, wat met semaforen niet even vanzelfsprekend is.
Monitors zijn synchronisatiebouwstenen van een hoger niveau dan semaforen. Ze bestaan
uit een verzameling procedures, variabelen en data-structuren die worden gegroepeerd in
een module.
Gebruikersprocessen kunnen procedures binen de monitor declareren, en deze procedures
aanroepen, maar krijgen geen rechtstreekse toegang tot de interne datastructuren van de
monitor. (conf. OGP)
Het gebruik van semaforen en monitors is volledig equivalent, maar de kans dat er fouten
worden gemaakt door de programmeur is veel kleiner bij monitors.
Ze zijn een eenvoudig instrument voor wederzijdse uitsluiting, aangezien er maar een proces
tegelijk in de monitor kan 'zitten'. De gegevensvariabelen van de monitor zijn namelijk maar
voor één proces tegelijk toegankelijk.
Ze gebruiken de operaties:


wait() = Als het proces zichzelf wil blokkeren wanneer het in de monitor zit.
signal() = notify() = Zo wordt één enkel geblokkeerd proces gewekt.
 dit alles met behulp van conditievariabelen, welke een wachtrij representeert van
processen die geblokeerd zijn op één of andere specifieke voorwaarde. Dezen
verwijzen enkel naar een wachtrij en bevatten geen tellers om weksignalen voor
toekomstig gebruik te verzamelen zoals semaforen. Daarom moet een wait() voor
een signal()/notify() komen, anders gaat het signaal verloren.
b) Conventies
Om te voorkomen dat er na het uitvoeren van een signal() of notify() operatie twee actieve
processen zich tegelijkertijd in de monitor zouden bevinden, zijn er twee mogelijkheden:


Signal-and-exit conventie van Brinch Hansen: Hierbij mag signal() enkel als laatste
opdracht gebruikt worden in een monitorprocedure (door compiler afgedwongen),
waardoor een proces dat een signal() uitvoert onmiddellijk de monitor verlaat.
Notify-and-continue conventie van Hoare: Hier blijft het proces dat de notify()
operatie heeft uitgevoerd in de monitor tot het vrijwillig de monitorprocedure
beïndigt, of zelf een wait() instructie uitvoert.
Welke conventie volgt Java?
Java biedt een mechanisme aan dat zeer goed lijkt op monitors. Elk object in Java is
geassocieerd met een lock. Deze kan worden beschouwd als een individuele monitor, per
object. De methoden van een object negeren de lock, tenzij de methode als synchronized
gedeclareerd is. Het is ook mogelijk om een deel van de code van een methode als
synchronized te merken. Om deze methodes aan te roepen moet men eigenaar van de lock
zijn, een thread kan tegelijkertijd eigenaar zijn van de lock voor verschillende objecten. Bij
aanroep door een niet-eigenaar blokkeert de thread en komt hij in de entryset van het
object.Een lock wordt pas vrijgegeven als de thread de synchronised methode verlaat.
Enkele karakteristieken:

Alternatieven voor notify() (ik denk toch dat dit bedoeld wordt)
In Java wordt ook (en vaak) notifyall() gebruikt. Ipv één bepaalde thread te wekken, wekt
notifyall() alle threads tegelijk.
Voordeel: Zo kunnen de processen zelf bepalen wie van hen de meest geschikte
kandidaat is om te beschikken over de lock. Bijvoorbeeld om rekening te houden met
prioriteiten.
Nadeel: Er zal zo veel overhead veroorzaakt worden, omdat de meeste threads repetitief
zichzelf na activering onmiddellijk opnieuw moeten blokkeren. (= denderende kudde
fenomeen)
d) Het liftalgoritme: formulering en toepassing
Dit algoritme maakt gebruik van priority wait (wanneer aangeroepen wordt een argument
meegegeven dat bepalend is voor de volgorde in de wachtrij: processen met kleinste
prioriteit komen eerst in aanmerking om te verdwijnen)
In de lift zijn 2 aanvragen mogelijk: oproepen(extern) en aanvragen(intern) om naar een
verdieping gebracht te worden. Om de verplaatsing van de lift te optimaliseren wenst men
een oplossing waarbij:



de lift zolang mogelijk in één richting blijft bewegen.
onderweg moet worden voldaan aan alle aanvragen.
de zin van de lift wordt pas omgedraaid als er geen onvoltooide aanvragen in de originele
zin meer zijn.
 eens de beslissing wordt genomen naar een bepaalde verdieping te gaan, wordt de
verplaatsing niet onderbroken.
Gebruik: Dit algoritme wordt gebruikt bij schijfscheduling (is dus enorm frequent gebruikt!)
Bij schijfscheduling moet de mechanische zoektijd zo klein mogelijk zijn. Het liftalgoritme
wordt gebruikt voor het berekenen van schijfarmverplaatsingen.
e) Het liftalgoritme: Opstelling
1) Elke aanvraag om verplaatsing creëert een proces, dat éénmalig een monitorprocedure,
aanvraag(), uitvoert. Deze voert de verplaatsing (alsook openen en sluiten deuren) uit.
2) De monitor heeft 2 wachtrijen, stijgt en daalt, die aanvragen ophouden tot ze uitgevoert kunnen
worden, respectievelijk tijdens een beweging in stijgende of dalende richting.
3) Onmiddellijk na het verlaten van de entryqueue komen de aanvraag() processen in één van de
twee wachtrijen terecht. In welke wachtrij, wordt beslist op basis van de huidige locatie van de lift en
eindbestemming. De afstand tot eindbestemming bepaalt de prioriteit waarmee de aanvraag
uiteindelijk zal vervuld worden.
4) Een 2e monitorprocedure, activeer(), wordt uitgevoerd telkens de deur van de lift gesloten wordt.
Deze repetitieve procedure verlost het meest prioritaire aanvraag proces uit de wachtrij, behorend
bij de actuele bewegingszin en keert de bewegingszin ook om als er geen in de wachtrij zitten.
5) De variabele vrij laat na elke periode van activiteit toe om de eerste aanvraag van de wachtrijen te
laten omzeilen.
aanvraag(int doel){
if(!vrij){
if(niveau < doel)
wait(stijgt, doel);
else if(niveau > doel)
wait(daalt, -doel);
else{
if(zin == STIJGEND)
wait(stijgt, doel);
else
wait(daalt, -doel);
}
vrij = FALSE;
niveau = doel;
}
activeer() {
vrij = TRUE;
if(zin == STIJGEND){
if(Qleeg(stijgt)){
zin = DALEND;
signal(daalt);
else
signal(stijgt);
else{
if(Qleeg(daalt)){
zin = STIJGEND;
signal(stijgt);
else
signal(daalt);
}
}
3) Reeks C
3.1. Vraag C1
Gelijktijdigheid: deadlocks
a) Definieer het begrip deadlock. Aan welke voorwaarden moet voldaan zijn opdat een deadlock zou
kunnen optreden ?
b) Bespreek de strategie detectie en opheffing van deadlocks. Behandel zowel het aspect detectie,
als het aspect opheffing. Verduidelijk zowel hulpmiddelen uit de grafentheorie als numerieke
technieken die hierbij van dienst kunnen zijn. Bespreek eveneens de praktische
implementeerbaarheid van deze strategie.
c) Vermeld drie andere benaderingen om met deadlocks om te gaan. Geef hiervan telkens een korte
situering, zonder echter op details in te gaan.
a)
Een deadlock is een verzameling processen waarin elk proces van de verzameling wacht op een
gebeurtenis, die alleen een ander proces in de verzameling kan veroorzaken. Omdat alle processen
aan het wachten zijn kan geen enkel proces zo’n gebeurtenis veroorzaken.
Voorwaarden voor een deadlock:




Wederzijdse uitsluiting: het systeem bevat bronnen die slechts door één proces kunnen
gebruikt worden.
Vasthouden en wachten: een proces mag toegewezen voorzieningen vasthouden terwijl het
wacht op de toewijzing van andere voorzieningen
Geen preëmptieve verwijderingen: Een bron kan niet gedwongen verwijderd worden van
een proces dat de bron vasthoudt. Alleen het proces dat de bron vasthoudt kan vrijwillig de
bron afstaan.
Cyclisch wachten: er bestaat een gesloten keten van processen waarin elk proces ten minste
één voorziening vasthoudt die het volgende proces in de keten nodig heeft.
b)
Detectie:
Benaderingen voor het detecteren van deadlocks beperken noch de toegang tot voorzieningen, noch
de acties van processen: indien mogelijk wordt altijd voldaan aan alle verzoeken van processen om
bronnen. Het deadlockprobleem wordt maar aangepakt als het zich effectief voordoet. Het is echter
niet zo eenvoudig deadlocks te detecteren. Het proces dat zich in een deadlock bevindt weet dit
immers zelf niet en ook het besturingssysteem weet dit niet.
Resourcegraaf:
Bij elke toestand van het systeem kunnen deadlocks pas worden vastgesteld door analyse van de
resourcegraaf. Een resourcegraaf toont de aanvragen en toewijzingen van processen aan bronnen bij
elke toestand van het systeem. In principe moet na elke aanvraag de resourcegraaf geanalyseerd
worden.

Indien van elke bron maar één element beschikbaar is => wacht-op-graaf: een mogen geen
cycli voorkomen, anders DEADLOCK!
 Indien bronnen meerdere elementen beschikbaar hebben => graafreductie: een
resourcegraaf kan worden gereduceerd indien er tenminste één procesknooppunt bestaat
waarvoor alle uitgaande pijlen kunnen worden omgedraaid (= alle gewenste bronnen kunnen
worden toegewezen) Indien volledige reductie mogelijk is => geen deadlocksituatie
Numerieke reductiemethoden:
Worden uitgevoerd mbv vectoren en matrices
Vectoren:
- aanwezige bronnen: totaal aantal elementen van elke bron
- beschikbare bronnen: aantal vrije elementen van elke bron
Matrices:
- Toewijzingsmatrix: geeft voor elk proces i hoeveel exemplaren van elke bron j reeds zijn
toegewezen
- Aanvraagmatrix: geeft voor elk proces i hoeveel exemplaren het proces nog wil van elke bron j.
Algoritme voor het detecteren van deadlocks:
Tijdens de uitvoering van het algoritme worden processen gemarkeerd om aan te geven dat ze geen
last hebben van een deadlock.
1) zoek een niet gemarkeerd proces i waarvoor geldt dat alle elementen op de i-de rij van A
kleiner zijn dan de overeenkomstige elementen van B. Indien zo’n proces er niet is stopt het
algoritme. Deze stap zoekt een proces op waaraan kan worden voldaan vanuit de momenteel
beschikbare bronnen, en dat tot het einde kan uitgevoerd worden.
2) tel alle elementen van de i-de rij van T op bij de overeenkomstige elementen van B. Het
geselecteerde proces wordt gedraaid tot het klaar is, en geeft alle bronnen, die het in zijn
bezit heeft, terug. Het proces wordt gemarkeerd als afgelopen.
Op het einde van het algoritme geven ongemarkeerde processen aan dat ze in een deadlock zijn.
Opheffen
Het controleren op deadlocks vraagt veel overhead en bovendien is het probleem er niet mee
opgelost. Er zijn een aantal manieren om deadlocks op te heffen, maar bij elke methode gaat
informatie verloren.



Elk proces in een deadlock, één voor één afbreken, detectie algoritme toepassen tot alle
deadlocks zijn verdwenen
Tijdens het uitvoeren van processen checkpoints (volledige procesbeeld) opslaan in een
bestand. Bij deadlock teruggaan naar vorige toestand zonder deadlock (rollback). Het werk
dat na de checkpoint is uitgevoerd gaat verloren.
Preëmptieve verwijdering van bronnen tot wanneer de deadlock niet meer bestaat.
Praktische implementeerbaarheid:
Veel overhead!
c)



Deadlocks vermijden door aanvragen van bronnen te analyseren en eventueel te vermijden.
1) Toestandsdiagrammen: veilige toestanden
2) Claimgrafen
3) Resourcetrajecten
Deadlocks onmogelijk maken door een van de 4 voorwaarden uit te sluiten
1) resources exclusief toegewezen aan één proces, beschermd door wederzijdse
uitsluiting
2) processen houden resources vast en wachten op andere resources
3) preëmptieve verwijdering van resources
4) cyclisch wachten: cyclus keten in de resourcegraaf
Kans op deadlocks minimaliseren. Het volledig uitsluiten van deadlocks vraagt meestal teveel
overhead.
3.2. Vraag C2
Gelijktijdigheid: deadlocks
a) Verduidelijk aan de hand van resourcetrajecten het verschil tussen de strategieën vermijden van
deadlocks en onmogelijk maken van deadlocks.
b) Bespreek in detail de strategie vermijden van deadlocks. Verduidelijk zowel hulpmiddelen uit de
grafentheorie als numerieke technieken die hierbij van dienst kunnen zijn. Bespreek eveneens de
praktische implementeerbaarheid van deze strategie.
c) Bespreek de alternatieve mogelijkheden in de strategie onmogelijk maken van deadlocks.
Behandel telkens in hoeverre deze praktisch kunnen verwezenlijkt worden.
d) Vermeld twee andere benaderingen om met deadlocks om te gaan. Geef hiervan telkens een
korte situering, zonder echter op details in te gaan.
a)
Vermijden
Onmogelijk maken
Verticale as: Voortgang van proces Q
Horizontale as: Voortgang van proces P
Dikke zwarte lijnen: Het pad dat uiteindelijk gevolgd wordt door de processor. (Omwille van
proceswisselingen kan het pad niet gewoon horizontaal of verticaal lopen)
De extra horizontale en verticale lijnen duiden op het aanvragen en vrijgeven van een bron.
De gearceerde gebieden duiden de momenten aan waarop beide processen dezelfde bronnen nodig
hebben. Door wederzijdse uitsluiting kunnen deze gebieden niet betreden worden.
Vermijden van Deadlocks:
De scheduler beslist om het zwarte gebied niet te betreden = de scheduler verwerpt het verzoek van
Q om B zolang A aan P toegewezen is.
Onmogelijk maken van Deadlocks:
Een proces geeft zijn bron vrij alvorens een andere bron te vragen. Deadlocks zijn onmogelijk.
b)
Voor het ontwerp van het algoritme voor vermijding van deadlocks hebben we claimgrafen nodig.
Claimgrafen zijn een bijzonder soort resourcegrafen, die ook de potentiële aanvragen weergeven.
Deze extra informatie zal het besturingssysteem nodig hebben om te weten welke bronnen een
proces in de toekomst zal aanvragen en gebruiken.
Het belangrijkste algoritme voor het vermijden van deadlocks is gebaseerd op het begrip veilige
toestand. Dit is een toestand waarin het besturingssysteem bronnen kan toewijzen zonder te
moeten vrezen voor deadlocks.
Om te bepalen of een toestand veilig is moet het besturingssysteem, behalve de reeds toegewezen
bronnen, ook weten wat elk proces in de toekomst zou kunnen aanvragen. Deze informatie zit
precies vervat in de claimgraaf op dat ogenblik. Een toestand is veilig indien de claimgraaf volledig
gereduceerd kan worden.
Uit deze concepten kan de volgende praktische benadering voor het vermijden van deadlocks
afgeleid worden:
Verzoekt een proces om een bijkomende voorziening die beschikbaar is, veronderstel dan fictief dat
aan dit verzoek voldaan wordt en pas de claimgraaf aan. Controleer vervolgens via graafreductie of
het resultaat een veilige toestand is. Is het resultaat een veilige toestand, voldoe dan ook effectief
aan het verzoek. Indien niet, blokkeer het proces totdat veilig aan het verzoek voldaan kan worden.
(= het bankiersalgoritme)
Numerieke technieken:
Worden uitgevoerd mbv vectoren en matrices
Vectoren:
- aanwezige bronnen: totaal aantal elementen van elke bron
- beschikbare bronnen: aantal vrije elementen van elke bron
Matrices:
- Toewijzingsmatrix: geeft voor elk proces i hoeveel exemplaren van elke bron j reeds zijn
toegewezen
- Aanvraagmatrix: geeft voor elk proces i hoeveel exemplaren het proces nog wil van elke bron j.
Zoek in de aanvraagmatrix A een rij waarvan alle elementen kleiner of gelijk zijn dan de
corresponderende elementen in B. Indien deze rij niet kan gevonden worden dan komt het systeem
bij een maximaal gebruik van bronnen uiteindelijk in een deadlock, omdat geen van de processen
kan worden afgemaakt.
Tel de overeenkomstige elementen van de toewijzingsmatrix T op bij B, en markeer het proces als
beëindigd
Herhaal stappen 1 en 2 tot alle processen gemarkeerd zijn als beëindigd. Is dit niet mogelijk, dan is de
oorspronkelijke toestand onveilig.
Praktische implementeerbaarheid:
Dit wordt in praktijk in geen enkel besturingssysteem gebruikt omdat het een onhaalbare zaak is om
van elk proces a priori te weten te komen welke bronnen het ooit nodig zal hebben
c)
Het optreden van deadlocks is onmogelijk indien aan verzoeken om bronnen en aan de
gelijktijdigheid van uitvoering van processen zondanige beperkingen worden opgelegd zodat aan één
van de vier noodzakelijke voorwaarden voor het optreden van deadlocks niet wordt voldaan.
1) Wederzijdse uitsluiting vermijden: Geen wederzijdse uitsluiting implementeren is in praktijk
niet mogelijk. Indien bronnen niet exclusief zouden worden toegewezen, zou er chaos
ontstaan.
2) Vasthouden en wachten vermijden: deadlocks kunnen onmogelijk gemaakt worden door te
voorkomen dat processen, die één of ander bron in bezit hebben, op nog meer bronnen
wachten. Dit kan bereikt worden door te eisen dat alle bronnen tegelijk worden
aangevraagd, voor de uitvoering. Indien een van de bronnen niet beschikbaar is, wordt geen
enkele bron toegewezen en moet het proces wachten.
Probleem: bronnen moeten a priori bekend zijn & uithongering mogelijk.
Oplossing: proces bij elke aanvraag van een nieuwe bron verplichten om de bronnen, die het
reeds in bezit heeft, vrij te geven.
Of twee-fasen-lock protocol:
fase 1: Groeifase: alle benodigde bronnen afgaan en op slot proberen zetten. Als er een niet
op slot kan gezet worden, alles vrijgeven en opnieuw beginnen
fase 2: Krimpfase: wijziging aanbrengen en slot verwijderen
Kan niet voor alle processen gerealiseerd worden
3) Preëmptieve verwijdering van bronnen: Het verwijderen van een bron dat door een proces
wordt vastgehouden is over het algemeen nog moeilijker te realiseren. De bron kan
weggehaald worden op voorwaarde dat de toestand van de bron gemakkelijk is op te slaan.
Bij printers en tapedrives is dit bijvoorbeeld niet mogelijk. Indien de bron is toegewezen aan
een proces dat niet geblokkeerd is, zijn aanvullende checkpoint en rollbackprocedures
vereist.
4) Cyclisch wachten doorbreken: Dit is de enigste mogelijkheid die in praktijk enigszins
haalbaar is. De meest voor de hand liggende oplossing is een globale nummering invoeren
voor alle bronnen. Processen kunnen op iedere moment een nieuwe bron aanvragen, maar
de aanvragen moeten in volgorde van de nummering van de bronnen gebeuren. Bovendien
moeten verschillende instanties van eenzelfde brontype in één keer aangevraagd worden.
Met deze regels kan een resourcegraaf en een wacht-op-graaf nooit een cyclus bevatten. Alle
processen worden sequentieel afgewerkt.
Echter INEFFICIËNT: processen worden vertraagd en onnodig de toegang geweigerd tot
bronnen. Dezelfde volgorde van bronnen voor elk proces is bovendien zeker niet optimaal.
d)
1) Detecteren en opheffen van deadlocks (zie C1)
2) Kans op deadlocks minimaliseren.
3.3. Vraag C3
a)
b)
Technologische stap:
Bij de eerste 2 manieren van geheugenbeheer is het noodzakelijk dat het proces volledig in het
geheugen geladen wordt. Door invoering van pagineren in segmentatie wordt het echter mogelijk
enkel die pagina’s (of segmenten) in het geheugen te laden die we op dat moment nodig hebben. Dit
concept noemen we virtueel geheugen.
Gevolgen:
Het deel dat zich op een bepaald moment in het hoofdgeheugen bevindt noemen we de residente
set. Op basis van de paginatabel (of segmenttabel) kan de processor vaststellen of alle
geheugenverwijzingen betrekking hebben op locaties die zich in de residente set bevinden. Wordt
een logisch adres (nu virtueel adres genoemd) tegengekomen dat zich niet in de residente set
bevindt, dan genereert de processor een interrupt = paginafout. Op dat moment neemt het
besturingssysteem de besturing over en plaatst een I/O-verzoek om de nodige pagina’s op te halen.
Indien het gewenste stuk is binnengehaald wordt een I/O-interrupt gegenereerd, die opnieuw het
besturingssysteem activeert, waardoor dit de paginatabellen kan bijwerken en het betrokken proces
terug in de gerede toestand kan plaatsen.
Voordelen:
=> Verbetering van systeemgebruik door:
- Meer ruimte voor processen => kans is groter dat er minstens 1 proces in de gerede toestand zal
zijn
- Geheugenhoeveelheid dat een proces kan aanspreken kan groter zijn dan de totale hoeveelheid
beschikbare hoofdgeheugen => programmeur moet geen rekening houden met het beschikbaren
geheugen, geen overlay-technieken nodig.
- Geheugen wordt efficiënter benut. I/O-operaties en bijgevolg tijd bespaard omdat ongebruikte
stukken niet in en uit geheugen moeten geswapt worden.
Nadelen:
- Heel wat overhead bij paginafouten. Bij teveel paginafouten -> trashing: processor is meer bezig
met swappen, dan uitvoeren van instructies.
c)
Paginering vereist een weloverwogen keuze voor de paginagrootte.
- Kleine pagina’s -> weinig interne fragmentatie, maar wel groot aantal pagina’s per proces -> grote
paginatabellen, waardoor er minder geheugen vrij blijft voor het proces.
- Grotere pagina’s geven ook een efficiëntere blokoverdracht van gegevens uit secundair geheugen.
- Bij een constante hoeveelheid toegewezen geheugen heeft de paginagrootte invloed op de
frequentie waarmee paginafouten optreden.
Relatief kleine paginagrootte is efficiënter. (order kb in praktijk)
In veel computersystemen is de virtuele adresruimte die elk proces kan aanspreken groter dan de
beschikbare hoeveelheid reëel geheugen. Hierdoor wordt de hoeveelheid geheugen die per proces
alleen al voor paginatabellen vereist is te groot om in het hoofdgeheugen te kunnen worden geladen.
Hiervoor bestaan 2 oplossingen:
1) Paginatabellen zelf in virtueel geheugen:
Hiervoor kan een systeem met 2 niveaus gebruikt worden: forward-mapped page table
Het paginanummer in het logisch adres wordt opgesplitst in 2 delen:
1. meest significante deel = index voor steeds residente paginatabel, en verwijst naar
specifieke paginatabel
2. minst significante deel = index specifiek paginatabel, verwijst naar fysieke frame
=> 2 soorten paginafouten mogelijk. Een voor binnenhalen specifieke paginatabel en een voor het
binnenhalen van de procespagina
2) Geïnverteerde paginatabel voor ganse systeem ipv procestabel voor elk proces.
Een geïnverteerde paginatabel bevat een ingang per geheugenframe. Grootte paginatabel is enkel
afhankelijk van de grootte van het geheugen.
Omdat de geïnverteerde paginatabel niet is gesorteerd op paginanummer, maar op framenummer,
en om te vermijden dat het paginanummer sequentieel moet opgezocht worden, past men hashing
toe. Bij virtueel geheugenbeheer wordt het paginanummer en de procesidentificatie vertaald naar
een hashwaarde, die gebruikt wordt als een index in een hashtabel. Deze tabel bevat een verwijzing
naar één van de elementen in de geïnverteerde paginatabel die de specifieke hashwaarde oplevert.
Alle elementen met dezelfde hashwaarde zijn in de geïnverteerde paginatabel aan elkaar gekoppeld
in een circulaire lijst. Het framenummer kan berekend worden op basis van het adres van het
element (ten opzichte van het beginadres van de geïnverteerde paginatabel) en hoeft bijgevolg niet
expliciet opgeslagen te worden.
In beide technieken veroorzaakt elke verwijzing naar een virtueel adres minimaal 2
geheugentoegangen: één voor het opvragen van de juiste paginatabel en één voor het opvragen van
de gewenste gegevens. Om verdubbeling van de geheugentoegangstijd te vermijden wordt een
hardwarecache in de MMU gebruikt die de meest recent gebruikte paginatabelingangen bevat.
d)
Paginering
Segmentatie
- onzichtbaarheid voor programmeur
- gemakkelijker- gemakkelijker
afhandeling van
afhandeling
groeiendevan
- eenvoudigere algoritmen voor
structuren
geheugenbeheer
groeiende structuren
- eliminatie externe fragmentatie
Nadelen
- interne fragmentatie
- externe fragmentatie
=> voordelen samenvoegen: besturingssystemen met zowel paginering als segmentatie. In
gecombineerde paginering- segmentatie virtueel geheugensystemen wordt de adresruimte van een
proces opgebroken in enkele segmenten, gekozen door de programmeur. Elk segment wordt
verdeeld in pagina’s met vaste grootte, gelijk aan de grootte van een frame in het hoofdgeheugen.
Voordelen
e)
Adresstructuur:
Adresvertaling:
Logische of virtueel adres = Segmentnummer + segmentpositie
Segmentpositie = paginanummer + paginapositie
Elk proces heeft zijn eigen segmenttabel, elk processegment zijn eigen paginatabel.
Seg # = index voor segmenttabel => ‘p’-bit, grootte v. segment, geheugenadres
Page # + geheugenadres = paginanummer = index paginatabel => framenummer
Frame # (= fysiek beginadres) + offset (= afstand van beginadres tot instructie) => instructie
3.4. Vraag C4
a)
Zie C3 deel a
b)
Technologische stap:
Om externe en interne fragmentatie zoveel mogelijk te beperken kunnen we proberen de processen
op te splitsen in stukjes die vrije ruimten in het geheugen kunnen opvullen. Het geheugen wordt dus
niet meer als een aaneengesloten blok in het geheugen geladen.
Hoe realiseren?
1) Paginering ~ vaste partitionering:
- Het hoofdgeheugen in frames verdeelt = stukken met gelijke, relatief kleine, grootte
- Procesbeelden in pagina’s verdeelt ter grootte van frames.
Het besturingssysteem houdt een paginatabel bij voor elk proces. Deze bevat de framelocatie voor
elke pagina van het proces.
2) Segmentatie ~ dynamische partitionering
Programma’s worden verdeelt in blokken, echter niet met gelijke grootte.
Het besturingssysteem houdt een segmenttabel bij voor elk proces, die de fysieke locatie van elk
segment van het proces bevat.
Voor- en nadelen:
Voordelen:
- interne (paginering) en externe (segmentatie) fragmentatie kleiner
- segmentatie vergemakkelijkt sharing
- meer processen in geheugen
Nadelen:
- ingewikkeldere adresvertalingen
c)
Een proces kan in de loop van de tijd verschillende partities bezetten. De locaties waarnaar een
proces verwijst zijn dus niet vast. Daarom wordt onderscheidt gemaakt tussen:

Logische adressen ~ het geheugenbeeld dat de programmeur heeft: verwijzingen naar
geheugenlocaties, onafhankelijk van de huidige toewijzing van het proces aan het geheugen.
Speciaal geval zijn de relatieve adressen. Hierbij worden alle adressen uitgedrukt tov één
bepaald punt, meestal het begin van het programma
 Fysieke adressen ~ het geheugenbeeld dat het besturingssysteem & de processor heeft: Dit
zijn de werkelijke locaties in het hoofdgeheugen.
Logische adressen moeten vertaald worden in fysieke adressen vooraleer geheugentoegang mogelijk
is. Deze omzetting wordt geregeld door het memory management unit op elk moment dat een
instructie wordt uitgevoerd.
Bij paginering:
Het besturingssysteem houdt een paginatabel bij voor elk proces. Elke ingang in de paginatabel bevat
het nummer van het frame in het hoofdgeheugen dat de corresponderende pagina bevat.
Alle pagina hebben een gelijke grootte die een macht is van 2 => logisch verband tussen logische en
relatieve adressen.
Logisch adres = Relatief adres = paginanummer + relatieve positie binnen pagina
MMU:
- linker bits van logisch adres = paginnanummer
- paginanummer is index procespaginatabel => framenummer
- fysiek adres = framenummer en relatieve positie samenvoegen
=> globale actie: tijdens instructiecyclus paginanummer veranderen in framenummer.
Bij segmentatie:
Het besturingssysteem houdt een segmenttabel bij voor elk proces, die de fysieke locatie van elk
segment van het proces bevat.
Segmenten hebben verschillende groottes => geen logisch verband tussen logische en relatieve
adressen. => adresvertaling minder gemakkelijk
Logische adres = segmentnummer + relatieve positie
MMU:
- segmentnummer uit linkerbits van logisch adres
- segmentnummer = index processegmenttabel => fysiek beginadres & lengte segm.
- fysiek adres = begin adres en relatieve positie optellen.
De lengte van het segment moet groter zijn dan de rechterbits van het logisch adres aangeven,
zoniet is het logisch adres ongeldig en wordt een interrupt gegenereerd.
d)
Voordelen
Paginering
- gemakkelijke adresvertaling
- verborgen voor programmeur
Nadelen
- interne fragmentatie
Segmentatie
- blokken van verschillende grootte
- sharing
- lengte segmenten kan wijzigen in de loop
van de uitvoering
- externe fragmentatie
- ingewikkeldere adresvertaling
e)
Administratie van geheugen gebeurt door het besturingssysteem. Er wordt bijgehouden welke
geheugenpartities reeds in gebruik zijn en welke nog beschikbaar zijn.
1) Bitmaps:
Het geheugen wordt verdeeld in kleine allocatie-eenheden van gelijke grootte. Bij elke allocatieeenheid hoort een bit die aangeeft of het geheugen vrij of bezet is.
Niet veel gebruikt, want tijdverslindend proces bij zoeken naar aaneengeschakelde allocatieeenheden die groot genoeg zijn voor een proces.
2) Gekoppelde lijsten:
Het geheugen wordt voorgesteld als een gekoppelde lijst van segmenten die ofwel in gebruik zijn
door een proces ofwel vrij zijn.
De meest efficiënte oplossing plaatst aan het begin en het eind van een segment informatie met de
status en de grootte van het segment en neemt enkel de vrije segmenten op in een
dubbelgekoppelde lijst.
3) Buddysysteem:
Gehele geheugenruimte die beschikbaar voor toewijzing wordt behandeld als een blok met groot 2y.
Zolang de vereiste geheugenruimte kleiner is dan de helft van de beschikbare ruimte wordt die
ruimte gesplitst in 2. Zo wordt de ruimte verder gesplitst tot het kleinst mogelijke blok wordt bereikt.
Het buddysysteem houdt voortdurend een gekoppelde lijst bij van alle niet toegewezen blokken.
Het buddysysteem versnelt samenvoeging, omdat het alleen moet zoeken in de lijst van blokken met
dezelfde grootte.
Interne fragmentatie helaas zeer groot!
3.5. Vraag C5
Geheugenbeheer: besturingssysteem software.
a) Welke globale taken bij geheugenbeheer moeten worden vervuld door
 de computerhardware en in het bijzonder door de processor?
 de besturingssysteemsoftware?
b) Welke (zes) specifieke vragen moet besturingssysteem software beantwoorden ? Ga hierbij
zoveel mogelijk in detail voor wat de invulling ervan betreft, behalve voor het probleem van
vervangingsstrategieën. Bij deze laatste moet je enkel de vraagstelling formuleren. Vermeld ook
steeds hoe het probleem in Unix en in Windows NT wordt aangepakt.
c) Bespreek paginabuffering. Bij welke vragen in b) komt deze techniek ter sprake ?
d) Bespreek de werksetbenadering. Bij welke vraag in b) komt deze techniek ter sprake ? Hoe wordt
de werksetbenadering in praktijk benaderd ?
a)
Processor:
- genereren van paginafouten
Besturingssysteem:
- beslissen of een pagina of segment naar het secundair geheugen moet verplaatst worden of niet en
de uitwerking ervan
b)
1) Wanneer moet een pagina worden overgebracht naar het hoofdgeheugen?
2 alternatieven:
1. vraagpaginering:
een pagina wordt pas overgebracht naar het hoofdgeheugen als hierom gevraagd
wordt => veel paginafouten bij opstarten van proces
2. prepaginering:
Meerdere aaneengesloten pagina’s, zoals ze opgeslagen zijn in het secundair
geheugen, worden ineens binnengehaald, ook al is maar een pagina gevraagd.
Unix: vraagpaginering
Windows: prepaginering, aantal pagina’s is afhankelijk van het geheugen en de aard
van de pagina’s.
2) Op welke plaats in het hoofdgeheugen moeten pagina’s geladen worden?
Enkel relevant bij pure segmentatiesystemen.
o
o
o
o
o
First-fit: zoekt vanaf het begin van het geheugen en plaatst het segment in de eerste
plaatst die groot genoeg is.
Next-fit: zoekt vanaf de plaats van waar het geëindigd is. Plaatst het blok in de eerst
geheugenplaats die groot genoeg is.
Best-fit: zoekt het hele geheugen af naar de plaats die het best past. Het geheugen
wordt snel verdeeld in blokken die te klein zijn voor nieuwe processen.
Worst-fit: wijst het grootst beschikbare blok toe, in de hoop veel gaten te krijgen die
nog voldoende groot zijn voor nieuwe processen.
Optimal-fit: Schakelt dynamisch tussen de vier basisalgoritmen.
3) Hoeveel paginaframes moeten worden toegewezen aan elk actief proces?
o Hoe kleiner de hoeveelheid geheugen die wordt toegewezen aan elk proces, hoe
groter het aantal processen dat kan worden geladen, hoe groter de kans dat er een
proces zich in de gerede toestand bevind.
o Een te klein aantal pagina’s per proces zal de frequentie van paginafouten doen
toenemen.
o Een overtoewijzing van geheugen aan een proces levert geen merkbare
verbeteringen
 2 mogelijke strategiën:
1. Vaste toewijzing: aantal pagina’s wordt toegekend bij creatie proces
2. Variabele toewijzing: paginaframes worden dynamisch toegewezen of onttrokken
aan processen om de paginafoutfrequentie te verlagen. Hierbij moet echter het
gedrag van de processen worden beoordeeld wat overhead veroorzaakt.
Unix: variabele toewijzing
Windows: variabele toewijzing
4) Lokale of globale vervanging?
Wanneer we een pagina moeten vervangen, omdat een nieuwe pagina moet worden
geladen zijn er 2 mogelijkheden:
o
o
Lokale vervanging: alleen de pagina’s van het proces dat een fout veroorzaakte
komen in aanmerking voor vervanging
Globale vervanging: alle pagina’s in het hoofdgeheugen komen in aanmerking voor
vervanging.
Gebruik van paginabuffering en werksetbenadering
Unix: variabele toewijzing met globale vervangingsstrategie
Windows: variabele toewijzing met lokale vervanginsstrategie
5) Wanneer moet een gewijzigde pagina worden weggeschreven naar het secundair
geheugen?
2 strategieën:
1. vraagopschoning: een pagina wordt alleen weggeschreven naar het secundair
geheugen als deze is geselecteerd voor vervanging.
2. opschoning vooraf: pagina’s worden in batches weggeschreven ook al zijn hun
paginaframes nog niet aan vervanging toe. Dit leidt tot verspilling als de kans groot is
dat de pagina’s later opnieuw zullen worden gewijzigd. Daarom wordt vaak
paginabuffering gebruikt.
6) Welke specifieke pagina’s in het hoofdgeheugen moeten worden vervangen wanneer een
nieuwe pagina moet worden geladen?
c)
Parallel met de paginatabellen per proces worden op systeemniveau twee intermediaire lijsten van
slachtofferframes bijgehouden: de lijst van vrije frames en de lijst van vrije frames met gewijzigde
pagina’s, die als cache werken voor te vervangen pagina’s.
Beslist een besturingssysteem om een pagina uit te swappen, dan wordt die pagina nog niet direct
verwijderd of naar het secundaire geheugen geschreven. Enkel de ingang in de paginatabel wordt
verwijderd en onderaan één van de lijsten van slachtofferframes bijgeplaatst, naar gelang de pagina
gewijzigd is of niet.
Moet er een nieuwe pagina geladen worden dan wordt de pagina bovenaan de lijst effectief
verwijderd of vanuit het hoofdgeheugen naar het secundair geheugen verplaatst.
Doordat een pagina nog even beschikbaar blijft in een intermediaire lijst kunnen we tijd besparen
wanneer er toch nog naar die pagina verwezen zou worden.
Komt aan bod bij vraag 4 & 5
d)
Bij combinatie variabele toewijzing met lokale vervangingsstrategie (vraag 3 & 4 van b) selecteert het
besturingssysteem te vervangen pagina’s uit de residente set van het actieve proces dat de fout
veroorzaakt heeft. Hierdoor moeten alternatieve technieken gebruikt worden om de waarschijnlijke
toekomstige behoeften, meer bepaald de ideale grootte van de residente set, van deze actieve
processen in te schatten. Hiervoor gebruikt men soms de werksetbenadering.
De werkset is de verzameling pagina’s die nodig is voor de uitvoering van een proces gedurende een
bepaalde periode. Als die set in het hoofdgeheugen staat treden geen paginafouten op. Periodiek
worden de pagina’s uit de residente set van een proces die niet voorkomen in de werkset,
verwijderd.
Een proces wordt enkel efficiënt uitgevoerd als de in het hoofdgeheugen residente set de werkset
kan bevatten: zijn er te weinig frames, dan zullen er veel meer verwijzingen zijn die paginafouten
opleveren. Indien de som van de werksetgroottes van alle processen groter is dan het totaal aantal
beschikbare frames, dan treedt trashing op. Het besturingssysteem kan beslissen om een of meer
processen volledig uit het geheugen te swappen. De werksetstrategie kan bijgevolg automatisch en
dynamisch het aantal actieve programma’s en hun geheugenverbruik beheren, en kan bovendien
trashing vermijden.
Praktisch gebruik:
Het nauwkeurig bepalen van de werksetgrootte vraagt veel overhead, daarom wordt de
foutenfrequentie van elk proces bijgehouden: daalt deze onder een drempelwaarde dan
kunnen frames van het proces aan andere processen worden toegekend. Wordt de
foutenfrequentie te hoog dan heeft het proces meer frames nodig.
Windows NT gebruikt een andere methode: bij elke paginafout wordt de werksetgrootte van dat
proces vergroot, op voorwaarde dat een drempelwaarde niet wordt overschreden. Pas bij
overschrijding leidt een paginafout tot paginavervanging
-
3.6. Vraag C6
Geheugenbeheer: vervangingsstrategieën.
a) Waar in de besturingssysteem software voor geheugenbeheer situeren deze vervangingsstrategieën zich ? In welke situaties (omschrijf deze !), buiten dit specifieke domein van
geheugenbeheer, zijn eveneens vervangingsstrategieën noodzakelijk ? Wie zorgt in deze situaties
voor de implementatie ervan ?
b) Bespreek de principes van de diverse vervangingsstrategieën, met inbegrip van de eventuele
varianten.
c) Vergelijk en bespreek de efficiëntie van deze strategieën (onderling en met de optimale strategie),
aan de hand van volgend voorbeeld: . . . Bovenaan het schema worden de achtereenvolgende
pagina's vermeld die nodig zijn voor de uitvoering van een proces waaraan drie geheugenframes zijn
toegekend. Bepaal voor de diverse strategieën de inhoud van de paginatabel op elk ogenblik. Duidt
eveneens telkens aan wanneer paginafouten optreden.
d) Welke (reële) strategie is globaal de meest efficiënte ? Is dit steeds het geval (geef eventueel een
tegenvoorbeeld) ? Hoe kan deze strategie in hardware en in software (eventueel benaderend)
worden geïmplementeerd ?
a)
Op het moment er geheugen moet vrijgemaakt worden moet een er pagina’s uit het hoofdgeheugen
geswapt worden. Welke pagina’s dit best zijn wordt bepaald door de vervangingsstrategie.
Ook op hoger lagen van de geheugenhiërarchie zijn vervangingstrategieën nodig. Hiervoor kan het
hardwaremechanisme van de LRU gebruikt worden.
b)




Optimale strategie: vervangt de pagina’s waarvoor het het langst zal duren voor ze opnieuw
opgevraagd zullen worden. In praktijk niet realiseerbaar.
Last Recently used: vervangt de pagina in het geheugen waarnaar het langst niet verwezen
is.
Niet geschikt voor processen met een cyclisch verwijzingspatroon, waarbij het paginabereik
groter is dan de hoeveelheid geheugen.
In praktijk moeilijk te implementeren: het is in principe nodig om een gesorteerde lijst of
stapel van pagina’s bij te houden, waarbij de recentst gebruikte pagina voorop staat en de
minst recente achteraan. De lijst moet softwarematig bij elke verwijzing naar het geheugen
aangepast worden wat veel te lang duurt.
Oplossing: hardwaremechanisme
Er wordt voor een machine met N paginaframes een matrix van NxN bits bijgehouden die
geïnitialiseerd zijn op 0. Telkens een paginaframe X gebruikt wordt, maakt de hardware eerst
in een rij X alle bits 1 en vervolgens in kolom X alle bits 0. Op elk moment geeft de binaire
waarde van de rij dan aan hoe recent de overeenkomstige pagina dan gebruikt is. Niet
bruikbaar op niveau van hoofdgeheugen – secundair geheugen, maar wel in hogere lagen
van de geheugenhiërarchie.
Not Frequently Used: Aangezien het hardwaremechanisme niet beschikbaar, wordt een licht
afwijkend software-algoritme gebruikt. In plaatst van het algoritme na elke
geheugenverwijzing toe te passen, wordt het slechts periodiek toegepast. Er wordt voor elke
pagina een softwareteller bijgehouden. Wanneer een paginafout optreedt wordt de pagina
verwijderd waarvan de teller het kleinst is.
First In, First Out: behandelt de frames die zijn toegewezen aan een proces als een circulaire
buffer, voegt nieuwe pagina’s toe aan het eind van de buffer en verwijdert pagina’s die zich
al het langst in het geheugen bevinden.
Pagina’s die langdurig nodig zijn voor het proces worden dan ook herhaaldelijk in en uit het

hoofdgeheugen gepagineerd.
Presteert zeer slecht!
Anomalie van Belady: meer frames beschikbaar, toch meer fouten!
Klokstrategie: Ook wel tweede-kans-algoritme genoemd. Aan elk frame wordt een extra usebit gekoppeld, die in de paginatabel opgeslagen wordt. ~ NFU-algoritme waarbij de teller
maar uit 1 bit bestaat. De usebit wordt op 1 ingesteld bij het laden in het hoofdgeheugen en
wanneer de pagina gebruikt wordt. De frames die kandidaat zijn voor vervangen worden
behandeld als een circulaire buffer (FIFO) Moet een pagina vervangen worden dan zoekt het
besturingssysteem adhv een pointer naar een frame waarvoor de usebit 0 is. Komt het hierbij
frames tegen waar de usebit 1 is dan worden die op 0 ingesteld. Het verschil met FIFO is dat
de recent geadresseerde frames worden overgeslagen.
o Kan geoptimaliseerd worden door het aantal usebits te verhogen. (Linux)
o Ook kan men de dirty bit bij de selectie betrekken => pagina’s die niet recent
gebruikt zijn en niet gewijzigd zijn worden verwijdert. Wordt bij een eerste rondje
niets gevonden dan worden de pagina’s opnieuw overlopen en wordt naar pagina’s
gezocht die gewijzigd zijn maar niet recent gebruikt zijn. Ook dit rondje kan niets
opleveren.
=> derde-kans-algoritme (Mac)
o
In Unix wordt nog een andere verfijning gebruikt voor het beheren van
gebruikersprocessen. (Voor kernelprocessen wordt een niet-virtueel buddysysteem
gebruikt.) De paginering wordt gedeeltelijk uitgevoerd door een specifiek proces, de
paginadeamon. Unix houdt een dubbelgekoppelde lijst bij waarin alle vrije
paginaframes staan. Bij een fout wordt het eerste element uit de lijst verwijdert en
wordt de benodigde pagina in dat frame ingelezen. De paginadeamon onderzoekt
regelmatig of het aantal vrije frames gelijk is aan de parameter lotsfree. Als er niet
voldoende frames vrij zijn dan wordt er geswapt. Er wordt bij het swappen geen
rekening gehouden met bij welk proces de pagina’s behoren => globaal
vervangingsalgoritme.
Omdat een volledige doorgang van het klokalgoritme vrij lang blijkt te duren wordt een klokalgoritme
met 2 wijzers (pointers) gebruikt. De voorste wijzer zet de usebit op 0 terwijl de achterste pagina’s
voor verwijdering selecteert
c)
d)
LRU benadert in het voorbeeld het best de optimale strategie. LRU is echter niet geschikt voor
processen met een cyclisch verwijzingspatroon en is in praktijk moeilijk te implementeren. NFU
benadert LRU. FIFO is het snelste proces.
Aangezien het klokalgoritme gebaseerd is op NFU en FIFO is dit globaal het meest efficiënte.
Dit algoritme kan in software worden geïmplementeerd. Dit proces kan aangeroepen worden door
verschillende gebeurtenissen:
 Op tijdbasis (bv elke seconde)
 Door de scheduler, indien de paginafoutenfrequentie te hoog oploopt
 Indien de lijst van vrije frames te klein wordt
Download