1 / 22

Semaphores

Semaphores. Jiwoong Park(jwpark@dcslab.snu.ac.kr) School of Computer Science and Engineering Seoul National University. Overview. Semaphore A synchronization primitive Invented by Edsger Dijkstra Uses Building Synchronization Primitives Binary Semaphores (Locks)

baparicio
Download Presentation

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. Semaphores Jiwoong Park(jwpark@dcslab.snu.ac.kr) School of Computer Science and Engineering Seoul National University

  2. Overview • Semaphore • A synchronization primitive • Invented by Edsger Dijkstra • Uses • Building Synchronization Primitives • Binary Semaphores (Locks) • Semaphores as Condition Variables • Solving Problems • Producer/Consumer (Bounded-Buffer) Problem • Reader-Writer Problem • Dining Philosopher’s Problem • Implementation • Zemaphores • Our own version of semaphores using Locks and Condition Variables

  3. Semaphores • Definition • An object with an integer value that can be manipulated with two routines • sem_wait( ) / sem_post( ) in the POSIX standard • Prerequisites • Initialization needed before calling any other routines • sem_init( ): Initializes an unnamed semaphore • Atomicity of the increment, decrement, and comparison operation needed • Atomic read-modify-write operations provided by H/W • Mutual exclusion algorithm provided by S/W

  4. Routines int sem_wait (sem_t *s) { decrement the value of semaphore s by one wait if value of semaphore s is negative } int sem_post (sem_t *s) { increment the value of semaphore s by one if there are one or more threads waiting, wake one } Note that when negative, s->value == # of waiting threads • Routines • sem_wait( ) • a.k.a. P( ) (for the Dutch word “to probe”) • sem_post( ) • a.k.a. V( ) (for the Dutch word “to test”)

  5. Locks (Binary Semaphores) sem_t m; sem_init(&m, 0, 1); // initialize semaphore to 1 sem_wait(&m); // critical section here sem_post(&m); • Locks • Ensures that a critical section executes as if it were a single atomic instruction • Only have two states • Locked / Unlocked • Can be implemented with Binary Semaphore • Simply surround the critical section of interest with a sem_wait( ) / sem_post( ) pair • The initial value should be 1

  6. Locks (Binary Semaphores) Semaphore -1 0 1 1 0 Run Context Switching! Context Switching! T0 Ready Wait T1 • An Example Scenario with Two Threads

  7. Semaphores As Condition Variables • Condition Variable • Useful when a thread wants to halt waiting for a condition to become true • Waiting thread • Waiting for something to happen • Notifying thread • Making that something happen • Signaling that it has happened • Waking the waiting thread • Can be implemented with Private Semaphore • A waiting thread calls sem_wait( ) • A notifying thread calls sem_post( ) • The initial value should be 0

  8. Semaphores As Condition Variables Semaphore 0 -1 0 Run Context Switching! Context Switching! Parent Ready Wait Child Z..z..z… • An Example Scenario: Parent waiting for Child • Case 1 • The parent creates the child but the child has not run yet

  9. Semaphores As Condition Variables Semaphore 1 0 0 Run Context Switching! Context Switching! Parent Ready Wait Child • An Example Scenario: Parent waiting for Child • Case 2 • The child runs to completion before the parent gets a chance to call sem_wait( )

  10. Producer / Consumer (Bounded-Buffer) Problem sem_t empty, full, mutex; int buffer[MAX]; int fill,use = 0; void put(int value) { buffer[fill] = value; fill = (fill + 1) % MAX; } int get() { int tmp = buffer[use]; use = (use + 1) % MAX; return tmp; } • Producer / Consumer Problem • Conditions • Producers MUST wait until a buffer is NOT FULL to place data in a buffer • ConsumersMUST wait until a buffer is NOT EMPTY to grab data items out of the buffer • Requirements • Two Semaphores(Empty / Full) • A lock for mutual exclusion • Put( ) and Get( ) routines

  11. Producer / Consumer (Bounded-Buffer) Problem void *producer(void *arg) { inti; for (i = 0; i < loops; i++) { sem_wait(&empty); put(i); sem_post(&full); } } Empty Full Buffer X 1 0 -1 0 0 0 -1 Run void *consumer(void *arg) { inti, tmp = 0; while (tmp != -1) { sem_wait(&full); tmp = get(); sem_post(&empty); printf(“%d\n”, tmp); } } Context Switching! Context Switching! Consumer Ready Wait Producer • An Example Scenario • Two threads on a single CPU & Buffer size = 1

  12. Producer / Consumer (Bounded-Buffer) Problem void *producer(void *arg) { inti; for (i = 0; i < loops; i++) { sem_wait(&empty); put(i); sem_post(&full); } } Buffer Empty Full 2 0 0 1 X1 X2 Overwritten!! Producer 2 Producer 1 void *producer(void *arg) { inti; for (i = 0; i < loops; i++) { sem_wait(&empty); put(i); sem_post(&full); } } Consumer 2 Consumer 1 • An Example Scenario • 2 producers and 2 consumers & Buffer size = 2 • Race Condition

  13. Producer / Consumer (Bounded-Buffer) Problem void *producer(void *arg) { inti; for (i = 0; i < loops; i++) { sem_wait(&empty); sem_wait(&mutex); put(i); sem_post(&mutex); sem_post(&full); } } void *consumer(void *arg) { inti, tmp = 0; while (tmp != -1) { sem_wait(&full); sem_wait(&mutex); tmp = get(); sem_post(&mutex); sem_post(&empty); printf(“%d\n”, tmp); } } • An Example Scenario • 2 producers and 2 consumers & Buffer size = 2 • A Solution: Adding Mutual Exclusion to make put( ) and get( ) operations atomic !

  14. Reader-Writer Locks typedef struct _rwlock_t { sem_t lock; // initial value is 1 sem_t writelock; // initial value is 1 int readers; // initial value is 0 } • Reader-Writer Locks • Functionality • Allows concurrent access for read-only operations while write operations require exclusive access • Requirements • A lock for writelock • A lock for mutual exclusion • A variable for counting the # of readers in critical section

  15. Reader-Writer Locks Waiting… Waiting… void rwlock_acquire_readlock(rwlock_t *rw) { sem_wait(&rw->lock); rw->readers++; if (rw->readrers == 1) sem_wait(&rw->writelock); sem_post(&rw->lock); } void rwlock_release_readlock(rwlock_t *rw) { sem_wait(&rw->lock); rw->readers--; if (rw->readers == 0) sem_post(&rw->writelock); sem_post(&rw->lock); } void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); } void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); } Reader 0 Reader 1 Writer 0 Reader 2 Reader 3 Waiting… Waiting… • An Example Scenario • A Writer got the lock first

  16. Reader-Writer Locks Waiting… void rwlock_acquire_readlock(rwlock_t *rw) { sem_wait(&rw->lock); rw->readers++; if (rw->readrers == 1) sem_wait(&rw->writelock); sem_post(&rw->lock); } void rwlock_release_readlock(rwlock_t *rw) { sem_wait(&rw->lock); rw->readers--; if (rw->readers == 0) sem_post(&rw->writelock); sem_post(&rw->lock); } void rwlock_acquire_writelock(rwlock_t *rw) { sem_wait(&rw->writelock); } void rwlock_release_writelock(rwlock_t *rw) { sem_post(&rw->writelock); } Reader 0 Reader 1 Writer 0 Reader 2 Reader 3 • An Example Scenario • One of the Readers got the lock first

  17. Reader-Writer Locks • Issues • Fairness • Easy for readers to starve writers (Writer starvation) • “Blocking new readers when a writer is blocker” can be a simple solution • Performance • Scale no better than having a single lock unless the lock hold time is long • Memory contention • Use of single word of memory to store the # of readers

  18. Dining Philosopher’s Problem P1 P2 Fork 2 P0 Fork 1 Fork 3 Fork 0 P3 Fork 4 P4 • Dining Philosopher’s Problem • Rule • There are five philosophers and five forks • Each philosopher must alternately think and eat • A philosopher can only eat when he/she has both left and right forks • Each fork can be held by only one philosopher • After finishing eating, he/she needs to put down both forks • Problem • The contention for these forks • Synchronization problems • Goal • To design a protocol with • No deadlock • No starvation • High concurrency

  19. Dining Philosopher’s Problem Waiting… int left(int p) { return p; } int right(int p) { return (p + 1) % 5; } void getforks() { sem_wait(forks[left(p)]); sem_wait(forks[right(p)]); } void putforks() { sem_post(forks[left(p)]); sem_post(forks[right(p)]); } P1 Waiting… P2 Fork 2 Waiting… Fork 1 P0 Fork 3 Deadlock!! Fork 0 Fork 4 P3 P4 Waiting… Waiting… • Naïve Approach • Every philosopher tries to pick left fork first

  20. Dining Philosopher’s Problem Waiting… int left(int p) { return p; } int right(int p) { return (p + 1) % 5; } void getforks() { sem_wait(forks[left(p)]); sem_wait(forks[right(p)]); } void putforks() { sem_post(forks[left(p)]); sem_post(forks[right(p)]); } P1 Waiting… P2 Fork 2 Waiting… Fork 1 P0 Fork 3 Fork 0 Fork 4 P3 P4 Waiting… Waiting… • A Solution: Breaking the Dependency • Philosopher 4 tries to pick right fork first

  21. How To Implement Semaphores typedef struct __Zem_t { int value; pthread_cond_t cond; pthread_mutex_t lock; } Zem_t; void Zem_init(Zem_t *s, int value) { s->value = value; Cond_init(&s->cond); Mutex_init(&s->lock); } void Zem_wait(Zem_t *s) { Mutex_lock(&s->lock); while (s->value <= 0) Cond_wait(&s->cond, &s->lock); s->value--; Mutex_unlcok(&s->lock); } void Zem_post(Zem_t *s) { Mutex_lock(*&s->lock); s->value++; Cond_signal(&s->cond); Mutex_unlock(&s->lcok); } • Zemaphores • Our own version of semaphores • Do not maintain the # of waiting threads • Can be implemented with Locks and CVs

  22. Summary • Semaphores • Powerful and flexible primitives for writing concurrent programs • Surprisingly versatile usages • Locks • Condition Variables • Producer/Consumer (Bounded-Buffer) Problem • Reader-Writer Problem • Dining Philosopher’s Problem • Can be easily implemented with Locks and CVs

More Related