
SharedLock : Reader/Writer Lock A reader/write lock or SharedLock is a new kind of “lock” that is similar to our old definition: • supports Acquire and Release primitives Synchronization: Going Deeper • guarantees mutual exclusion when a writer is present But: a SharedLock provides better concurrency for readers when no writer is present. often used in database systems class SharedLock { AcquireRead (); /* shared mode */ easy to implement using mutexes AcquireWrite(); /* exclusive mode */ and condition variables ReleaseRead (); a classic synchronization problem ReleaseWrite(); } Reader/Writer Lock Illustrated Reader/Writer Lock: First Cut int i; /* # active readers, or -1 if writer */ If each thread acquires the Lock rwMx ; lock in exclusive (*write) Condition rwCv ; SharedLock::ReleaseWrite() { Multiple readers may hold mode, SharedLock functions rwMx.Acquire(); the lock concurrently in A exactly as an ordinary mutex. SharedLock::AcquireWrite() { i = 0; shared mode. r A r Aw rwMx.Acquire(); rwCv.Broadcast(); while (i != 0) rwMx.Release(); Rr Rr rwCv.Wait(&rwMx); } Writers always hold the i = -1; lock in exclusive mode, R rwMx.Release(); w and must wait for all } SharedLock::ReleaseRead() { readers or writer to exit. SharedLock::AcquireRead() { rwMx.Acquire(); rwMx.Acquire(); i -= 1; mode read write max allowed while (i < 0) if (i == 0) shared yes no many rwCv.Wait(&rwMx); rwCv.Signal(); exclusive yes yes one i += 1; rwMx.Release(); not holder no no many rwMx.Release(); } } The Little MutexInside SharedLock Limitations of the SharedLock Implementation This implementation has weaknesses discussed in [Birrell89]. • spurious lock conflicts (on a multiprocessor): multiple Ar waiters contend for the mutex after a signal or broadcast. A r Solution: drop themutex before signaling. Aw R (If the signal primitive permits it.) r R r • spurious wakeups A r ReleaseWrite awakens writers as well as readers. Rw Solution: add a separate condition variable for writers. • starvation Rr How can we be sure that a waiting writer will everpass its acquire if faced with a continuous stream of arriving readers? 1 Reader/Writer Lock: Second Try Guidelines for Condition Variables 1. Understand/document the condition(s) associated with each CV. SharedLock::AcquireWrite() { SharedLock::ReleaseWrite() { rwMx.Acquire(); rwMx.Acquire(); What are the waiters waiting for? while (i != 0) i = 0; When can a waiter expect a signal? wCv.Wait(&rwMx); if (readersWaiting) i = -1; rCv.Broadcast(); 2. Always check the condition to detect spurious wakeups after returning rwMx.Release(); else from a wait: “loop before you leap”! } wcv.Signal(); rwMx.Release(); Another thread may beat you to the mutex. SharedLock::AcquireRead() { } The signaler may be careless. rwMx.Acquire(); SharedLock::ReleaseRead() { while (i < 0) rwMx.Acquire(); A single condition variable may have multiple conditions. i -= 1; ...rCv.Wait(&rwMx);... 3. Don’t forget: signals on condition variables do not stack! i += 1; if (i == 0) rwMx.Release(); wCv.Signal(); A signal will be lost if nobody is waiting: always check the wait } rwMx.Release(); condition before calling wait. } Starvation Deadlock The reader/writer lock example illustrates starvation: under load, a writer Deadlock is closely related to starvation. will be stalled forever by a stream of readers. • Processes wait forever for each other to wake up and/or • Example: a one-lane bridge or tunnel. release resources. Wait for oncoming car to exit the bridge before entering. • Example: traffic gridlock. Repeat as necessary. The difference between deadlock and starvation is subtle. • Problem: a “writer” may never be able to cross if faced with a continuous stream of oncoming “readers”. • With starvation, there always exists a schedule that feeds the starving party. • Solution: some reader must politely stop before entering, even though it is not forced to wait by oncoming traffic. The situation may resolve itself…if you’re lucky. Use extra synchronization to control the lock scheduling policy. • Once deadlock occurs, it cannot be resolved by any possible Complicates the implementation: optimize only if necessary. future schedule. …though there may exist schedules that avoiddeadlock. Dining Philosophers Four Preconditions for Deadlock • N processes share N resources Four conditions must be present for deadlock to occur: • resource requests occur in pairs A 4 1 1. Non-preemptability. Resource ownership (e.g., by threads) • random think times is non-preemptable. D B • hungry philosopher grabs a fork Resources are never taken away from the holder. • ...and doesn’t let go 3 C 2 2. Exclusion. Some thread cannot acquire a resource that is • ...until the other fork is free held by another thread. • ...and the linguine is eaten while(true) { Think(); 3. Hold-and-wait. Holder blocks awaiting another resource. AcquireForks(); Eat(); ReleaseForks(); 4. Circular waiting. Threads acquire resources out of order. } 2 Resource Graphs Not All Schedules Lead to Collisions Given the four preconditions, some schedules may lead to circular waits. The scheduler chooses a path of the executions of the • Deadlock is easily seen with a resource graph or wait-for graph. threads/processes competing for resources. Synchronization constrains the schedule to avoid illegal states. The graph hasa vertex for each process and each resource. If process A holds resource R, add an arcfrom R to A. Some paths “just happen” to dodge dangerous states as well. If process A is waiting for resource R, add an arc from A to R. What is the probability that philosophers will deadlock? The system is deadlocked iff the wait-for graph has at least one cycle. • How does the probability change as: Sn A think times increase? A grabs fork 1 and B grabs fork 2 and waits for fork 2. 1 2 waits for fork 1. number of philosophers increases? assign B request RTG for Two Philosophers Two Philosophers Living Dangerously Y 2 1 Sn Sm R2 R2 X R1 R1 2 1 Sn X A1 2 1 A1 ??? Y Sm A2 A2 (There are really only 9 states we care about: the important transitions are allocate and release events.) A1 A2 R2 R1 A1 A2 R2 R1 The Inevitable Result Dealing with Deadlock 1. Ignore it. “How big can those black boxes be anyway?” 2. Detect it and recover. Traverse the resource graph looking for cycles before blocking any customer. • If a cycle is found, preempt: force one party to release and restart. R2 X 3. Prevent it statically by breaking one of the preconditions. R1 2 1 • Assign a fixed partial ordering to resources; acquire in order. • Use locks to reduce multiple resources to a single resource. A1 Y • Acquire resources in advance of need; release all to retry. A2 no legal transitions out 4. Avoid it dynamically by denying some resource requests. of this deadlock state Banker’s algorithm A1 A2 R2 R1 3 Extending the Resource Graph Model Banker’s Algorithm Reasoning about deadlock in real systems is more complex than the The Banker’s Algorithm is the classic approach to deadlock simple resource graph model allows. avoidance (choice 4) for resources with multiple units. • Resources may have multiple instances (e.g., memory). Cycles are necessary but not sufficient for deadlock. 1. Assign a credit limit to each customer. For deadlock, each resource node with a request arc in the cycle must be “maximum claim” must be stated/negotiated in advance fully allocated and unavailable. 2. Reject any request that leads to a dangerous state. • Processes may block to await events as well as resources. A dangerous state is one in which a sudden request by any E.g., A and B each rely on the other to wake them up for class. customer(s) for the full credit limit could lead to deadlock. These “logical” producer/consumer resources can be considered to be available as long as the producer is still active. A recursive reduction procedure recognizes dangerous states. Of course, the producer may not produce as expected. 3. In practice, this means the system must keep resource usage well below capacity to maintain a reserve surplus. Rarely used in practice due to low resource utilization. Implementing Spinlocks : First Cut Spinlocks : What Went Wrong class Lock { Race to acquire: two threads int held; could observe held == 0 } concurrently, and think they both can acquire the lock. void Lock::Acquire() { void Lock::Acquire() { while (held); “busy -wait” for lock holder to release while (held); /* test */ held = 1; held = 1; /* set */ } } void Lock::Release() { void Lock::Release() { held = 0; held = 0; } } What Are We Afraid Of? The Need for an Atomic “Toehold” Potential problems with the “rough” spinlock implementation: To implement safe mutual exclusion, we need support for (1) races that violate mutual exclusion some sort of “magic toehold” for synchronization. • involuntary context switch between test and set • The lock primitives themselves have critical sections to test and/or set the lock flags. • on a multiprocessor, race between test and set on two CPUs • These primitives must somehow be made atomic. (2) wasteful spinning uninterruptible • lock holder calls sleepor yield a sequence of instructions that executes “all or nothing” • interrupt handler acquires a busy lock • Two solutions: • involuntary context switch for lock holder (1) hardware support: atomic instructions (test-and-set) Which are implementation issues, and which are problems with (2) scheduler control: disable timeslicing (disable interrupts) spinlocks themselves? 4 Atomic Instructions: Test-and-Set On Disabling Interrupts Spinlock ::Acquire () { Nachos has a primitive to disable interrupts, which we will while(held); use as a toehold for synchronization. held = 1; } • Temporarily block notification of external events that could load trigger a context switch. test load Wrong e.g., clock interrupts (ticks) or device interrupts store test load 4(SP), R2 ; load “this” store busywait: • In a “real” system, this is available only to the kernel. load 4(R2), R3 ; load “held” flag Problem: interleaved why? load/test/store. bnz R3, busywait ; spin if held wasn’t zero store #1, 4(R2) ; held = 1 • Disabling interrupts is insufficient on a multiprocessor.
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages10 Page
-
File Size-