// file: gcd_th.c // Name: Jason Shuey // Email: jds308@nyu.edu // Course: Comp. Sys. Org. II, Spring 2005, Prof. Yap // Homework 4 // // A program using POSIX threads to compute the GCD of various // pairs of numbers using the Euclidean Algorithm. #include #include #define MAXNUMPAIRS 20 void * worker_th (void *); void * gcd_th (void *); int numToSpawn; int m[MAXNUMPAIRS], mm[MAXNUMPAIRS], n[MAXNUMPAIRS], nn[MAXNUMPAIRS]; int workAvail[MAXNUMPAIRS]; // keeps track of whether a particular thread has work available to be done unsigned count = 0; pthread_mutex_t count_lock; pthread_cond_t count_nonzero; main(int argc, char **argv) { int temp; pthread_t worker; pthread_t gcd[MAXNUMPAIRS]; // check command line input to make sure it's a set of pairs of numbers if (argc % 2 == 0 || argc == 1) { printf("Input must be a set of pairs of numbers.\n"); exit(0); } // set them all to 0 (currently no available work to be done) int k; for(k = 0; k < MAXNUMPAIRS; k++) workAvail[k] = 0; // the number of gcd threads to spawn (number of pairs of numbers) numToSpawn = (argc - 1) / 2; // create threads int i, index[numToSpawn]; if (0 != pthread_create(&worker, NULL, worker_th, NULL)) perror("create pthread"); for(i = 0; i < numToSpawn; i++) { sscanf(argv[2*i + 1], "%d", &m[i]); sscanf(argv[2*i + 2], "%d", &n[i]); // keep a copy of the original values of the numbers for printing mm[i] = m[i]; nn[i] = n[i]; // swap numbers to make sure that m is always greater than or equal to n if(m[i] < n[i]) { temp = m[i]; m[i] = n[i]; n[i] = temp; } index[i] = i; if (0 != pthread_create(&gcd[i], NULL, gcd_th, (void *)&index[i])) perror("create pthread"); } // wait until all gcd threads have exited for(i = 0; i < numToSpawn; i++) pthread_join(gcd[i], NULL); // kill the worker thread pthread_cancel(worker); // exit the main thread. pthread_exit(NULL); } // worker thread that does the actual computation on pairs (m, n) void * worker_th (void *arg) { printf("\nWorker Thread\n"); while(1) { int i, mod; // Waits for there to be work available. pthread_mutex_lock(&count_lock); while(count == 0) pthread_cond_wait(&count_nonzero, &count_lock); count = count - 1; // do work on a pair by finding one that is ready and computing m mod n for(i = 0; i < numToSpawn; i++) { if(workAvail[i]>0) { printf("work available, i=%d\n", i); mod = m[i] % n[i]; m[i] = n[i]; n[i] = mod; workAvail[i] = 0; } } pthread_mutex_unlock(&count_lock); } } // gcd thread that submits pairs (m, n) to the worker thread. Once it has computed the gcd of a pair, it prints the result and then exits. void * gcd_th (void *arg) { printf("\nGCD Thread %d\n", *(int *)arg); while(1) { pthread_mutex_lock(&count_lock); // GCD has been found printf("\nInside GCD Thread %d, m=%d, n=%d\n", *(int *)arg, m[*(int *)arg], n[*(int *)arg]); if(n[*(int *)arg] == 0) { printf("GCD(%d, %d) = %d", mm[*(int *)arg], nn[*(int *)arg], m[*(int *)arg]); pthread_exit(NULL); } // Indicate that work needs to be done for this pair else { workAvail[*(int *)arg] = 1; } // Tell worker that work is now available if it is the only work available if (count == 0) pthread_cond_signal(&count_nonzero); count = count + 1; pthread_mutex_unlock(&count_lock); sleep(0.4); } }