71 4. 4.1. Allmänt Vid multiprogrammering kan det vara önskvärt att anpassa systemets beteende till olika tillämpningars behov. En anledning till multiprogrammering var att man önskade öka genomströmningen. Antag tre jobb, vardera bestående av tre faser, givna: inmatning, beräkning och utmatning. Tiderna för respektive operation är för de tre jobben 1, 1, och 10, 1, 10 och 1 respektive 10, 1 och 1. Satsvis bearbetning skulle ge en totaltid 36 för de tre jobben. Eftersom de tre faserna i jobben utnyttjar olika resurser kan operationerna överlappas. Jobb är en beteckning på vad som idag kallas process och härstammar från tiden med satsvisbearbetning under multiprogrammering. /Schemaläggning ('Scheduling'): Intervall Inmatning Beräkning Utmatning 0-1 Jobb 1 1-2 Jobb 2 Jobb 1 2-12 Jobb 3 Jobb 2 Jobb 1 12-13 Jobb 3 Jobb 2 13-14 Jobb 3 Med denna multiprogrammering kan totaltiden reduceras till 14. Denna högst avsevärda vinst beror på att blandningen av jobb i detta exempel är överdrivet bra, men resonemanget har ändå en poäng. 4.2. Begrepp Schemaläggningen av processer brukar struktureras. 4.2.1. 'Dispatcher' Denna modul i kärnan i operativsystemet handhar bara själva igångsättandet av processer. Modulen väljer alltid att köra den process som 'short term scheduler' placerat först i redolistan. 4.2.2. 'Short term scheduler' Denna del av operativsystemet hanterar blandningen av aktiva processer i exekverande, redo och korttidsblockerat tillstånd. Förutsättningen är att processernas aktiva namnrum är allokerat till primärminnet: Blockerandetillstånden avser semaforlistor eller dylika korttids väntetillstånd. 4.2.3. 'Medium term scheduler' Denna del väljer ut de processer som ska vara aktiva. Väntetillstånd vars orsaker är mer långtidsverkande införs tex för processer som väntar på långsam in/ut-matning eller på att få processdelar (tex sidor) inlästa till primärminnet. Under vissa förutsättningar kan det vara viktigt att begränsa antalet aktiva processer (se Minnesallokering; 'Thrashing'). 4.2.4. 'Long term scheduler' I multiprogrammerade kövisbearbetande system sekvenseras hela jobb ('spooling') och dessas in/ut-sekvenser på långsamma medier som skrivare på skivminne innan de blir föremål för egentlig schemaläggning. Långtidsschemaläggaren har kontroll över sådana jobb. 4.2.5. Schemaläggningen syftar till att förbättra prestanda. Den kan avse något eller flera av följande mått.
72 i. Processorutnyttjande ('cpu utilization'). Detta brukar mätas i % (av reell tid). Oftast gäller att detta ökas då graden av multiprogrammering ökas. Ett 'overhead' (tid som operativsystemet utnyttjar för resursplanering) brukar vara i storleksordningen 1-10%. ii. Genomströmning ('through put'). Detta mått beskriver hur många processer som per tidsenhet exekveras klart av systemet. iii. Processtid ('process time'). Tiden mellan det att en process anländer till systemet till dess processen är avslutad. Oftast är det mer intressant att mäta medelvärdet av processtiderna. iv. Väntetid ('waiting time'). Den tid processer måste vänta på att få tillgång till resurser. Väntetiden uppstår på grund av att resurser delas. Processtiden blir summan av denna väntetid och processens exekveringstid. v. Svarstid ('response time'). Intressant vid interaktiva och realtids- tillämpningar. Denna tid R i sammansätts av den tid det tar för processen att utföra en begäran C i, den tid processen är blockerad i väntan på icke tillgänliga resurser B i och den tid processen måste vänta i redolistan då andra processer exekverar I i ; R i = C i + B i + I i. Tiden I i beror i sin tur på process- och väntetid för högre prioriterade processer. Observera att måtten (delvis) är ömsesidigt beroende. Ett högt cpu-utnyttjande leder tex (ofta) till längre svarstid. 4.3. Algoritmer De tre viktigaste typerna av algoritmer är - Algoritmer som bygger på prioritet. - Algoritmen 'round robin'. ('Robin' betyder rödhake och 'round robin' är ett spel/en lek, tror jag.) - Tidstyrning. 4.3.1. Högsta prioritet först (HPF) En prioritet (som kodas i processbeskrivningen) används för att sortera redolistan. Algoritmerna i denna klass kan användas på två sätt. -- 'preemptive' eller -- icke 'preemptive'. I det första undersöks och sorteras redolistan vid varje avbrott eller 'trap' så att färskast möjliga information utnyttjas. I det andra fallet körs en påbörjad process till dess den blir helt klar, gör fel eller blockerar sig själv oberoende av om det under tiden har inträffat att någon tidigare blockerad process med högre prioritet anlänt till redolistan. Prioriteten kan sättas på tre sätt: i. Fix prioritet. Alla processer tilldelas en prioritet när de skapas endera av operativsystemet eller av användaren. ii. Halvdynamisk prioritet. Prioriteten kan förändras av användaren via systemanrop eller kommandon. iii. Dynamisk prioritet. Prioriteten ändras av operativsystemet under processens aktiva liv tex genom att låta den vara a(t) i blockerat tillstånd och b(t) i exekverande tillstånd, där t är tiden och a och b givna (enkla, tex linjära) funktioner.
73 Den metod som alltid ger den minsta medelväntetiden är 'shortest job first' (SJF). Prioriteten är det inverterade värdet av processens (resterande) exekveringstid. Denna måste i praktiken uppskattas. Metoden 'first come first served' (FCFS) är icke-preemptive och bygger på att först anländ process åsätts högst prioritet. Operativsystem för realtidstillämpningar brukar bygga på halvdynamisk HPF. Realtidstillämpningar är ofta cykliska; de ska exekvera under vissa intervall. I 'rate monotonic scheduling' (RMS) sätts prioriterna i omvänd proportion till exekveringsintervallet hos processerna. utan hänsynstagande till processernas "viktighet" eller varaktighet. 4.3.2. 'Round robin' (RR) Detta är en tidstyrd 'preemptive' metod. Redolistan ordnas FCFS. Processer tillåts exekvera högst ett sk tidskvantum eller 'time slice'. Om processen inte är klar eller inte begår fel eller inte blockerar sig själv under ett tidskvantum placeras den sist i redolistan och nästa process väljes. Tidskvanta brukar vara i storleksordningen 0.01 till 1 sekund. Stora tidskvanta gör att metoden urartar till FCFS. Korta tidskvanta gör att mycket tid åtgår till processbyten. Metoden används då alla processer ska ges samma tjänst, tex i tiddelningssystem ('time sharing'). Tidskvantum kan anpassas efter (minskas med) antalet aktiva processer; metoden kallas då cyklisk 'round robin'; fler processer ger kortare tidskvantum, dock måste en undre gräns sättas så att inte det 'overhead' som processbytena medför blir orimligt stort. Exempel: Om ett processbyte tar s tidsenheter och om man vill att varje process ska köras var t:te tidsenhet samtidigt som 'overhead' ska minimeras bör man alltså välja tidskvantum q = t/n - s, om det finns n stycken aktiva processer. Tiden (s+q)*n skall vara t och q så stort som möjligt. Metoderna RR och HPF kan kombineras. Det är möjligt att tänka sig flera redolistor; en per prioritet och inom varje lista avvända RR. Det är också möjligt att använda tidstyrda dynamiska prioriteter för att efterlikna ett RR-beteende. 4.3.3. Tidstyrning Detta innebär att processerna via systemanrop eller användaren via kommandon anger 'scheduling times'. Vanligt är att kunna ange - tidigast tid. - senast tid. - intervall. I detta fall är det ju egentligen användaren som svarar för schemaläggningen. Operativsystemet ger avsedd schemaläggning via tidslistan. Kombinerat med halvdynamiska prioriteter är detta exakt vad som brukar användas i realtids[operativ]system. De olika algoritmerna påverkar de givna prestandamåtten i olika hänseenden. 4.3.4. Schemaläggning i VMS I systemet VMS används i grunden prioriteter: Prioriteter 31-16 tilldelas fixt till realtidsprocesser. Prioriteter 15-0 varieras dynamiskt för interaktiva tidsdelade processer. Sådana processer tilldelas en bas-prioritet (minimumprioritet). Till varje systemhändelse associeras en prioritetsökning (pö). Exempelvis har en avslutatad interaktiv i/o operation högre pö än en avslutad diskoperation. När en process väcks på grund av en händelse adderas pö till prioriteten för att bilda aktuell prioritet. Interaktiva processer exekveras längs ett tidskvantum. När en sådant tilländalupit minskas aktuell prioritet med 1. Vid varje händelse körs alltid den process som har högst prioritet. Realtidsprocesser körs till dess de är klara eller på annat sätt blockerar sig själva.
74 4.3.5. Exempel Figur 4.1 visar hur val av algoritm påverkar medelvärdet av processtiden. Observera att detta mått är bara ett av flera som kan vara värt att studera. Giver är tre processer enligt följande Process nr Ankomsttid Längd Prioritet ------------------------------------------------------------- 1 0-4 medium 2 0 2 låg 3 0 + 3 hög ------------------------------------------------------------- För olika metoder erhålls följande scheman. Processtid 1 2 3 medelvärde --------------------------- SJF p2 p3 p1 tid 2 5 9 9 2 5 5.3 FCFS RR (q=1) p1 p2 p3 p1 p2 p3 p1 p2 p3 p1 p3 p1 4 6 9 5.7 9 5 8 7.3 RR(q 4) Precis som FCFS HPFS p3 p1 p2 3 7 9 Figur 4.1 Exempel på schemaläggning 7 9 3 6.3 4.3.6. Systemanrop I samband med processers schemaläggning används följande systemanrop. - create-process och delete process. Innebörden är att pcb-er skapas respektive tas bort. - activate-process ('schedule' eventuellt med tidsangivelser). - passivate-process ('suspend'). - request/release resource. Anrop som svarar mot P/V operationer på (binära) semaforer. - set-priority. - set-time.slice. - anrop för kommunikation synkronisering ömsesidigt uteslutande. I realtidssystem brukar dessutom förekomma en mängd anrop som avser möjligher att styra in- och utmatning i detalj. Följande är en fullständig lista från ETT verkligt (litet) realtidsoperativsystem. - Synkron och asynkron läsning och skrivning (5 systemanrop). - In/utmatningskontroller (4 systemanrop) - Allokera och frisläpp utrymme på disk (5 systemanrop). - Avsluta, blockera, ladda in och schemalägg processer (7 systemanrop). - Ange reell tid (1 systemanrop). - Tidstyrd schemaläggning (2 systemanrop). - Skicka en "sträng" till en annan process (1 systemanrop). - Lås och frisläpp resurser/enheter (3 anrop).
75 4.4. Baklås Fenomenet betyder att två eller fler processer har tilldelats och begär resurser så att de aktuella processerna kommer att bli blockerade för alltid. Tre villkor är nödvändiga för att baklås ska uppstå: i. Resurserna är exklusivt kontrollerade, dvs föremål för ömsesidigt uteslutande. ii. Resurserna är 'non-preemptive', dvs kan bara frisläppas av den process som begärde resursen. iii. Resurserna efterfrågas cirkulärt. Ett specialfall är 'hold and wait' som innebär att processer håller resurs(er) och väntar på fler. Figur 4.2 illustrerar baklåsvillkoren. 4 3 Södergående trafik stannar vid 4 pga västergående trafik som är blockerad vid 2, etc -- cirkulärt Korsningarna 1, 2, 3 och 4 är 1 2 A. föremål för öu (endast en bil ryms) B. 'non preemptible' (bara den som står i korsningen kan frisläppa den) och C. en cirkulär väntan föreligger A, B och C är de nödvändiga och tillräckliga baklåsvillkoren Figur 4.2 Baklås i en trafikmiljö För att bemästra baklåsfenomenet är några olika metoder tänkbara. Hanteringen inkorporeras i de systemanrop som handhar resursreserveringar och frisläppningar av tex enheter, minne, filer och "lås". 4.4.1. Förhindrande av baklås ('prevention') Detta innebär att användaren eller operativsystemet ser till att minst ett av de nödvändiga baklåsvillkoren inte uppfylls. Villkor i. är svårt att neka eftersom många resurser tex yttre enheter inherent är odelbara. Villkor ii. går principiellt alltid att neka, men det skulle ofta leda till för mycket 'overhead'. Villkor iii. kan uteslutas genom att numrera alla resurser och endast tilldela resurser i nummerordning. Cirkulär väntan kan då inte uppstå, men metoden kan ge mycket 'overhead' (onödig resursreservering) och förutsätter att de resurser en process behöver är kända i förväg. 4.4.2. Undvikande av baklås ('avoidance') Om alla processers framtida resursbehov är känt kan baklås undvikas genom att se till att ingen sådan allokering sker att den i framtiden kan ge baklås. En algoritm som kallas 'bankers' algorithm' kan användas för återanvändbara resurser som allokeras i enheter. Varje process identifieras av ett index i i intervallet [1, N] och har maximumbehov maxdemand(i), sig redan tilldelat allocated(i) och återstående behov claim(i).
76 procedure banker's algorithm; unusedunits := totalunits; for i in [1,N] do unusedunits := unusedunits - allocated(i); claim(i) := maxdemand(i) - allocated(i); maynotfinish(i) := true; end for; flag := true; while flag do flag := false; for i in [1,N] do if maynotfinish(i) and claim(i) unusedunits then flag := true; maynotfinish(i) := false; unusedunits := unusedunits + allocated(i) end if; end for; end while; if unusedunits = totalunits then 'system is safe' else 'system is unsafe' end if; Tilldelning av en resursenhet sker endast om systemet är 'safe'. Figur 4.3 visar ett annat sätt att framställa undvikande av baklås. Resurs 1 frisläpps Virtuell tid för process 2 Godkänd "processväg" Resurs 2 frisläpps Resurs 1 behövs Resurs 2 behövs Osäkert ('unsafe') område Väg som leder till baklås Olämligt ('infeasible') område Om processerna schemaläggs så att vägen kommer in i det osäkra området så resulterar det i baklås, eftersom vägen är en icke-avtagande funktion. Om processerna schemaläggs så att vägen inte kommer in i det olämpliga området så undiker man baklås Resurs 1 behövs Resurs 2 behövs Resurs 1 frisläpps Resurs 2 frisläpps Virtuell tid för process 1 Figur 4.3 Baklåsillustration 4.4.3. Upptäckt och återstart ('detect and recover') Tekniken innebär att operativsystemet genom att upprätthålla en beskrivning av allokeringstillståndet kan avgöra när ett baklås har inträffat. Om tillräcklig information om ett tidigare systemtilstånd är sparad kan systemt återstartas från detta. Nytt baklås undviks hoppeligen genom att systemet av processer har ett icke-deterministiskt beteende, dvs tar en alternativ exekveringsväg den andra gången. Om inte tillräcklig information kan sparas för återstart återstår att successivt avsluta processer till dess baklås inte längre finns eller att avallokera resurser eller resursenheter en efter en.
77 Upptäckt av låsning kan baseras på en sk precedensmatris. Antag att R i, 1 i m, är resurser som i helhet tilldelas processer P k, 1 k n. Om en process P k tilldelats en resurs R i säger vi att processen är omedelbar (eller första) precedent till resursen. Om en process P behöver en resurs R som redan (exklusivt) tilldelats en annan process Q, så säges P vara precedent till Q. P är då andre precedent till resursen R. Ett baklås föreligger om en process som tilldelats minst en resurs har sig själv som j:te precendent, j 2. Precendensmatrisen M framställs genom att som radindex använda P k och som kolumnindex använda R i och P k. Matrisen M, en n*(n + m)- matris, bildas genom att sätta M ij = 1 precis då i (en process) är en omedelbar precedent till j (resurs eller process) och 0 för övrigt. Matrisen delas upp i två submatriser M = [MR, MP]. Ett baklåstillstånd kan inträffa om det för någon potens MP e gäller att denna matris har minst ett diagonalelement = 1. Många föredrar att uttrycka ovanstående med hjälp av grafer i stället. Eftersom grafer kan uttryckas med (Booleska) matriser och omvänt, så blir uttrycksmedlen ekvivalenta. Figur 4.4 illustrerar. R1 R2 R3 P1 P2 P3 P4 P1 har R1, P2 har R2, R3 delas mellan P2 och P3. P2 och P4 väntar på R1 och P1 väntar på P2/R2. Precedensmatrisens två delar är 1 0 0 0 1 0 0 0 1 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 0 0 0 = MR MP, så MP*MP*MP = Risk för baklås föreligger 1000 0100 0000 0001 Figur 4.4 Precedens; graf och matris 4.4.4. Strutsalgoritmen ('the ostrich algorithm') Innebär att man utgår från att sannolikheten för baklås är försumbar. Risk för baklås bortses ifrån. Man kör huvudet i sanden. Går det så går det. Metoden används i Unix. 4.4.5. Metoderna kan kombineras Exempel: I ett system kan 'swap'-utrymme på disk, yttre enheter som skrivare, primärminne och interna resurser som i/o-kanaler hanteras med olika strategier. 'Swap'-utrymme. Förhindrande genom förallokering är lämpligt. Undvikande är möjligt, men upptäckt och återstart går ju inte alls, eftersom 'swap'-utrymmet saknar 'back up'. Yttre enheter. Undvikande via 'precalaiming' är möjligt. Förhindrande via numrering också. Däremot är upptäckt återstart mycket olämpligt. Primärminne. Om vi använder 'swapping' är förhindrande genom att göra 'preempt' troligen det bästa valet. Undvikande ger för mycker 'overhead' för att vara attraktivt. Interna resurser. Eftersom dessa begärs och frisläpps relativt sett ofta, så är undvikande knappast tillrådligt. Ej heller upptäckt och återstart. Förhindrande via numrering är förmodligen bäst (det enda tänkbara?). Anmärkning: 'Spooling' kan mildra baklåsproblemet. När en/ett användare/program tror att den/det skriver på en yttre enhet (och därför "reserverar" den), så temporärskriver operativsystemts 'spooler' i stället data på en area på skivminnet. För varje enhet bildas köer av 'streams' som skriv ut tex enligt FIFO när enheten är ledig.
78 4.5. Processkoordination Schemaläggningen, processinteraktionen och baklåshanteringen måste ofta samplaneras. I detta avsnitt förutsätter vi en 'pre-emptive', hösta-prioritet-först-algoritm tex RMS. Inledningsvis anförs ett resultat avseende ett tillräckligt villkor för schemaläggning av cykliska processer med 'rate monotonic scheduling'. Sats. Ett system av periodiska processer {pr i }, i = 1,..., n, planerade under principen med prioritetstak kan schemaläggas (så att de utför hela sina respektive cykler med angiven frekvens) med RMS (pr 1 har högst och pr n har lägst prioritet) om för den sk 'utilization factor' U(n) gäller att U(n) Σ 1 i n c i /T i + max 1 i (n-1) {b i /T i } n(2 1/n - 1) där c i = exekveringstiden (i varje cykel) för pr i, T i = periodiciteten för pr i och där b i = den längsta blockerandetiden för pr i. Anmärkning. Om {pr i } inte samverkar blir b i = 0 för alla i. Ett viktigt specialfall av satsen. Notera också att lim n n(2 1/n - 1) = ln2 0.69 4.5.1. Prioritetsinversion Antag att pr1, pr2 och pr3 är tre processer med hög, medel respektive låg prioritet. Antag vidare att pr1 och pr3 innehåller kritiska avsnitt map samma kritiska resurser som "vaktas" av en semafor s. Om pr3 exekverar i sitt kritiska avsnitt och blir uppehållen ('pre-emption') pga pr1 blir redo så kommer pr1 att bli blockerad när pr1 önskar gå in i sitt kritiska avsnitt. Eftersom pr1 har högst prioritet skulle vi vilja att pr1 bleve blockerad högst så länge det krävs för pr3 att göra klart sitt kritiska avsnitt. Nu kan fördröjningen emellertid bli oförutsägbart lång pga att pr3 kan uppehållas ('pre-empt') av pr2. Den högst prioriterade processen pr1 kommer då att förbli blockerad till dess pr2 (och alla andra processer av mellanliggande prioriteter) är klara. Detta fenomen kallas prioritetsinversion (pi). Förslaget att förhindra pi genom att inte avbryta processer i kritiska avsnitt fungerar bara för korta kritiska avsnitt. Det skulle innebära att högt prioriterade processer stoppas pga att lägre prioriterade processser befinner sig i sina kritiska avsnitt och detta trots att processer med högre prioritet inte innehåller kritiska avsnitt (map samma resurs). 4.5.2. Prioritetstak Ett protokoll ('priority ceiling') som finns för detta ändamå har följande egenskaper. - frihet från baklås och - begränsad prioritetsinversion. Två idéer ligger bakom: - Prioritetsarv: När prx blockerar exekvering av en process med högre prioritet så ärver prx prioriteten för den process som har högst prioritet av de blockerade. - Ett kritiskt avsnitt tillåts börja endast om det utförs med högre prioritet än eventuellt uppehållna andra kritiska avsnitts. Dessa principer inducerar en total ordning (för att förhindra baklås) i utförandet av kritiska avsnitt.
79 Tekniskt sett associeras till varje semafor s ett prioritetstak som är lika med den högsta prioriteten för de processer som kan låsa s. När en process prx önskar utföra ett kritiskt avsnitt så kommer den att bli avstannad såvida inte dess prioritet är högre än prioritetstaket för alla de semaforer som är låsta av andra processer än prx. Om prx pga detta inte kan gå in i sitt kritiska avsnitt så säger vi att den process som håller låset blockerar prx och låter denna ärva prx:s prioritet. Så länge prx inte försöker gå in i ett kritiskt avsnitt så kan den uppehålla ('pre-empt') en process med lägre prioritet. Detta protokoll garanterar att en högt prioriterad process blockeras av högst en lägre process' kritiska avsnitt. Det förhindrar också baklås. Ett exempel illusterar. 4.5.3. Exempel Antag givet pr1:... p(s1)... p(s2)... v(s2)... v(s1)... ; med hög (H) prioritet. pr2:... p(s2)... p(s1)... v(s1)... v(s2)... ; med låg (L) prioritet. Båda semaforernas prioritetstak blir H. Antag att pr2 kommer först och låser s2 vid tiden t0. Vid t1 (> t0) kommer pr1 igång och avbryter/uppehåller pr2 och kommer så småningom vid t2 att vilja låsa s1. Eftersom pr1:s prioritet inte är högre än den låsta semaforens s2 prioritetstak kommer pr1 att uppehållas utan att låsa s1. Processen pr2 ärver nu pr1:s prioritet (H) och fortsätter exekvera. Observera att pr1 under tiden är blockerad utanför sitt kritiska avsnitt. Eftersom pr1 inte låser s1 så förhindras baklås mellan pr1 och pr2. Senare, vid t3, när pr2 lämnar sitt kritiska avsnitt och återfår sin ursprungliga prioritet kommer pr2 att omedelbart avbrytas/uppehållas av pr1. Därefter kommer pr1 att exekvera klart innan sedemera pr2 kommer att gå klar. Se figur 4.5. Vill gå in i krit. avsnitt Utför både cs1 och cs2 pr1 pr1 väntar för att förhindra baklås t0 t1 t2 t3 låser s2 låser s1 släpper s1 pr2 släpper s2 tid Figur 4.5 Ärvda prioritetstak
80 Repetition 1. Schemaläggning 2. Prestandamått 1. 'Dispatcher' 1. cpu untyttjande 2. 'Short term scheduler' 2. genomströmning 3. 'Medium term scheduler' 3. processtid 4. 'Long term scheduler' 4. väntetid 5. 'Spooler' 5. svarstid 3. Algoritmer 4. Baklås Prioriteter Villkor 1. Fix 1. Odelbarhet 2. Ändringsbar 2. Oavbrytbarhet 3. Dynamisk 3. Cirkularitet Ex: FCFS, SJF, RMS Metoder 'Round robin' 1. Förhindrande Tidskvantum q; tex resursnumrering cyklisk variant 2. Undvikande Tidsstyrd tex 'banker's' algoritm intervall 3. Upptäckt och återstart givna tidpunkter 4. Kombinationer eller intet 5. Samordning - prioritetsinversion - prioritetstak Lösning till problemet med begränsad buffert i Ada95 Anropas från en task (producent) med My_Buffer: BUFFERING;... My_Buffer.PUT (X);... protected type BUFFERING is entry PUT (x: in ITEM); entry GET (x: out ITEM); private N: constant := 4513; A: array (1..N) of ITEM; I, J: integer range 1.. N := 1; COUNT: integer range 0.. N := 0; end BUFFERING; protected body BUFFERING is entry PUT (x: in ITEM) when COUNT < N is begin A(I) := x; I := I mod N + 1; COUNT := COUNT + 1; end PUT; entry GET (x: out ITEM) when COUNT > 0 is begin x := A(J); J := J mod N + 1; COUNT := COUNT - 1; end GET end BUFFERING;