// // 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. // // In this version, we use classes to hide some of the low-level // details of multithreading and avoid global variables. // #include #include #include #include // has setprecision() #include // has exit(), etc. #include "pthreads-threadmgr.h" // has threadManager class #include "pthreads-lock.h" // has lockObj class #include "timer.h" // has timer() // ---- Class for thread --------------------------------------------- // See function definitions below for comments about functions. class sumThreadObj { public: typedef sumThreadObj * ptr; sumThreadObj(const int myID, int * Nptr, int * Pptr, double * nums, double * sumPtr); void run(void); private: static lockObj sumLock; // lock for sum int myID; // unique ID for thread // pointers to shared vars: int * Nptr; // number of numbers to sum int * Pptr; // number of threads double * nums; // numbers to sum double * sumPtr; // sum }; // ---- Function declarations ---------------------------------------- double * getFileInput(const char filename[], int & count); double * getRandomInput(const char inputCount[], int & count); // ---- 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); } // Time before initialization. double startInitTime = timer(); int P = atoi(argv[1]); // number of threads int N; // number of numbers to sum double * nums; // numbers to sum if (argc == 3) nums = getFileInput(argv[2], N); else nums = getRandomInput(argv[3], N); double sum; // sum // Time after initialiation and before compute. double startTime = timer(); // Create P sumThreadObj objects, one for each thread, to // hold parameters. sumThreadObj::ptr * threadObjs = new sumThreadObj::ptr[P]; for (int i = 0; i < P; ++i) threadObjs[i] = new sumThreadObj(i, &N, &P, nums, &sum); { // make a block here so destructor for threadManager is // called while we're timing. // Create and start P new threads. threadManager tMgr(P, threadObjs); // Wait for all threads to complete. tMgr.join(); } // Clean up threads-related stuff. for (int i = 0; i < P; ++i) delete threadObjs[i]; delete [] threadObjs; // 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; // Clean up and exit. delete [] nums; return EXIT_SUCCESS; } // ---- Functions, etc., for sumThreadObj class -------------------- // Constructor. sumThreadObj::sumThreadObj(const int myID, int * Nptr, int * Pptr, double * nums, double * sumPtr) { this->myID = myID; this->Nptr = Nptr; this->Pptr = Pptr; this->nums = nums; this->sumPtr = sumPtr; } // Member function containing code each thread should execute. void sumThreadObj::run(void) { // Initialization. double partialSum = 0; int N = *Nptr; int P = *Pptr; 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). sumLock.lock(); (*sumPtr) += partialSum; sumLock.unlock(); } // Initialization for static member variable. lockObj sumThreadObj::sumLock; // ---- 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; }