1 / 14

Condition Variables

Condition Variables. Youngju Song(youngju.song@sf.snu.ac.kr) Jeongyoon Eo(jyeo@rubis.snu.ac.kr) School of Computer Science and Engineering Seoul National University. Contents. Condition Variables Motivation Condition Variables: Definition and Routines Producer/Consumer Problem

mossl
Télécharger la présentation

Condition Variables

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. Condition Variables Youngju Song(youngju.song@sf.snu.ac.kr) Jeongyoon Eo(jyeo@rubis.snu.ac.kr) School of Computer Science and Engineering Seoul National University

  2. Contents • Condition Variables • Motivation • Condition Variables: Definition and Routines • Producer/Consumer Problem • Covering Condition • Summary

  3. Motivation • Concurrent programs depend on certain conditions • How to wait for the condition? • Spinning wastes CPU time • Sleep for a condition instead of spinning • If condition is met, continue execution • Else, sleep for the condition

  4. Definition and Routines #include <pthread.h> pthread_cond_t c; // condition variable int pthread_cond_wait(pthread_cond_t *c, pthread_mutex_t *m); // wait() int pthread_cond_signal(pthread_cond_t *c); // signal() // returns 0 if OK, else error # • Condition Variable(CV) • A queue where threads wait on conditions • Routines associated with CV • Wait(CV, mutex) • Atomically, Release the mutex (assumes locked) Put calling thread to sleep • When wakes up, Re-acquire the mutex And then return • Signal(CV) • Wake one of the sleeping threads

  5. CV Routines Example: join() int done = 0; pthread_cond_t c; Parent Child int main(int argc, char* argv[]){ printf(“parent: begin\n”); pthread_t p; pthread_create(&p, NULL, child, NULL); thr_join(); printf(“parent: end\n”); return 0; } void* child(void* arg){ printf(“child\n”); thr_exit(); return NULL; } Wakes Parent up void thr_exit(){ pthread_mutex_lock(&m); done = 1; pthread_cond_signal(&c); pthread_mutex_unlock(&m); } void thr_join(){ pthread_mutex_lock(&m); while(done == 0) pthread_cond_wait(&c, &m); pthread_mutex_unlock(&m); } Parent waits on a condition ‘child exit’ • Parent creates a child thread and waits on ‘child exit’ condition • Requirements • state variable ‘done’ • mutex

  6. CV Routines Broken Example: join() X int done = 0; pthread_cond_t c; Parent Child int main(int argc, char* argv[]){ printf(“parent: begin\n”); pthread_t p; pthread_create(&p, NULL, child, NULL); thr_join(); printf(“parent: end\n”); return 0; } void* child(void* arg){ printf(“child\n”); thr_exit(); return NULL; } Wakes Up Nobody Waits Forever void thr_exit(){ pthread_mutex_lock(&m); pthread_cond_signal(&c); pthread_mutex_unlock(&m); } void thr_join(){ pthread_mutex_lock(&m); pthread_cond_wait(&c, &m); pthread_mutex_unlock(&m); } Parent waits on a condition ‘child exit’ • Are BOTH state variable and mutex ALWAYS needed? • YES! • Without the state variable, wait and signal operations get lost

  7. CV Routines Broken Example: join() int done = 0; Parent Child int main(int argc, char* argv[]){ printf(“parent: begin\n”); pthread_t p; pthread_create(&p, NULL, child, NULL); thr_join(); printf(“parent: end\n”); return 0; } void* child(void* arg){ printf(“child\n”); thr_exit(); return NULL; } Wakes Up Nobody Waits Forever void thr_exit(){ done = 1; pthread_cond_signal(&c); } void thr_join(){ if(done == 0) pthread_cond_wait(&c, &m); } Interrupted Parent waits on a condition ‘child exit’ • Are BOTH state variable and mutex ALWAYS needed? • YES! • Without the mutex, race conditions arise; multiple threads share the state variable

  8. Producer/Consumer Problem How to control access to the shared buffer? single entry shared buffer int buffer; int count = 0; Consumer Producer void* consumer(void* arg){ int i; while(1){ int tmp = get(); printf(“%d\n”, tmp); } } void* producer(void* arg){ int i; int loops = (int) arg; for(i=0; i < loops; i++) put(i); } void put(int value){ assert(count == 0); count = 1; buffer = value; } int get(){ assert(count == 1); count = 0; return buffer; } Only when buffer isn’t full, fill the buffer Only when buffer isn’t empty, empty the buffer • Producer • Generate data and put it in a buffer • Consumer • Take the data away from the buffer

  9. Re-check the condition when awaken! Broken Solution: Using If pthread_cond_t c; mutex_t m = 0; int count = 0; Consumer: C1, C2 Producer: P Producer void* producer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); if(count == 1) pthread_cond_wait(&c, &m); put(i); pthread_cond_signal(&c); pthread_mutex_unlock(&m); } } context switch p1 p2 p3 p4 p5 p6 wakes C1 up Consumer void* consumer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); if(count == 0) pthread_cond_wait(&c, &m); int tmp = get(); pthread_cond_signal(&c); pthread_mutex_unlock(&m); print(“%d\n”, tmp); } } context switch c1 c2 c3 c4 c5 c6 consumes data context switch Buffer is empty!

  10. Signaling should be directed! Broken Solution: Using While pthread_cond_t c; mutex_t m = 0; int count = 0; Consumer: C1, C2 Producer: P Producer void* producer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); while(count == 1) pthread_cond_wait(&c, &m); put(i); pthread_cond_signal(&c); pthread_mutex_unlock(&m); } } context switch p1 p2 p3 p4 p5 p6 context switch wakes C1 up Consumer void* consumer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); while(count == 0) pthread_cond_wait(&c, &m); int tmp = get(); pthread_cond_signal(&c); pthread_mutex_unlock(&m); print(“%d\n”, tmp); } } context switch c1 c2 c3 c4 c5 c6 wakes C2 up, NOT P context switch Sleeps forever!

  11. Signaling should be directed! Broken Solution: Using While pthread_cond_t empty, fill; mutex_t m = 0; int count = 0; Consumer: C1, C2 Producer: P Producer void* producer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); while(count == 1) pthread_cond_wait(&empty, &m); put(i); pthread_cond_signal(&fill); pthread_mutex_unlock(&m); } } context switch p1 p2 p3 p4 p5 p6 context switch wakes C1 up Consumer void* consumer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); while(count == 0) pthread_cond_wait(&fill, &m); int tmp = get(); pthread_cond_signal(&empty); pthread_mutex_unlock(&m); print(“%d\n”, tmp); } } context switch c1 c2 c3 c4 c5 c6 wakes C2 up, NOT P context switch Sleeps forever!

  12. Generalized Final Solution • Producer/consumer with a multi-slot buffer int buffer[MAX]; int fill_ptr = 0; int use_ptr = 0; pthread_cond_t empty, fill; mutex_t m = 0; int count = 0; Producer Consumer void* consumer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); while(count == 0) pthread_cond_wait(&fill, &m); int tmp = get(); pthread_cond_signal(&empty); pthread_mutex_unlock(&m); print(“%d\n”, tmp); } } void* producer(void* arg){ int i; while(1){ pthread_mutex_lock(&m); while(count == MAX) pthread_cond_wait(&empty, &m); put(i); pthread_cond_signal(&fill); pthread_mutex_unlock(&m); } } int get(){ int tmp = buffer[use_ptr]; use_ptr = (use_ptr+1)%MAX; count--; return tmp; } void put(int value){ buffer[fill_ptr] = value; fill_ptr = (fill_ptr+1)%MAX; count++; }

  13. Covering Condition Thread A alloc 100 Wake up Check cond Sleep should wait Thread C free 50 ? broadcast Wake up Check cond Get memory should receive memory Thread B alloc 10 • Signaling thread might not know which thread(s) to wake up • Example: a multi-threaded memory allocation library • Wait(): Sleep for enough memory to become free • Signal(): Wake up when amount of free memory is increased • Broadcast the signal and wake all waiting threads • Pros: Threads that should get the signal are guaranteed to receive it • Cons: Negative performance impact – too many threads can be awaken

  14. Summary • Condition Variables • A queue where threads wait on conditions - wait() and signal() routines • Allows threads to sleep on condition: No need for spinning • Solves producer/consumer problem • Solves covering condition by broadcasting signals

More Related