1 / 16

More Synchronization, Semaphores

More Synchronization, Semaphores. Vivek Pai / Kai Li Princeton University. Continuing on Synchronization. So far, we’ve seen “Spinning” on lock during entire critical section Disabling interrupts for critical section (bad) Queue associated with each lock & blocking

gwylan
Download Presentation

More Synchronization, Semaphores

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. More Synchronization, Semaphores Vivek Pai / Kai Li Princeton University

  2. Continuing on Synchronization So far, we’ve seen • “Spinning” on lock during entire critical section • Disabling interrupts for critical section (bad) • Queue associated with each lock & blocking • System calls for locking – possibly blocking Since system calls exist, is everything solved? Assume shared variable “count” Lock(&mutex); count++; Unlock(&mutex);

  3. Cost of Protecting a Shared Variable • Making lock system call • Pushing parameter, sys call # onto stack • Generating trap/interrupt to enter kernel • System call in kernel • Jump to appropriate function in kernel • Verify process passed in valid pointer to mutex • Do locking operation, block process if needed • Actually change count – load/modify/store • System call again to release mutex

  4. What is Lock Contention? • Competition for a lock • Uncontended = rarely in use by someone else • Contended = often used by someone else • Held = currently in use by someone • Question: what do these combinations do? • Spinning on low-contention lock • Spinning on high-contention lock • Blocking on low-contention lock • Blocking on high-contention lock

  5. Things to Ponder • If critical section is just “count++;”, what is the overhead of the synchronization • Is there some other way of doing this? • What if you don’t know how long the critical section will be?

  6. What If You Have the Following • Test-and-set – works at either user or kernel • System calls for block/unblock • Block takes some token and goes to sleep • Unblock “wakes up” a waiter on token

  7. User-Level Acquire/Release using Block and Unblock • In what scenarios is this scheme appropriate? • Where should it not be used? Release(lock) { lock = 0; Unblock( lock ); } Acquire(lock) { while (!TAS(lock)) Block( lock ); }

  8. Semaphores (Dijkstra, 1965) • Up or “V” • Atomic • Increment semaphore by 1 wake up a waiting P if any • Down or “P” • Atomic • Wait for semaphore to become positive and then decrement by 1 P(s) { if (--s < 0) Block(s); } V(s) { if (++s <= 0) Unblock(s); }

  9. Bounded Buffer (Consumer-Producer) • Example: • grep vivek access.log | more Producer Consumer

  10. Bounded Buffer w/ Semaphores mutex = 1 emptyCount = N; fullCount = 0; producer() { while (1) { produce an item P(emptyCount); P(mutex); put the item in buffer V(mutex); V(fullCount); } } consumer() { while (1) { P(fullCount); P(mutex); take an item from buffer V(mutex); V(emptyCount); consume the item } }

  11. Implementing General Semaphores • Need a mutex for each semaphore • Block and Unblock need to release mutex after entering their critical section V(s) { Acquire(s.mutex); if (++s.value <= 0) Unblock(s); else Release(s.mutex) } P(s) { Acquire(s.mutex); if (--s.value < 0) Block(s); else Release(s.mutex) }

  12. Implement General Semaphores with Acquire/Release • Kotulski (1988) • Two processes call P(s) (when s.value is 0) and preempted after Release(s.mutex) • Two other processes call V(s) P(s) { Acquire(s.mutex); if (--s.value < 0) { Release(s.mutex); Acquire(s.delay); } else Release(s.mutex); } V(s) { Acquire(s.mutex); if (++s.value <= 0) Release(s.delay); Release(s.mutex); }

  13. Hemmendinger’s Solution (1988) • The idea is not to release s.mutex and turn it over individually to the waiting process • P and V are executing in lockstep P(s) { Acquire(s.mutex); if (--s.value < 0) { Release(s.mutex); Acquire(s.delay); } Release(s.mutex); } V(s) { Acquire(s.mutex); if (++s.value <= 0) Release(s.delay); else Release(s.mutex); }

  14. Kearns’s Solution (1988) P(s) { Acquire(s.mutex); if (--s.value < 0) { Release(s.mutex); Acquire(s.delay); Acquire(s.mutex); if (--s.wakecount > 0) Release(s.delay); } Release(s.mutex); } V(s) { Acquire(s.mutex); if (++s.value <= 0) { s.wakecount++; Release(s.delay); } Release(s.mutex); } Two Release( s.delay) calls are also possible

  15. Hemmendinger’s Correction (1989) P(s) { Acquire(s.mutex); if (--s.value < 0) { Release(s.mutex); Acquire(s.delay); Acquire(s.mutex); if (--s.wakecount > 0) Release(s.delay); } Release(s.mutex); } V(s) { Acquire(s.mutex); if (++s.value <= 0) { s.wakecount++; if (s.wakecount == 1) Release(s.delay); } Release(s.mutex); } Correct but a complex solution

  16. Hsieh’s Solution (1989) P(s) { Acquire(s.delay); Acquire(s.mutex); if (--s.value > 0) Release(s.delay); Release(s.mutex); } V(s) { Acquire(s.mutex); if (++s.value == 1) Release(s.delay); Release(s.mutex); } • Use Acquire(s.delay) to block processes • Correct but still a constrained implementation

More Related