Download presentation
Presentation is loading. Please wait.
1
Chapter 30 Condition Variables
Chien-Chung Shen CIS/UD
2
Review of Locks Built from the right combination of hardware (assembly instructions) and OS support (queue, yield, sleep, etc.)
3
Basic Ideas A thread check whether a condition is true before continuing (parent thread waits for child thread) void *child(void *arg) { printf("child\n"); // how to indicate I am done? return NULL; } main(int argc, char *argv[]) { pthread_t c; printf("parent: begin\n"); Pthread_create(&c, NULL, child, NULL); // create child // how to wait for child? printf("parent: end\n"); return 0; P C
4
How to Wait for a Condition ?
Does a shared variable work here? yes How does this run on one CPU? What is the main issue? spin and waste CPU time What could be a better solution? how to wait for a condition? “Shared” (global) variable volatile int done = 0; void *child(void *arg) { printf("child\n"); done = 1; return NULL; } main(int argc, char *argv[]) { printf("parent: begin\n"); pthread_t c; Pthread_create(&c, NULL, child, NULL); // create child while (done == 0) ; // spin printf("parent: end\n"); return 0;
5
How to Wait for a Condition ?
Ideas: to put the parent to sleep until the condition we are waiting for (e.g., the child is done executing) comes true Condition variable (CV) an explicit queue that threads can put themselves on when some state of execution (i.e., some condition) is not as desired (by waiting on the condition) some other thread, when it changes said state, wake one (or more) of those waiting threads and allow them to continue (by signaling on the condition)
6
Condition Variable A queue Two operations
wait() is executed when a thread wishes to put itself to sleep signal() is executed when a thread has changed something and thus wants to wake a sleeping thread waiting on this condition
7
Pthread API for CV Pthread_cond_wait(&c, &m): Pthread_cond_signal(&c):
release lock m and put calling thread to sleep atomically (assuming m is locked when wait is called) when thread wakes up (after some other thread has signaled it), re-acquire lock m before returning to caller Pthread_cond_signal(&c): signal
8
Two cases Parent create child and continue to run; call into thr_join() to wait for child to complete parent acquires the lock, check if child is done [it is not], and put itself to sleep by calling wait() (hence release the lock) child eventually runs and calls thr_exit() to wake parent: grabs the lock, set done to 1, signal parent to wake it finally parent runs (return from wait() with lock held), release the lock Child runs immediately upon creation, set done to 1, calls signal to wake a sleeping thread [but there is none, so it just returns] parent then runs, call thr_join(). Sees done is 1, and thus does not wait and returns
9
Why We Need done? Will the following code work? Assume child runs immediately and calls thr_exit() to signal But there is no thread asleep on CV c When parent runs, it will wait and be stuck (no thread will ever wake it) Variable done records the value both threads are interested in knowing - sleeping, waking, and locking all are built around it
10
Why We Need Lock for CV? i A subtle race condition Usage of CV
// by child A subtle race condition if the parent calls thr_join() and then checks the value of done, it will see that it is 0 and thus try to go to sleep But just before it calls wait() to go to sleep, the parent is interrupted, and the child runs The child changes done to 1 and signals, but no thread is waiting and thus no thread is woken When the parent runs again, it calls wait() and sleeps forever Usage of CV wait() always (a) assumes lock is held when called, (b) releases said lock when putting the caller to sleep, and (c) re-acquires lock just before returning Also, always hold lock while signaling // by parent i
11
Need both done and Lock void thr_exit() { Pthread_mutex_lock(&m)
Pthread_cond_signal(&c); Pthread_mutex_unlock(&m); } Do we need done? failed when child runs immediately and calls thr_exit() done = 1; Does not hold a lock when wait and signal? failed when parent proceeds first (and will sleep forever) void thr_join() { Pthread_mutex_lock(&m); Pthread_cond_wait(&c, &m); Pthread_mutex_unlock(&m); } if (done == 0) Pthread_cond_wait(&c); interrupt
12
CV Design Pattern
13
Properties of CV CV is memoryless
cv.wait(&lock) atomically release the lock when sleep When a waiting thread is re-enabled via signal or broadcast, it may not run immediately
14
Producer/Consumer Problem
A.k.a. bounded buffer problem – by E. Dijkstra One item buffer Only put data into the buffer when the buffer is empty (count is 0) Only get data from the buffer when the buffer is full (count is 1) What/where are the critical sections? Will lock be enough? need to know when it is OK to put or get data
15
buffer P C
16
P C P C P C Efficiency? more buffer Concurrency? more P and C
17
One Solution Using CV p1-p3 wait for buffer to become empty; c1-c3 wait for buffer to become full Is the code OK for single P and single C ? yes How about two C’s ? C1 waits, P puts one data, and another C2 sneaks in to consume it; C1 wakes up and get ??? if statement is to blame Mesa semantics – signaling a thread only wakes it up; the waken thread does not run immediately Always use while loop
18
Signaling logic between P and C
For single P and single C, this code works One item buffer
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.