75 lines
3 KiB
C
75 lines
3 KiB
C
|
// odd/even thread coordination on incrementing an global
|
||
|
// variable. This version uses a condition variable to efficiently
|
||
|
// notify threads of changes to the global variable.
|
||
|
#include "odds_evens.h"
|
||
|
|
||
|
int count = 0; // global variable all threads are modifiying
|
||
|
pthread_mutex_t count_mutex; // mutex to check count
|
||
|
pthread_cond_t count_condv; // condition variable to receive wake-ups
|
||
|
|
||
|
// Run by even child threads, increment count when it is even
|
||
|
void *even_work(void *t) {
|
||
|
int tid = *( (int *) t);
|
||
|
for(int i=0; i<THREAD_ITERS; i++){
|
||
|
pthread_mutex_lock(&count_mutex);
|
||
|
while(count % 2 != 0){ // wait until count is even
|
||
|
VPRINTF("%d iter %d: count %d, NOT EVEN, sleeping\n",
|
||
|
tid, i, count);
|
||
|
pthread_cond_wait(&count_condv, &count_mutex); // await notification to check again, gets lock on wakeup
|
||
|
}
|
||
|
printf("%d iter %d: count %d, IS EVEN, proceeding\n",
|
||
|
tid, i, count);
|
||
|
update(&count); // now have lock and condition is correct can safely increment
|
||
|
pthread_mutex_unlock(&count_mutex); // release lock
|
||
|
pthread_cond_broadcast(&count_condv); // notify all others waiting
|
||
|
}
|
||
|
printf("%d FINISHED %d iterations\n", tid, THREAD_ITERS);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
// Run by odd child threads, increment count when it is odd
|
||
|
void *odd_work(void *t) {
|
||
|
int tid = *( (int *) t);
|
||
|
for(int i=0; i<THREAD_ITERS; i++){
|
||
|
pthread_mutex_lock(&count_mutex);
|
||
|
while(count % 2 != 1){ // wait until count is odd
|
||
|
VPRINTF("%d iter %d: count %d, NOT ODD, sleeping\n",
|
||
|
tid, i, count);
|
||
|
pthread_cond_wait(&count_condv, &count_mutex); // await notification to check again, gets lock on wakeup
|
||
|
}
|
||
|
printf("%d iter %d: count %d, IS ODD, proceeding\n",
|
||
|
tid, i, count);
|
||
|
update(&count); // now have lock can safely increment
|
||
|
pthread_mutex_unlock(&count_mutex); // release lock
|
||
|
pthread_cond_broadcast(&count_condv); // notify all others waiting, pthread_cond_signal() only notifies single thread
|
||
|
}
|
||
|
printf("%d FINISHED %d iterations\n", tid, THREAD_ITERS);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
int main(int argc, char *argv[]) {
|
||
|
pthread_t threads[TOT_THREADS];
|
||
|
int tids[TOT_THREADS];
|
||
|
|
||
|
pthread_mutex_init(&count_mutex, NULL); // Initialize mutex and condition variable
|
||
|
pthread_cond_init (&count_condv, NULL);
|
||
|
|
||
|
for(int i=0; i<TOT_THREADS; i+=2){
|
||
|
tids[i] = i;
|
||
|
pthread_create(&threads[i], NULL, even_work, (void *) &(tids[i]));
|
||
|
tids[i+1] = i+1;
|
||
|
pthread_create(&threads[i+1], NULL, odd_work, (void *) &(tids[i+1]));
|
||
|
}
|
||
|
|
||
|
for(int i=0; i<TOT_THREADS; i++) { // Wait for all threads to complete
|
||
|
pthread_join(threads[i], NULL);
|
||
|
}
|
||
|
|
||
|
printf("main: count is %d\n",count);
|
||
|
|
||
|
pthread_mutex_destroy(&count_mutex); // Clean up and exit
|
||
|
pthread_cond_destroy(&count_condv);
|
||
|
exit(0);
|
||
|
}
|
||
|
|