// Author: Prof. Chee Yap // Modified by Chien-I Liao // Mar 2005 /*************************************************** * gcd_th.c * * method: * (0) N=argc%2 * (1) init count_mut, count_nonzero (default scope) * (2) main thread spawns a worker thread. * (3) main thread spawns N child threads, each with a pair (m,n) * (4) main thread wait on children to terminate * (5) worker thread: * LOOP: * wait(count_nonzero) * count-- * work on (m,n,id) * signal(id) * * (6) child subroutine: * while n>0 * set up (m,n,id) * count++ * signal(count_nonzero) * wait(id) * update m,n * return gcd * * REMINDER: * (1) In solaris or linux, when you link, * you must give the -lpthread flag. * (2) In cygwin, the signaling does not work? * You may also need to add a private stack * for each GCD thread. * * ***************************************************/ #include #include #define PTHREAD_STACK_MIN 100000 // ========================================= Global variables #define TRUE 1 #define FALSE 0 typedef int boolean; struct pair { // actually, a triple... int m; int n; int idx; }; #define NN 30 int count=0; // count is number of pending requests pthread_mutex_t mutex1, count_mut; pthread_cond_t count_nonzero; pthread_cond_t cond[NN]; // conditional variable for each gcd thread pthread_attr_t attr; // attribute of thread pthread_t workThread; // id of worker thread pthread_t pthreads[NN]; // array of all gcd threads struct pair inputArgs[NN]; // inputArgs[i] is the input pair for i-th thread struct pair workPair[NN]; // workPair[i] is the (mm,nn) work request of // the i-th thread int ans[NN]; // per gcd thread variable! int m[NN]; // per gcd thread variable! int n[NN]; // per gcd thread variable! int done[NN]; // per gcd thread variable! //pthread_t countQueue[NN]; // countQueue[i] is the i-th thread requesting // ========================================= thread routines void *gcd(void *args); void *worker(void *args); // ========================================= main int main(int argc, char ** argv) { int i, j, res; int index[NN]; int N = (argc-1)/2; // N is number of input pairs //========================================== //initialization //========================================== pthread_mutex_init(&mutex1, NULL); pthread_mutex_init(&count_mut, NULL); pthread_cond_init(&count_nonzero, NULL); pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); for (i=0; i0) { pthread_mutex_lock(&count_mut); workPair[count].m = m[my_index]; workPair[count].n = n[my_index]; workPair[count].idx = my_index; count = count+1; done[my_index]=0; //printf("GCD THREAD[%d]: m=%d, n=%d, count=%d \n",my_index, m[my_index], n[my_index], count); fflush(stdout); if (count == 1){ pthread_cond_signal(&count_nonzero); } pthread_mutex_unlock(&count_mut); while(done[my_index]==0); pthread_mutex_lock(&count_mut); m[my_index] = n[my_index]; n[my_index] = ans[my_index]; pthread_mutex_unlock(&count_mut); } printf("%d : gcd(%d, %d) = %d (n= %d) \n", my_index, p.m, p.n, m[my_index], n[my_index]); pthread_exit(NULL); } // ========================================== WORKER Routine // void *worker(void *args){ int mm, nn, pp, idx; while (TRUE) { pthread_mutex_lock(&count_mut); while (count==0) pthread_cond_wait(&count_nonzero, &count_mut); count = count-1; mm = workPair[count].m; nn = workPair[count].n; idx = workPair[count].idx; //printf("WORKER: mm=%d, nn=%d, ans=%d, idx=%d, count=%d\n",mm, nn, mm%nn, idx, count); fflush(stdout); ans[idx] = mm % nn; done[idx] = 1; pthread_cond_signal(&cond[idx]); pthread_mutex_unlock(&count_mut); } }