se350 operating systems
play

SE350: Operating Systems Lecture 7: Synchronization API Outline - PowerPoint PPT Presentation

SE350: Operating Systems Lecture 7: Synchronization API Outline Semaphores Monitors Mesa vs. Hoare Communicating sequential process Use cases Bounded buffer Reader writer lock Recap: Locks Using Interrupts int value =


  1. Condition Variables Operations • wait(Lock *lock) • Atomically release lock and relinquish processor • Reacquire the lock when wakened • signal() • Wake up a waiter, if any • broadcast() • Wake up all waiters, if any

  2. Properties of Condition Variables • Condition variables are memoryless • No internal memory except a queue of waiting threads • No effect in calling signal/broadcast on empty queue • ALWAYS hold lock when calling wait(), signal(), broadcast() • In Birrell paper, he says you can call signal() outside of lock – IGNORE HIM (this is only an optimization) • Calling wait() atomically adds thread to wait queue and releases lock • Re-enabled waiting threads may not run immediately • No atomicity between signal/broadcast and the return from wait

  3. Condition Variable Design Pattern method_that_waits() { method_that_signals() { lock.acquire(); lock.acquire(); // Read/write shared state // Read/write shared state while (!testSharedState()) // If testSharedState is now true cv.wait(&lock); cv.signal(); // Read/write shared state // Read/write shared state lock.release(); lock.release(); } }

  4. Bounded Buffer Implementation with Monitors Lock lock; CV emptyCV, fullCV; produce(item) { lock.acquire(); // get lock while (queue.size() == MAX) // wait until there is fullCV.wait(&lock); // space queue.enqueue(item); emptyCV.signal(); // signal waiting costumer lock.release(); // release lock } consume() { lock.acquire(); // get lock while (queue.isEmpty()) // wait until there is item emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); // signal waiting producer lock.release(); // release lock return item; }

  5. Question • Does k th call to consume() return item put by k th call to produce() ? • No! thread calling wait() must re-acquire lock after waking up; before woken-up thread re-acquire lock, a newly arrived thread could acquire lock and consume item

  6. Mesa vs. Hoare Monitors • Consider piece of consume() code while (queue.isEmpty()) emptyCV.wait(&lock); • Why didn’t we do this? if (queue.isEmpty()) emptyCV.wait(&lock); • Answer: it depends on the type of scheduling • Hoare-style • Mesa-style

  7. Hoare Monitors • Signaler gives up lock and processor to waiter – waiter runs immediately • Waiter gives up lock and processor back to signaler when it exits critical section or if it waits again … lock.acquire() lock.acquire() … … if (queue.isEmpty()) lock & CPU dataready.signal(); emptyCV.wait(&lock); … … lock & CPU lock.release(); lock.release();

  8. Mesa Monitors • Signaler keeps lock and processor • Waiter placed on ready queue with no special priority • Practically, need to check condition again after wait • Most real operating systems Put waiting thread … lock.acquire() on ready queue lock.acquire() … … while (queue.isEmpty()) dataready.signal(); emptyCV.wait(&lock); … … g n i t i a w e u l lock.release(); d lock.release(); e h c s d a e r h t

  9. Mesa Monitor: Why “ while() ”? • What if we use “ if ” instead of “ while ” in bounded buffer example? consume() { produce(item) { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.size() == MAX) emptyCV.wait(&lock); fullCV.wait(&lock); item = queue.dequeue(); queue.enqueue(item); fullCV.signal(); emptyCV.signal(); lock.release(); lock.release(); return item; } } Use “ if ” instead of “ while ”

  10. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: T1 queue emptyCV queue → NULL ready queue → NULL … T1 (Running) consume() { lock.acquire(); if (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  11. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T1) Running: T1 queue emptyCV queue → NULL ready queue → NULL … T1 (Running) consume() { lock.acquire(); if (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  12. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: queue emptyCV queue → T1 ready queue → NULL … wait(&lock) puts thread T1 (Waiting) on emptyCV queue and consume() { releases lock lock.acquire(); if (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  13. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: T2 queue emptyCV queue → T1 ready queue → NULL … T1 (Waiting) T2 (Running) consume() { produce(item) { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.size()==MAX) emptyCV.wait(&lock); fullCV.wait(&lock); item = queue.dequeue(); queue.enqueue(item); fullCV.signal(); emptyCV.signal(); lock.release(); lock.release(); return item; } }

  14. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T2) Running: T2 queue emptyCV queue → T1 ready queue → NULL … T1 (Waiting) T2 (Running) consume() { produce(item) { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.size()==MAX) emptyCV.wait(&lock); fullCV.wait(&lock); item = queue.dequeue(); queue.enqueue(item); fullCV.signal(); emptyCV.signal(); lock.release(); lock.release(); return item; } }

  15. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T2) Running: T2 queue emptyCV queue → NULL ready queue → T1 … T1 (Ready) T2 (Running) signal() wakes up and consume() { produce(item) { moves it to ready queue lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.size()==MAX) emptyCV.wait(&lock); fullCV.wait(&lock); item = queue.dequeue(); queue.enqueue(item); fullCV.signal(); emptyCV.signal(); lock.release(); lock.release(); return item; } }

  16. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T2) Running: T2 queue emptyCV queue → NULL ready queue → T1, T3 … T1 (Ready) T2 (Running) T3 (Ready) consume() { produce(item) { consume() { lock.acquire(); lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.size()==MAX) if (queue.isEmpty()) emptyCV.wait(&lock); fullCV.wait(&lock); emptyCV.wait(&lock); item = queue.dequeue(); queue.enqueue(item); item = queue.dequeue(); fullCV.signal(); emptyCV.signal(); fullCV.signal(); lock.release(); lock.release(); lock.release(); return item; } return item; } }

  17. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: queue emptyCV queue → NULL ready queue → T1, T3 … T2 (Terminated) T1 (Ready) T3 (Ready) consume() { produce(item) { consume() { lock.acquire(); lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.size()==MAX) if (queue.isEmpty()) emptyCV.wait(&lock); fullCV.wait(&lock); emptyCV.wait(&lock); item = queue.dequeue(); queue.enqueue(item); item = queue.dequeue(); fullCV.signal(); emptyCV.signal(); fullCV.signal(); lock.release(); lock.release(); lock.release(); return item; } return item; } }

  18. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: T3 queue emptyCV queue → NULL ready queue → T1 … T1 (Ready) T3 (Running) T3 is scheduled first consume() { consume() { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.isEmpty()) emptyCV.wait(&lock); emptyCV.wait(&lock); item = queue.dequeue(); item = queue.dequeue(); fullCV.signal(); fullCV.signal(); lock.release(); lock.release(); return item; return item; } }

  19. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T3) Running: T3 queue emptyCV queue → NULL ready queue → T1 … T1 (Ready) T3 (Running) consume() { consume() { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.isEmpty()) emptyCV.wait(&lock); emptyCV.wait(&lock); item = queue.dequeue(); item = queue.dequeue(); fullCV.signal(); fullCV.signal(); lock.release(); lock.release(); return item; return item; } }

  20. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T3) Running: T3 queue emptyCV queue → NULL ready queue → T1 … T1 (Ready) T3 (Running) consume() { consume() { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.isEmpty()) emptyCV.wait(&lock); emptyCV.wait(&lock); item = queue.dequeue(); item = queue.dequeue(); fullCV.signal(); fullCV.signal(); lock.release(); lock.release(); return item; return item; } }

  21. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: queue emptyCV queue → NULL ready queue → T1 … T1 (Ready) T3 (Terminated) consume() { consume() { lock.acquire(); lock.acquire(); if (queue.isEmpty()) if (queue.isEmpty()) emptyCV.wait(&lock); emptyCV.wait(&lock); item = queue.dequeue(); item = queue.dequeue(); fullCV.signal(); fullCV.signal(); lock.release(); lock.release(); return item; return item; } }

  22. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T1) Running: T1 queue emptyCV queue → NULL ready queue → NULL … T1 (Running) consume() { lock.acquire(); if (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  23. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T1) Running: T1 queue emptyCV queue → NULL ready queue → NULL … T1 (Running) consume() { lock.acquire(); Error! if (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  24. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: BUSY (T1) Running: T1 queue emptyCV queue → NULL ready queue → NULL … T1 (Running) Check again if consume() { empty! lock.acquire(); while (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  25. Mesa Monitor: Why “ while() ”? (cont.) App. Shared State Monitor CPU State lock: FREE Running: queue emptyCV queue → T1 ready queue → NULL … T1 (Waiting) consume() { lock.acquire(); while (queue.isEmpty()) emptyCV.wait(&lock); item = queue.dequeue(); fullCV.signal(); lock.release(); return item; }

  26. Mesa Monitor: Why “ while() ”? (cont.) When waiting upon a Condition , a spurious wakeup is permitted to occur, in general, as a concession to the underlying platform semantics. This has little practical impact on most application programs as a Condition should always be waited upon in a loop, testing the state predicate that is being waited for From Java User Manual

  27. Condition Variable vs. Semaphore • CV’s signal() has no memory • If signal() is called before wait() , then signal is waisted • Semaphore’s V() has memory • If V() is called before P() , P() will not wait • Generally, it’s better to use monitors but not always • Example: interrupt handlers • Shared memory is read/written concurrently by HW and kernel • HW cannot use SW locks • Kernel thread checks for data and calls wait() if there is no data • HW write to shared memory, starts interrupt handler to then call signal() • This is called naked notify because interrupt handler doesn’t hold lock (why?) • This may not work if signal comes before kernel thread calls wait • Common solution is to use semaphores instead

  28. Implementing Condition Variable using Semaphores (Take 1) wait(lock) { lock.release(); semaphore.P(); lock.acquire(); } signal() { semaphore.V(); } • Does this work? • No! signal() should not have memory!

  29. Implementing Condition Variable using Semaphores (Take 2) wait(lock) { lock.release(); semaphore.P(); lock.acquire(); } signal() { if (semaphore’s queue is not empty) semaphore.V(); } • Does this work? • No! For one, not legal to look at contents of semaphore’s queue. • But also, releasing lock and going to sleep should happen atomically – signaler can slip in after lock is released, and before waiter is put on wait queue, which means waiter never wakes up!

  30. Implementing Condition Variable using Semaphores (Take 3) Key idea: have separate semaphore for each waiting thread and put semaphores in ordered queue wait(lock) { semaphore = new Semaphore; // a semaphore per waiting thread queue.enqueue(semaphore); // queue for waiting threads lock.release(); semaphore.P(); lock.acquire(); } signal() { if (!queue.isEmpty()) { semaphore = queue.dequeu() semaphore.V(); } }

  31. Readers/Writers Lock W W R R • Motivation: consider shared database with two classes of users • Readers: never modify database • Writers: read and modify database • Database can have many readers at the same time • But there can be only one writer active at a time

  32. Properties of Readers/Writers Lock • Common variant of mutual exclusion • One writer at a time, if no readers • Many readers, if no writer Thread 2 Writer Reader Thread 1 Writer NO! NO! Reader NO! OK! OK! • Correctness constraints • Readers can read when no writers • Writers can read/write when no readers or writers • Only one thread manipulates state of the lock at a time

  33. Readers/Writers Lock Class class ReadWriteLock { private: Lock lock; // needed to change state vars CV okToRead // CV for readers CV okToWrite; // CV for writers int AW = 0; // # of active writers int AR = 0; // # of active readers int WW = 0; // # of waiting writers int WR = 0; // # of waiting readers public: void acquireRL(); void releaseRL(); void acquireWL(); void releaseWL(); }

  34. Readers/Writers Lock Design Pattern read() { write() { lock.acquireRL(); lock.acquireWL(); // Read shared state // Read/write shared state lock.releaseRL(); lock.releaseWL(); } }

  35. Readers/Writers Lock Implementation acquireRL() { lock.acquire(); // Need lock to change state vars while (AW + WW > 0) { // Is it safe to read? WR++; // No! add to # of waiting readers okToRead.wait(&lock); // Wait on condition variable WR--; // No longer waiting } AR++; // Now we are active again lock.release(); } Why release lock here? releaseRL() { lock.acquire(); AR--; // No longer active if (AR == 0 && WW > 0) // If no active reader, okToWrite.signal(); // wake up waiting writer lock.release(); } Lock is acquired to change internal state of R/W lock

  36. Readers/Writers Lock Implementation (cont.) acquireWL() { lock.acquire(); while (AW + AR > 0) { // is it safe to write? WW++; // No! add to # of waiting writers okToWrite.wait(&lock); // Wait on condition variable WW--; // No longer waiting } AW++; // Now we are active again lock.release(); } releaseWL() { lock.acquire(); AW--; // No longer active if (WW > 0) { // Give priority to writers okToWrite.signal(); // Wake up a waiting writer } else if (WR > 0) { // If there are waiting readers, okToRead.broadcast(); // wake them all up } lock.release(); }

  37. Simulation of Readers/Writers Lock • Consider following sequence of arrivals: R1, R2, W1, R3 read() { write() { lock.acquire(); lock.acquire(); while (AW + WW > 0) { while (AW + AR > 0) { WR++; WW++; okToRead.wait(&lock); okToWrite.wait(&lock); WR--; WW--; } } AR++; AW++; lock.release(); lock.release(); // Read // Read and Write lock.acquire(); lock.acquire(); AR--; AW--; if (AR == 0 && WW > 0) okToWrite.signal(); if (WW > 0) { lock.release(); okToWrite.signal(); } } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  38. Simulation of Readers/Writers Lock • R1 comes – AR = 0, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  39. Simulation of Readers/Writers Lock • R1 comes – AR = 0, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  40. Simulation of Readers/Writers Lock • R1 comes – AR = 0, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  41. Simulation of Readers/Writers Lock • R1 comes – AR = 1, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  42. Simulation of Readers/Writers Lock • R1 comes – AR = 1, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  43. Simulation of Readers/Writers Lock • R1 comes – AR = 1, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  44. Simulation of Readers/Writers Lock • R2 comes – AR = 1, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  45. Simulation of Readers/Writers Lock • R2 comes – AR = 1, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  46. Simulation of Readers/Writers Lock • R2 comes – AR = 1, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  47. Simulation of Readers/Writers Lock • R2 comes – AR = 2, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  48. Simulation of Readers/Writers Lock • R2 comes – AR = 2, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  49. Simulation of Readers/Writers Lock • R2 comes – AR = 2, WR = 0, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); } Assume readers take a while to access database Situation: Locks released, only AR is non-zero

  50. Simulation of Readers/Writers Lock • W1 comes – AR = 2, WR = 0, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  51. Simulation of Readers/Writers Lock • W1 comes – AR = 2, WR = 0, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  52. Simulation of Readers/Writers Lock • W1 comes – AR = 2, WR = 0, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  53. Simulation of Readers/Writers Lock • W1 comes – AR = 2, WR = 0, AW = 0, WW = 1 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  54. Simulation of Readers/Writers Lock • W1 comes – AR = 2, WR = 0, AW = 0, WW = 1 write() { lock.acquire(); while (AW + AR > 0) { WW++; W1 cannot start because of readers, so okToWrite.wait(&lock); it releases lock and goes to sleep WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  55. Simulation of Readers/Writers Lock • R3 comes – AR = 2, WR = 0, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  56. Simulation of Readers/Writers Lock • R3 comes – AR = 2, WR = 0, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  57. Simulation of Readers/Writers Lock • R3 comes – AR = 2, WR = 0, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  58. Simulation of Readers/Writers Lock • R3 comes – AR = 2, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  59. Simulation of Readers/Writers Lock • R3 comes – AR = 2, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); Status: while (AW + WW > 0) { WR++; • R1 and R2 still reading okToRead.wait(&lock); • W1 and R3 waiting on okToWrite WR--; } and okToRead , respectively AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  60. Simulation of Readers/Writers Lock • R2 is done reading – AR = 2, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  61. Simulation of Readers/Writers Lock • R2 is done reading – AR = 1, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  62. Simulation of Readers/Writers Lock • R2 is done reading – AR = 1, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  63. Simulation of Readers/Writers Lock • R2 is done reading – AR = 1, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  64. Simulation of Readers/Writers Lock • R1 is done reading – AR = 1, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  65. Simulation of Readers/Writers Lock • R1 is done reading – AR = 0, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  66. Simulation of Readers/Writers Lock • R1 is done reading – AR = 0, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  67. Simulation of Readers/Writers Lock • R1 is done reading – AR = 0, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; All readers are finished, R1 signals lock.release(); waiting writer – note, R3 is still waiting // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  68. Simulation of Readers/Writers Lock • R1 is done reading – AR = 0, WR = 1, AW = 0, WW = 1 read() { lock.acquire(); while (AW + WW > 0) { WR++; okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

  69. Simulation of Readers/Writers Lock • W1 gets a signal – AR = 0, WR = 1, AW = 0, WW = 1 write() { lock.acquire(); while (AW + AR > 0) { WW++; W1 gets signal from R1 okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  70. Simulation of Readers/Writers Lock • W1 gets a signal – AR = 0, WR = 1, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  71. Simulation of Readers/Writers Lock • W1 gets a signal – AR = 0, WR = 1, AW = 1, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  72. Simulation of Readers/Writers Lock • W1 gets a signal – AR = 0, WR = 1, AW = 1, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  73. Simulation of Readers/Writers Lock • W1 gets a signal – AR = 0, WR = 1, AW = 1, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  74. Simulation of Readers/Writers Lock • W1 is done – AR = 0, WR = 1, AW = 1, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  75. Simulation of Readers/Writers Lock • W1 is done – AR = 0, WR = 1, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  76. Simulation of Readers/Writers Lock • W1 is done – AR = 0, WR = 1, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  77. Simulation of Readers/Writers Lock • W1 is done – AR = 0, WR = 1, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  78. Simulation of Readers/Writers Lock • W1 is done – AR = 0, WR = 1, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { No waiting writer, so okToRead.broadcast(); only signal R3 } lock.release(); }

  79. Simulation of Readers/Writers Lock • W1 is done – AR = 0, WR = 1, AW = 0, WW = 0 write() { lock.acquire(); while (AW + AR > 0) { WW++; okToWrite.wait(&lock); WW--; } AW++; lock.release(); // Read and Write lock.acquire(); AW--; if (WW > 0) { okToWrite.signal(); } else if (WR > 0) { okToRead.broadcast(); } lock.release(); }

  80. Simulation of Readers/Writers Lock • R3 gets a signal – AR = 0, WR = 1, AW = 0, WW = 0 read() { lock.acquire(); while (AW + WW > 0) { WR++; R3 gets signal from W3 okToRead.wait(&lock); WR--; } AR++; lock.release(); // Read lock.acquire(); AR--; if (AR == 0 && WW > 0) okToWrite.signal(); lock.release(); }

Recommend


More recommend