Race Condition in Mesa Monitor


global volatile RingBuffer queue;  global Lock queueLock;       global CV queueEmptyCV;      global CV queueFullCV;  public method producer() {     while (true) {         task myTask = ...; // Producer makes some new task to be added.         queueLock.acquire();          while (queue.isFull()) { //####             wait(queueLock, queueFullCV);         }         queue.enqueue(myTask);         signal(queueEmptyCV); -- OR -- notifyAll(queueEmptyCV);                  queueLock.release();      } }  public method consumer() {     while (true) {         queueLock.acquire();          while (queue.isEmpty()) {              wait(queueLock, queueEmptyCV);         }         myTask = queue.dequeue();          signal(queueFullCV); -- OR -- notifyAll(queueFullCV); //###          queueLock.release();          doStuff(myTask); // Go off and do something with the task.     } } 

This is from https://en.wikipedia.org/wiki/Monitor_(synchronization). I have tried a lot but I cannot understand that when notifyAll(queueFullCV) is called at //### why is there not a race condition in while loop of //####. I can easily see many treads taking off and then, since while (queue.isFull()) is false at that instant, go and queue.enqueue(myTask) more than capacity.

//OR//

Can only one tread at a time acquire the queueLock, and after one queue.enqueue(myTask), when the other’s turn comes while (queue.isFull()) is full and then go back to sleep again? In that case, what is the need for notifyAll(queueFullCV) when only one tread would get the queueLock?