RTP Real-Time Programmatuur hoofdstuk 8: synchronisatie en communicatie met gedeelde variabelen Yolande Berbers Programmatuur voor real-time controle slide 1 RTP overzicht probleemstelling: producer - consumer probleem kritische sectie en conditionele synchronisatie oplossing 1: busy waiting, suspend/resume: zie boek oplossing 2: semaforen gebruik in POSIX oplossing 3: conditionele kritische secties oplossing 4: monitors gebruik in POSIX protected objects in Ada synchronized klassen in Java Yolande Berbers Programmatuur voor real-time controle slide 2 RTP Producer - Consumer Concurrent: … need buffer ... Yolande Berbers Programmatuur voor real-time controle slide 3 RTP Producer - Consumer Synchronization Unbounded Buffer Consumer: Wait if buffer empty Yolande Berbers Bounded Buffer Consumer: Wait if buffer empty Producer: Wait if buffer full Programmatuur voor real-time controle slide 4 RTP Producer - Consumer Circular buffer out out out in Yolande Berbers in in in in in Programmatuur voor real-time controle slide 5 RTP Producer - Consumer Circular buffer out in Yolande Berbers in in Programmatuur voor real-time controle slide 6 RTP Producer - Consumer Producer Consumer Item ip; Item ic; while (true) { while(true) { ip = produce(...); while (counter == 0) {} ic = buffer[out]; while (counter == n) {} buffer[in] = ip; out = (out + 1) % n; in = (in+1) % n; counter--; counter++; } consume(ic); } Yolande Berbers Programmatuur voor real-time controle slide 7 RTP Producer - Consumer counter++ counter-- Load Rp,counter Incr Rp Store Rp,counter Load Rc,counter Decr Rc Store Rc,counter Monoprocessor: Preemption between Load and Store Multiprocessor: Interleaving (Load before Load and Store) Yolande Berbers Programmatuur voor real-time controle slide 8 RTP Producer - Consumer COUNTER = 4 Load Incr Rp,COUNTER Rp Process Control Block (Producer) Load Rc,COUNTER Decr Rc Store Rc,COUNTER Rp=5 COUNTER = 3 Rp=5 Store Rp,COUNTER COUNTER = 5 Yolande Berbers Programmatuur voor real-time controle slide 9 RTP Producer - Consumer COUNTER = 4 COUNTER = 3 (incorrect) COUNTER = 4 (correct) COUNTER = 5 (incorrect) Race condition • # processes manipulate same data structure • outcome depends on execution order Yolande Berbers Programmatuur voor real-time controle slide 10 RTP Critical Section Problem { P0, P1, ...,Pn-1} with Pi process / thread code accessing shared variable = critical section At most one Pi executing in its critical section Process: Protocol Entry Critical Section (CS) ... Exit Remainder Section (RS) ... Yolande Berbers Programmatuur voor real-time controle slide 11 RTP Critical Section Problem Mutual Exclusion (Correctness) at most one process in its critical section Progress (Lifeness) only processes not in RS may participate decision not postponed indefinitely Bounded Waiting (Fairness) bound on # times surpassed Yolande Berbers Programmatuur voor real-time controle slide 12 RTP Cooperating Processes Cooperating Concurrent Processes (Threads): outcome may be not deterministic execution may be not reproducible (bugs …) stop / resume processes may affect outcome! Yolande Berbers Programmatuur voor real-time controle slide 13 RTP semaforen wat: eenvoudig laag-niveau mechanisme voor wederzijdse uitsluiting en conditionele synchronisatie hoe niet-negatieve geheel getal kan geïnitialiseerd worden 1 bij binaire semaforen gelijk welk positief getal bij tellende semaforen twee ondeelbare (atomaire) operaties zijn mogelijk wait(S) oorspronkelijk P(S) indien S > 0: verlaag S met 1, anders wacht tot S > 0 en verlaag dan signal (S) oorspronkelijk V(S) verhoog S met 1 mogelijke problemen: deadlock, verhongering Yolande Berbers Programmatuur voor real-time controle slide 14 RTP semaforen Dijkstra Yolande Berbers Programmatuur voor real-time controle slide 15 RTP semaforen Integer value 0 0 means CLOSED >0 means OPEN (Atomic) Operations: Initialization P (proberen) wait V (verhogen) signal Yolande Berbers Higher value: More open lock unlock Programmatuur voor real-time controle slide 16 RTP semaforen P(s) while (s == 0) { } WAIT s-- ; V(s) s++; C-Note: P and V are not procedure calls! Yolande Berbers Programmatuur voor real-time controle slide 17 RTP semaforen : gebruik kritische sectie Critical Section typedef semaphore int; semaphore s = 1; while (true) { P(& s); Critical Section … V(& s); Remainder section … } Yolande Berbers C-Note: P and V are defined as procedure calls! Programmatuur voor real-time controle slide 18 RTP semaforen : gebruik synchronisatie Synchronization Process 1 Process 2 … Action1 …(&s); V ... P (&s); Action2 ... semaphore s = 0 … Action1; V(&s); ... Yolande Berbers Programmatuur voor real-time controle … P(&s); Action2; ... slide 19 RTP semaforen : problemen deadlock semaphore s = 1; semaphore r = 1; P1 P(s); // s == 0 … P(r); Yolande Berbers vehongering possible if the queue is not a FIFO queue P2 … P(r); // r == 0 … P(s); Programmatuur voor real-time controle slide 20 RTP binaire semaforen Two states: lock (s) while (s == locked) { } s = locked; locked open unlock (s) s = open; locked Yolande Berbers open Note: unlock(s) when open = NOP Programmatuur voor real-time controle slide 21 RTP semaforen: producer-consumer … buffer … semaphore mutex = 1; semaphore full = N; semaphore empty = 0; Producer Consumer while (true) while (true) { { ip = produce (…); P (&empty); P (&full); CS P (&mutex); insert (buffer, ip); CS V (&mutex); V (&mutex); V (&full); consume (ic); V (&empty); } Yolande Berbers P (&mutex); ic = remove (buffer); } Programmatuur voor real-time controle slide 22 RTP semaforen: producer-consumer … buffer … semaphore mutex = 1; semaphore full = N; semaphore empty = 0; Producer Consumer while (true) { ip = produce (…); while (true) { P (&full); (&mutex); P (&full); P (&mutex); (&empty); P (&mutex); insert (buffer, ip); ic = remove (buffer); V (&mutex); V (&mutex); } Deadlock if full == 0 V (&full); consume (ic); V (&empty); } Yolande Berbers Programmatuur voor real-time controle slide 23 RTP ondersteuning voor semaforen Ada, Java geen directe ondersteuning in de taal gemakkelijk om een package/klasse te maken die het aanbiedt voor gebruik tussen taken 8.4.5: klassiek voorbeeld van producer/consumer in Ada C geen ondersteuning POSIX tellende semaforen tussen aparte processen en voor verschillende threads in een proces Yolande Berbers Programmatuur voor real-time controle slide 24 RTP POSIX semaforen standard operations for counting semaphores initialize, wait, signal typedef … sem_t; int sem_init (sem_t *sem_location, int pshared, unsigned int value); /* initializes the semaphore at location sem_location to value pshared determines if used between processes or threads or only between threads of the same process */ int sem_wait (sem_t *sem_location); /* a standard wait operation on a semaphore */ int sem_post (sem_t *sem_location); /* a standard signal operation on a semaphore */ Yolande Berbers Programmatuur voor real-time controle slide 25 RTP POSIX semaforen non-standard operations for counting sem. non-blocking wait, determining value of sem. int sem_trywait (sem_t *sem_location); /* attempts to decrement the semaphore returns -1 if the call might block the calling process */ int sem_getvalue (sem_t *sem_location, int *value); /* gets the current value of the semaphore to a location pointed at by value */ Yolande Berbers Programmatuur voor real-time controle slide 26 RTP nadelen van semaforen semaforen leiden gemakkelijk tot fouten (en zijn dus ongeschikt in real-time programmatuur) vergeet er 1 en het programma loopt fout heel moeilijk om te vinden waar precies wait of signal vergeten deadlock kan gemakkelijk optreden (misschien maar in heel weinig voorkomende gevallen, maar dat is juist moeilijk te testen) Yolande Berbers Programmatuur voor real-time controle slide 27 RTP conditionele kritische sectie wat: een code-segment met garantie voor uitvoering onder wederzijdse uitsluiting, en met mogelijkheid tot conditionele synchronisatie hoe: groepering van variabelen die beschermd moeten worden in code-segmenten (region) die een naam krijgen wachtercode (guard) mogelijk voor conditionele synchronisatie nadelen een proces dat wacht om binnen te treden moet, telkens er een ander proces uittreedt, actief gemaakt worden voor het testen van de wachtercode de code-segmenten kunnen ongestructureerd verspreid zijn over het programma Yolande Berbers Programmatuur voor real-time controle slide 28 RTP conditionele kritische sectie: voorbeeld process producer; ... loop region buf when buffer.size < N do -- plaats een character in de buffer end region ... end loop end process consumer ... loop region buf when buffer.size > 0 do -- neem een character uit de buffer end region ... end loop end Yolande Berbers Programmatuur voor real-time controle slide 29 RTP monitors wat gestructureerde manier om code-segmenten te schrijven met garantie voor uitvoering onder wederzijdse uitsluiting, en met mogelijkheid tot conditionele synchronisatie hoe module met een verzameling van kritische secties die elk als procedure of functie geschreven zijn module heet monitor alle variabelen die beschermd moeten worden zijn verborgen (information hiding) conditie variabelen voor conditionele synchronisatie wait: blokkeert altijd het uitvoerende proces signal: deblokkeert een wachtend proces indien er zo één is Yolande Berbers Programmatuur voor real-time controle slide 30 RTP monitor: voorbeeld monitor buffer; export append, take; const size = 32; var buf: array[0...suze-1] of integer; top, base : 0 .. size-1; SpaceAvailable, ItemAvailable : condition; NumberInBuffer : integer; procedure append (I : integer) ..... procedure take (var I : integer) ..... begin (* initialisatie *) NumberInBuffer := 0; top := 0; base := 0 end; Yolande Berbers Programmatuur voor real-time controle slide 31 RTP monitor: voorbeeld procedure append (I : integer); begin if (NumberInBuffer = size) then wait (SpaceAvailable); buf[top] := I; NumberInBuffer := NumberInBuffer + 1; top := (top + 1) mod size; signal (ItemAvailable); end append; procedure take (var I : integer); begin if (NumberInBuffer = 0) then wait (ItemAvailable); I := buf[base]; base := (base + 1) mod size; NumberInBuffer := NumberInBuffer - 1; signal (SpaceAvailable); end take; Yolande Berbers Programmatuur voor real-time controle slide 32 RTP monitors (commentaar bij voorbeeld) minstens 2 processen zijn betrokken één producent (maar het kunnen er meerdere zijn) één consument (maar het kunnen er meerdere zijn) processen kunnen geblokkeerd zijn omdat ze de monitor proberen binnen te gaan ze proberen append of take uit te voeren omdat ze wachten op een conditie er is bv geen plaats in de buffer of er zijn geen elementen in de buffer er is dus een mogelijke wachtrij voor de monitor zelf en voor elke conditievariabele Yolande Berbers Programmatuur voor real-time controle slide 33 RTP monitors monitor procedure condition var a function condition var b thread requesting monitor access thread executing in monitor Yolande Berbers Programmatuur voor real-time controle slide 34 RTP monitors welk proces mag (exclusief) uitvoeren na een signal ? proces dat signal uitvoert (proces dat een wait deed wacht nog even) proces dat een wait deed (proces dat de signal doet moet nu wachten) mogelijke semantiek voor signal signal mag alleen als laatse instructie voor verlaten van monitor zoals in het producer/consumer voorbeeld niet erg flexibel signal heeft als neven-effect een return (dus het uitvoerend proces wordt verplicht de monitor te verlaten) proces dat signal uitvoert blijft uitvoeren; proces dat gedeblokkeerd is moet daarna weer vechten om de monitor te mogen betreden proces dat de signal uitvoert blokkeert, en proces dat gedeblokkeerd werd mag direct uitvoeren Yolande Berbers Programmatuur voor real-time controle slide 35 RTP monitors voordeel van monitors gestructureerde manier voor het programmeren van wederzijdse uitsluiting nadeel van monitors laag-niveau manier voor het programmeren van conditionele synchronisatie Yolande Berbers Programmatuur voor real-time controle slide 36 RTP mutexes and condition variables in POSIX wederzijdse uitluiting: aan elke monitor koppelt men een mutex variabele operaties van monitor moeten omringd worden door oproepen lock en unlock van mutex conditie synchronizatie: door conditievariabelen gekoppeld aan mutex thread wacht op conditievariabele: lock op geassocieerde mutex komt vrij thread hervat na wachten op conditievariabele: thread heeft lock weer Yolande Berbers Programmatuur voor real-time controle slide 37 RTP mutexes and condition variables in POSIX int pthread_mutex_init (pthread_mutex_t *mutex, const pthread_mutexattr_t *attr); /* initializes a mutex with certain attributes */ int pthread_mutex_lock (pthread_mutex_t *mutex); /* lock the mutex; if already locked suspend calling thread the owner of the mutex is the thread which locked it */ int pthread_mutex_unlock (pthread_mutex_t *mutex); /* unlock the mutex if called by the owning thread undefined behavior if the calling thread is not the owner undefined behavior if the mutex is not locked when successful, results in release of a blocked thread */ Yolande Berbers Programmatuur voor real-time controle slide 38 RTP mutexes and condition variables in POSIX int pthread_cond_init (pthread_cond_t *cond, const pthread_condattr_t *attr); /* initializes a condition variable with certain attributes */ int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); /* called by thread which owns a locked mutex (undefined behavior if the mutex is not locked) atomically blocks the calling thread on the cond variable and releases the lock on mutex a successful return indicates that the mutex has been locked */ int pthread_cond_signal (pthread_cond_t *cond); /* unblocks at least 1 blocked thread; no effect if no threads are blocked; unblocked threads automatically contend for the associated mutex /* Yolande Berbers Programmatuur voor real-time controle slide 39 RTP mutexes and condition variables in POSIX int pthread_mutex_trylock (pthread_mutex_t *mutex); /* the same as lock but gives error return if mutex already locked */ int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const st’ruct timespec *abstime); /* the same as pthread_cond_wait, except that an error is returned if the timeout expires */ Yolande Berbers Programmatuur voor real-time controle slide 40 RTP mutexes and condition variables in POSIX: producer-consumer example: bounded buffer consisting of mutex two condition variables (buffer_not_full and buffer_not_empty) a count of number of elements the buffer itself the positions of first and last items in buffer routine ‘append’ routine ‘take’ Yolande Berbers Programmatuur voor real-time controle slide 41 RTP mutexes and condition variables in POSIX: producer-consumer note: lighter notation for calls in POSIX error conditions from POSIX: return -1 for reliability: every call to system function should test the return value in book: macro #define SYS_CALL (A) if (sys_call(A) != 0) error() /* where error is function which undertakes some error processing */ Yolande Berbers Programmatuur voor real-time controle slide 42 RTP mutexes and condition variables in POSIX: producer-consumer # include “pthreads.h” # define BUFF_SIZE 10 typedef struct { pthread_mutex_t mutex; pthread_cond_t buffer_not_full; pthread_cond_t buffer_not_empty; int count, first, last; int buf [BUFF_SIZE]; } buffer; /* an initialize routine is required */ Yolande Berbers Programmatuur voor real-time controle slide 43 RTP mutexes and condition variables in POSIX: producer-consumer int append (int item, buffer *B) { PTHREAD_MUTEX_LOCK (&B->mutex); while (B->count == BUFF_SIZE) PTHREAD_COND_WAIT (&B->buffer_not_full, &B->mutex); /* put data in buffer and update count and last */ PTHREAD_MUTEX_UNLOCK (&B->mutex); PTHREAD_COND_SIGNAL (&B->buffer_not_empty); return 0; } Yolande Berbers Programmatuur voor real-time controle slide 44 RTP mutexes and condition variables in POSIX: producer-consumer int take (int *item, buffer *B) { PTHREAD_MUTEX_LOCK (&B->mutex); while (B->count == 0) PTHREAD_COND_WAIT (&B->buffer_not_empty, &B->mutex); /* get data from buffer and update count and first */ PTHREAD_MUTEX_UNLOCK (&B->mutex); PTHREAD_COND_SIGNAL (&B->buffer_not_full); return 0; } Yolande Berbers Programmatuur voor real-time controle slide 45 RTP protected objects (enkel in Ada) wat: gestructureerde manier voor het programmeren van code-segmenten met garantie voor uitvoering onder wederzijdse uitsluiting conditionele synchronisatie hoe analoog aan monitors (genoemd protected type) voor wederzijdse uitsluiting maar meerdere lezers enkelvoudige schrijvers mogelijk analoog aan conditionele kritische secties (gebruik van barriers (guard) bij entries) voor conditionele synchronisatie entry is analoog aan procedure, maar kan slechts uitgevoerd worden indien aan de barrier voldaan is oproepen van entry zoals van een procedure Yolande Berbers Programmatuur voor real-time controle slide 46 RTP protected objects een protected body heeft een specificatie een body kunnen voorzien worden in de specificatie entries: dit zijn procedures die voorzien zijn van een conditie voorwaarde voor uitvoeren: niemand voert het protected object uit en de conditie is waar procedures: zijn niet voorzien van een conditie voorwaarde voor uitvoeren: niemand voert protected object uit functies: zijn niet voorzien van een conditie voorwaarde voor uitvoeren: niemand of alleen andere functies voeren protected object uit (dit implementeert meerdere lezers) Yolande Berbers Programmatuur voor real-time controle slide 47 RTP Write Access to Protected Object protected object function procedure barrier queue entry task requesting read/write access task requesting read access task executing with read/write access task executing with read access Yolande Berbers Programmatuur voor real-time controle slide 48 RTP Read Access to Protected Object protected object function procedure barrier queue entry task requesting read/write access task requesting read access task executing with read/write access task executing with read access Yolande Berbers Programmatuur voor real-time controle slide 49 RTP protected object: voorbeeld 1 protected type Shared_Integer (Initial_Value: Integer) is function read return Integer; procedure Write (New_Value: Integer); procedure Increment (By: Integer); private The_Data : Integer := Initial_Value; end Shared_Integer; My_Data: Shared_Integer(42); Yolande Berbers Programmatuur voor real-time controle slide 50 RTP protected object: voorbeeld 1 protected body Shared_Integer is function Read return Integer is begin return The_Data; end Read; procedure Write (New_Value: Integer) is begin The_Data := New_Value; end Write; procedure Increment (By: Integer) is begin The_Data := The_Data + By; end Increment; end Shared_Integer; Yolande Berbers Programmatuur voor real-time controle slide 51 RTP protected object: voorbeeld 2 Buffer_Size : constant Integer := 10; type Index is mod Buffer_Size; subtype Count is Natural range 0 .. Buffer_Size; type Buffer is array (Index) of Data_Item; protected type Bounded_Buffer is entry Get (Item: out Data_Item); entry Put (Item: in Data_Item); private First : Index := Index’First; Last : Index := Index’Last; Number_In_Buffer : Count := 0; Buf : Buffer; end Bounded_Buffer; My_Buffer: Bounded_Buffer; Yolande Berbers Programmatuur voor real-time controle slide 52 RTP protected object: voorbeeld 2 protected body Bounded_Buffer is entry Get (Item: out Data_Item) when Number_In_Buffer > 0 is begin Item := Buf(First); First := First + 1; Number_In_Buffer := Number_In_Buffer - 1; end Get; entry Put (Item: in Data_Item) when Number_In_Buffer < Buffer_Size is begin Last := Last + 1; Buf(Last) := Item; Number_In_Buffer := Number_In_Buffer + 1; end Put; end Bounded_Buffer; Yolande Berbers Programmatuur voor real-time controle slide 53 RTP protected object: voorbeeld 3 protected Resource_Control is entry Allocate; procedure Deallocate; private Free : Boolean := True; end Resource_Control; protected body Resource_Control is entry Allocate when Free is begin Free := False; end Allocate; procedure Deallocate is begin Free := True; end Deallocate; end Resource_Control ; Yolande Berbers Programmatuur voor real-time controle slide 54 RTP protected object: voorbeeld 4 een taak wil een boodschap sturen naar andere taken die hierop wachten indien er geen wachtende taken zijn wordt er geen boodschap achtergelaten protected type Broadcast is entry Receive (M: out Message); procedure Send (M: Message); private New_Message : Message; Message_Arrived : Boolean := False; end Broadcast ; Yolande Berbers Programmatuur voor real-time controle slide 55 RTP protected object: voorbeeld 4 protected body Broadcast is entry Receive (M: out Message) when Message_Arrived is begin M := New_Message; if Receive’Count = 0 then Message_Arrived := False; end if; end Receive; procedure Send (M: Message) is begin if Receive’Count > 0 then Message_Arrived := True; New_Message := M; end if; end Send; end Broadcast ; Yolande Berbers Programmatuur voor real-time controle slide 56 RTP protected object: voorbeeld 5 pakket dat semaforen aanbiedt, geïmplementeerd met behulp van een protected object package Semaphore_Package is type Semaphore (Initial : Natural := 1) is limited private; procedure Wait (S: in out Semaphore); procedure Signal (S: in out Semaphore); private protected type Semaphore (Initial : Natural := 1) is entry Wait_Imp; procedure Signal_Imp; private Value: Natural := Initial; end Semaphore ; end Semaphore_Package ; Yolande Berbers Programmatuur voor real-time controle slide 57 RTP protected object: voorbeeld 5 package body Semaphore_Package is protected body Semaphore is entry Wait_Imp when Value > 0 is begin Value := Value - 1; end Wait_Imp; procedure Signal_Imp is begin Value := Value + 1; procedure Wait (S: in out Semaphore); end Signal_Imp; begin S.Wait_Imp end Semaphore; end Wait; procedure Signal (S: in out Semaphore); begin S.Signal_Imp end Signal; end Semaphore_Package ; end Semaphore_Package ; Yolande Berbers Programmatuur voor real-time controle slide 58 RTP Synchronization in Java Comparable to monitor with 1 condition variable Unsynchronised methods Object Ma Ma Ma Ms Ms Synchronised methods Yolande Berbers Object Mb Ma Waiting Queue Ms Waiting to acquire the lock Programmatuur voor real-time controle Called wait(); slide 59 RTP Synchronization in Java Object Ma Mb wait() Ms Waiting Queue Mt Yolande Berbers Programmatuur voor real-time controle slide 60 RTP Synchronization in Java Object Ma Mb Ms notify() Waiting Queue Mt Yolande Berbers Programmatuur voor real-time controle slide 61 RTP Synchronization in Java class BoundedBuffer { ... public synchronized void put (int item) { ...} public synchronized int get () { … } public int countBuffer () { … } // returns # of items in buffer ... } Synchronized: • unique lock (mutex) with each instance of that class • synchronized method in Critical Section • start of method: lock • end of method: unlock • locking/unlocking atomically Yolande Berbers Programmatuur voor real-time controle slide 62 RTP Synchronization in Java class ReentrantClass { ... public synchronized void a () { …; b(); … } public synchronized void b () { … } ... } Java locks: • re-entrant • thread can reacquire a lock it already holds Yolande Berbers Programmatuur voor real-time controle slide 63 RTP Synchronization in Java class PartlySynchronizedClass { ... public void c () { …; synchronized (this) { … CS … } ... } ... } Yolande Berbers Only part of method is synchronized Programmatuur voor real-time controle slide 64 RTP Synchronization in Java class PartlySynchronizedClass { ... public void d () { …; synchronized (obj) { … CS … } ... } ... } Yolande Berbers Synchronize on another object Programmatuur voor real-time controle slide 65 RTP Synchronization in Java Object.wait() Only if Thread relinquishes the lock owns lock! waits for a notification resumes when a) notified and b) lock is reacquired Object.wait (long timeout) Object.wait (long timeout, int nanoseconds) Object.notify() notifies one thread waiting on that object Object.notifyAll() notifies all threads waiting on that object Yolande Berbers Programmatuur voor real-time controle slide 66 RTP Condition Variables Java: no explicit condition variables awoken thread usually evaluates condition on which it is waiting public class BoundedBuffer { private int buffer[]; private int first; private int last; private int numberInBuffer = 0; private int size; public BoundedBuffer(int length) { size = length; buffer = new int[size]; last = 0; first = 0; }; Yolande Berbers Programmatuur voor real-time controle slide 67 public synchronized void put(int item) throws InterruptedException { if (numberInBuffer == size) { wait(); bij consumer-producer geen while nodig }; last = (last + 1) % size ; // % is modulus numberInBuffer++; buffer[last] = item; notify(); }; public synchronized int get() throws InterruptedException { if (numberInBuffer == 0) { wait(); bij consumer-producer geen while nodig }; first = (first + 1) % size ; // % is modulus numberInBuffer--; notify(); return buffer[first]; }; }