Condition variables
- Threads might want to check a condition is true before continuing its execution.
- A parent thread might wish to check whether a child thread has completed before continuing
- We would want to put the parent to sleep until the condition is met.
Definition and Routines
- Condition variable: 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)
- When some other threads changes said state, it can then wake one (or more) of those waiting threads and thus allow them to continue.
- To use condition variables we have
wait()
andsignal()
:wait()
is used by threads to put themselves to sleep.signal()
is executed when a thread has changed something in the program and thus wants to wake a sleeping thread waiting this condition
int done = 0;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
void thr_exit() {
Pthread_mutex_lock(&m);
done = 1;
Pthread_cond_signal(&c);
Pthread_mutex_unlock(&m);
}
void *child(void *arg) {
printf("child\n");
thr_exit();
return NULL;
}
void thr_join() {
Pthread_mutex_lock(&m);
while (done == 0)
Pthread_cond_wait(&c, &m);
Pthread_mutex_unlock(&m);
}
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;
}
In this code we have two cases to consider, the first:
- Parent create child thread
- Parent continues execution and jumps to
thr_join
- It acquires the lock and check if
done
is 1 - Since
done
is not 1 yet, it callsPthread_cond_wait
which takes the condition and a lock Pthread_cond_wait
releases the lock and puts the thread to sleep- The child thread runs and calls
thr_exit
thr_exit
acquires the lock and sets done to 1 and sends a signal to threads that are watching forc
- The parent threads wakes up with the lock held and checks if
done
is 1 done
is 1 so we jump toPthread_mutex_unlock
to release the lock
On the seconds options we have:
- Parent creates thread
- Child runs executes the code and set
done
to 1 - The parent calls
thr_join
and sincedone
is 1, it skips thePthread_cond_wait
part and directly callsPthread_mutex_unlock
and continues execution.
The Producer/Consumer (Bounded Buffer) Problem
- We have one or more producer threads and one or more consumer threads.
- Producers generate data and place them in a buffer
- Consumers grab the items from the buffer and consume them in some way
- The bounded buffer is a shared resource, we rquire sync access to it. Example:
void *producer(void *arg) {
int i;
int loops = (int) arg;
for (i = 0; i)
}