// file: tgcd.c // This is the thread version of the mgcd.c // problem of computing many gcds. // // Author: Chee Yap // Modified by Chien-I Liao // Mar 2005, Oct 2006 /*************************************************** * 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 gcd threads, each with a pair (m,n) * (4) main thread waits on gcd threads to terminate, * then kills worker thread * (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 * * NOTES: * (1) In solaris or linux, when you link, * you must give the -lpthread flag. * (2) In cygwin, private stack may not work. * So you may need to create array data for the GCD threads * * ***************************************************/ #include #include #define PTHREAD_STACK_MIN 100000 // ========================================= Global variables #define TRUE 1 #define FALSE 0 typedef int boolean; struct 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_attr_t attr; // attribute of thread pthread_t workThread; // id of worker thread pthread_t pthreads[NN]; // array of all gcd threads struct triple inputArgs[NN]; // inputArgs[i] is input triple for i-th thread struct triple 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! //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); // LOCK workPair[count].m = m[my_index]; workPair[count].n = n[my_index]; workPair[count].idx = my_index; count = count+1; ans[my_index]=-1; // ans<0 means not ready //printf("DEBUG 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); // SIGNAL } pthread_mutex_unlock(&count_mut); // UNLOCK while(ans[my_index]<0); pthread_mutex_lock(&count_mut); // LOCK m[my_index] = n[my_index]; n[my_index] = ans[my_index]; pthread_mutex_unlock(&count_mut); // UNLOCK } printf("%d : gcd(%d, %d) = %d \n", my_index, p.m, p.n, m[my_index]); pthread_exit(NULL); } // ========================================== WORKER Routine // void *worker(void *args){ int mm, nn, pp, idx; while (TRUE) { pthread_mutex_lock(&count_mut); // LOCK while (count==0) pthread_cond_wait(&count_nonzero, &count_mut); // WAIT FOR WORK count = count-1; mm = workPair[count].m; nn = workPair[count].n; idx = workPair[count].idx; //printf("DEBUG WORKER: mm=%d, nn=%d, ans=%d, idx=%d, count=%d\n", // mm, nn, mm%nn, idx, count); fflush(stdout); ans[idx] = mm % nn; pthread_mutex_unlock(&count_mut); // UNLOCK } }