// // Program to add numbers (read in from file, or generated // randomly). // // Command-line arguments: // (1) number of threads to use (P) // (2) name of file containing numbers (doubles) // or "-n N" to randomly generate N doubles. // #include #include #include #include // has setprecision() #include // has exit(), etc. #include // has pthread_ routines #include "timer.h" // has timer() // ---- Global variables --------------------------------------------- // (Global variables are a bit ugly, but this is an easy way to create // variables all threads can access.) int N; // number of numbers to sum int P; // number of threads double *nums; // numbers to sum double sum; // sum pthread_mutex_t sumLock; // lock for shared variable "sum" // ---- Function declarations ---------------------------------------- double * getFileInput(const char filename[], int & count); double * getRandomInput(const char inputCount[], int & count); void * addSome(void * threadArg); // ---- Main program ------------------------------------------------- int main(int argc, char* argv[]) { // Process command-line arguments. if (argc < 3) { cerr << "Usage: " << argv[0] << " numThreads [inputfile | -n N]\n"; exit(EXIT_FAILURE); } P = atoi(argv[1]); // Time before initialization. double startInitTime = timer(); if (argc == 3) nums = getFileInput(argv[2], N); else nums = getRandomInput(argv[3], N); // Time after initialiation and before compute. double startTime = timer(); // Initialize sum, lock. pthread_mutex_init(&sumLock, NULL); sum = 0; // no need to lock here since we have // only one thread at this point. // Set up IDs for threads. int * threadIDs = new int[P]; for (int i = 0; i < P; ++i) threadIDs[i] = i; // Start P new threads. pthread_t * threads = new pthread_t[P]; for (int i = 0; i < P; ++i) pthread_create(&threads[i], NULL, addSome, (void *) &threadIDs[i]); // Wait for all threads to complete. for (int i = 0; i < P; ++i) pthread_join(threads[i], NULL); // Clean up. pthread_mutex_destroy(&sumLock); delete [] threadIDs; delete [] threads; // Time after compute. double endTime = timer(); // Print results. cout << "Sum = " << setprecision(10) << sum << endl; cout << "Added " << N << " numbers using " << P << " threads\n"; cout << "Time to compute sum (seconds) = " << setprecision(4) << endTime - startTime << endl; cout << "Total time (seconds) = " << setprecision(4) << endTime - startInitTime << endl; return EXIT_SUCCESS; } // ---- Code to be executed by each thread --------------------------- // Computes partial sum of N/P of the elements and adds its to sum. void * addSome(void * threadArg) { int * myID = (int *) threadArg; // Initialization. double partialSum = 0; // Originally the plan was to have thread i add up elements // i, i+P, i+2P, etc., but this appears to be significantly // slower (on the system on which it was tried), probably // because of details of caching. int numsPerThread = (N+P-1)/P; int first = (*myID) * numsPerThread; int limit = first + numsPerThread; if (limit > N) limit = N; // Calculate partial sum. for (int i = first; i < limit; ++i) partialSum += nums[i]; // Add to global sum (using lock to be sure only one thread // at a time performs this operation). pthread_mutex_lock(&sumLock); sum += partialSum; pthread_mutex_unlock(&sumLock); pthread_exit((void *) NULL); } // ---- Other functions ---------------------------------------------- // Function to get input from file. double * getFileInput(const char filename[], int & count) { ifstream infile; infile.open(filename); if (!infile) { cerr << "Input file " << filename << " not found\n"; exit(EXIT_FAILURE); } double temp; vector vTemp; while (infile >> temp) vTemp.push_back(temp); infile.close(); count = vTemp.size(); double * numsToReturn = new double[count]; copy(vTemp.begin(), vTemp.end(), numsToReturn); return numsToReturn; } // Function to generate input randomly. double * getRandomInput(const char inputCount[], int & count) { count = 0; count = atoi(inputCount); if (count <= 0) { cerr << "Count is not numeric\n"; exit(EXIT_FAILURE); } double * numsToReturn = new double[count]; for (int i = 0; i < count; ++i) numsToReturn[i] = (double) rand() / (double) (RAND_MAX); return numsToReturn; }