
Review: Monitor with Condition Variables CS162 Operating Systems and Systems Programming Lecture 9 Synchronization, Readers/Writers example, Scheduling • Lock: the lock provides mutual exclusion to shared data – Always acquire before accessing shared data structure September 26th, 2016 – Always release after finishing with shared data – Lock initially free Prof. Anthony D. Joseph • Condition Variable: a queue of threads waiting for something inside a http://cs162.eecs.Berkeley.edu critical section – Key idea: make it possible to go to sleep inside critical section by atomically releasing lock at time we go to sleep – Contrast to semaphores: Can’t wait inside critical section 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.2 Review: Condition Variables Review: Mesa vs. Hoare Monitors • How do we change the RemoveFromQueue() routine to wait until • Need to be careful about precise definition of signal and wait. something is on the queue? Consider a piece of our dequeue code: – Could do this by keeping a count of the number of things on the queue while=(queue.isEmpty())={ dataready.wait(&lock);=//=If=nothing,=sleep (with semaphores), but error prone } • Condition Variable: a queue of threads waiting for something inside a item===queue.dequeue(); //=Get=next=item critical section – Why didn’t we do this? – Key idea: allow sleeping inside critical section by atomically releasing if=(queue.isEmpty())={ lock at time we go to sleep dataready.wait(&lock);=//=If=nothing,=sleep } – Contrast to semaphores: Can’t wait inside critical section item===queue.dequeue(); //=Get=next=item • Operations: • Answer: depends on the type of scheduling – Wait(&lock): Atomically release lock and go to sleep. Re-acquire – Hoare-style (most textbooks): lock later, before returning. » Signaler gives lock, CPU to waiter; waiter runs immediately – Signal(): Wake up one waiter, if any » Waiter gives up lock, processor back to signaler when it exits critical section or if it waits again – Broadcast(): Wake up all waiters – Mesa-style (most real operating systems): • Rule: Must hold lock when doing condition variable ops! » Signaler keeps lock and processor – In Birrell paper, he says can perform signal() outside of lock – » Waiter placed on ready queue with no special priority IGNORE HIM (this is only an optimization) » Practically, need to check condition again after wait 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.3 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.4 Extended Example: Readers/Writers Problem Basic Readers/Writers Solution W • Correctness Constraints: – Readers can access database when no writers – Writers can access database when no readers or writers R – Only one thread manipulates state variables at a time R • Basic structure of a solution: R – Reader() Wait=until=no=writers Access=data=base Check=out=– wake=up=a=waiting=writer – Writer() • Motivation: Consider a shared database Wait=until=no=active=readers=or=writers Access=database – Two classes of users: Check=out=– wake=up=waiting=readers=or=writer » Readers – never modify database – State variables (Protected by a lock called “lock”): » int AR: Number of active readers; initially = 0 » Writers – read and modify database » int WR: Number of waiting readers; initially = 0 – Is using a single lock on the whole database sufficient? » int AW: Number of active writers; initially = 0 » int WW: Number of waiting writers; initially = 0 » Like to have many readers at the same time » Condition=okToRead ==NIL » Only one writer at a time » Condition=okToWrite ==NIL 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.5 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.6 Code for a Reader Code for a Writer Reader()={ Writer()={ //=First=check=self=into=system //=First=check=self=into=system lock.Acquire(); lock.Acquire(); while=((AW=+=AR)=>=0)={ //=Is=it=safe=to=write? while=((AW=+=WW)=>=0)={ //=Is=it=safe=to=read? WW++; //=No.=Active=users=exist WR++; //=No.=Writers=exist okToWrite.wait(&lock); //=Sleep=on=cond var okToRead.wait(&lock); //=Sleep=on=cond var WWXX; //=No=longer=waiting WRXX; //=No=longer=waiting } } AW++; //=Now=we=are=active! AR++; //=Now=we=are=active! lock.release(); lock.release(); //=Perform=actual=read/write=access AccessDatabase(ReadWrite); //=Perform=actual=readXonly=access AccessDatabase(ReadOnly); //=Now,=check=out=of=system lock.Acquire(); //=Now,=check=out=of=system AWXX; //=No=longer=active lock.Acquire(); if=(WW=>=0){ //=Give=priority=to=writers ARXX; //=No=longer=active okToWrite.signal(); //=Wake=up=one=writer if=(AR====0=&&=WW=>=0) //=No=other=active=readers }=else=if=(WR=>=0)={ //=Otherwise,=wake=reader okToWrite.signal(); //=Wake=up=one=writer okToRead.broadcast(); //=Wake=all=readers Why broadcast() } lock.Release(); lock.Release(); } } Why Release the 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.7 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.8 Simulation of Readers/Writers solution Simulation(2) • Consider the following sequence of operators: • Next, W1 comes along: – R1, R2, W1, R3 while=((AW=+=AR)=>=0)={ //=Is=it=safe=to=write? WW++; //=No.=Active=users=exist • On entry, each reader checks the following: okToWrite.wait(&lock); //=Sleep=on=cond var while=((AW=+=WW)=>=0)={ //=Is=it=safe=to=read? WWXX; //=No=longer=waiting WR++; //=No.=Writers=exist } okToRead.wait(&lock); //=Sleep=on=cond var AW++; WRXX; //=No=longer=waiting } • Can’t start because of readers, so go to sleep: AR++; //=Now=we=are=active! AR = 2, WR = 0, AW = 0, WW = 1 • First, R1 comes along: • Finally, R3 comes along: AR = 1, WR = 0, AW = 0, WW = 0 AR = 2, WR = 1, AW = 0, WW = 1 • Next, R2 comes along: • Now, say that R2 finishes before R1: AR = 2, WR = 0, AW = 0, WW = 0 AR = 1, WR = 1, AW = 0, WW = 1 • Now, readers make take a while to access database • Finally, last of first two readers (R1) finishes and wakes up writer: – Situation: Locks released if=(AR====0=&&=WW=>=0) //=No=other=active=readers – Only AR is non-zero okToWrite.signal(); //=Wake=up=one=writer 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.9 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.10 Simulation(3) Questions • Can readers starve? Consider Reader()=entry code: • When writer wakes up, get: while=((AW=+=WW)=>=0)={ //=Is=it=safe=to=read? AR = 0, WR = 1, AW = 1, WW = 0 WR++; //=No.=Writers=exist • Then, when writer finishes: okToRead.wait(&lock); //=Sleep=on=cond var WRXX; //=No=longer=waiting if=(WW=>=0){===========//=Give=priority=to=writers } okToWrite.signal(); //=Wake=up=one=writer AR++; //=Now=we=are=active! }=else=if=(WR=>=0)={ //=Otherwise,=wake=reader okToRead.broadcast(); //=Wake=all=readers • What if we erase the condition check in Reader exit? } ARXX; //=No=longer=active – Writer wakes up reader, so get: if=(AR====0=&&=WW=>=0) //=No=other=active=readers okToWrite.signal();= //=Wake=up=one=writer AR = 1, WR = 0, AW = 0, WW = 0 • Further, what if we turn the signal() into broadcast() • When reader completes, we are finished ARXX; //=No=longer=active okToWrite.broadcast();= //=Wake=up=one=writer • Finally, what if we use only one condition variable (call it “okToContinue”) instead of two separate ones? – Both readers and writers sleep on this variable – Must use broadcast() instead of signal() 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.11 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.12 Administrivia • Midterm on Wednesday 9/28 5-6:30PM – 1 LeConte (Last name A-H) and 2050 VLSB (Last name I-Z) – Topics include course material through lecture 9 (today) » Lectures, project 1, homeworks, readings, textbook – Closed book, no calculators, one double-side letter-sized page of handwritten notes – Review today 6:45-8:30PM in Hearst Field Annex A1 • No office hours on Mon10/3 (covering CS 262A) BREAK • Deadlines next week: – HW2 due next Monday (10/3) – Project 1 code due next Wednesday (10/5) – Project 1 final report due next Friday (10/7) 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.13 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.14 Can we Construct Monitors from Semaphores? Construction of Monitors from Semaphores (cont’d) • Locking aspect is easy: Just use a mutex • Problem with previous try: • Can we implement condition variables this way? – P and V are commutative – result is the same no matter what order they occur Wait()==={=semaphore.P();=} Signal()={=semaphore.V();=} – Condition variables are NOT commutative – Doesn’t work: Wait()=may sleep with lock held • Does this fix the problem? Wait(Lock=lock)={ • Does this work better? lock.Release(); Wait(Lock=lock)={ semaphore.P(); lock.Release(); lock.Acquire(); semaphore.P(); } lock.Acquire(); Signal()={ } if=semaphore=queue=is=not=empty Signal()={=semaphore.V();=} semaphore.V(); – No: Condition vars have no history, semaphores have history: } » What if thread signals and no one is waiting? NO-OP – Not legal to look at contents of semaphore queue » What if thread later waits? Thread Waits – There is a race condition – signaler can slip in after lock release and » What if thread V’s and no one is waiting? Increment before waiter executes semaphore.P() » What if thread later does P? Decrement and continue • It is actually possible to do this correctly – Complex solution for Hoare scheduling in book – Can you come up with simpler Mesa-scheduled solution? 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.15 2/22/16 Joseph CS162 ©UCB Spring 2016 Lec 9.16 Monitor Conclusion C-Language Support for Synchronization • Monitors represent the logic of the program • C language: Pretty straightforward synchronization – Wait if necessary – Just make sure you know all the code paths out of a critical – Signal when change
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages12 Page
-
File Size-