// A program that spell checks works in parallel
// By Mike Solomon for Parallel Programming
// Program 2
// 3-18-10
#include <fstream>
#include <iostream>
#include <pthread.h>
#include <stdlib.h>
#include <string>
#include <vector>
using namespace std;
typedef struct
{
string * data_ptr;
int order;
}THREAD_ARG_T;
void *spellCheck ( void * arg )
{
// Cast arg to a pointer of THREAD_ARG_T
THREAD_ARG_T *arg_pointer = static_cast<THREAD_ARG_T *>(arg);
// Get the input stored in arg pointer
string * data_ptr = arg_pointer -> data_ptr;
// Dereference it so I don't have to use *input
// throughout my program
string & data = *data_ptr;
// Get the ordering of it
int order = arg_pointer -> order;
cout << "Thread " << pthread_self() << " stopping by to say hi!"
<< endl;
cout << "My data = " << data << endl;
cout << "My order = " << order << endl;
return NULL;
}
int main (int argc, char *argv[])
{
// inData is like cin
ifstream inData;
// Gets the number of threads
int numThreads = atoi(argv[1]);
// Temporary string to store reading in data
string tempString = "";
// An array of strings for all the input data
//vector<string> input;
vector<THREAD_ARG_T *> input;
// Opens the file for us to read
inData.open(argv[2]);
// File couldn't be opened
if ( !inData )
{
cerr << "Error: file could not be opened" << endl;
exit(1);
}
// Used to keep track of the order of the items
int count = 0;
// While there is still data in the file
while ( !inData.eof() )
{
// Get the next line from indata and
// store it in tempString
getline( inData, tempString );
// Create a thread_arg_t to add to our vector
THREAD_ARG_T * data = new THREAD_ARG_T;
// Set the pointer to the address of this string
(*data).data_ptr = &tempString;
// Set it's ordinal value
(*data).order = count;
// Incremenet the count
count++;
// Push it onto our array
input.push_back(data);
}
// THREAD_ARG_T x = *input.at(0);
// cout << "x.data_ptr = " << x.data_ptr << endl;
// This is slightly complex. As count is incremented
// after each loop we end up with count being one
// greater than the position of the last element.
// Furthermore, we subtract another one because
// the last element is the empty string as C++
// seems to read data in like that.
// In other words, this is the position of the
// last element that we care about.
count = count - 2;
// If the number of threads is greater than the
// number of strings then we shouldn't really
// use that number of threads.
if ( numThreads > count )
{
numThreads = count;
}
// Push it onto the end of the vector
//input.pop_back();
// Close the input stream
inData.close();
// Store the thread pointers in an array of pthread_t*
// elements.
//
// The type of my_thread is pthread_t**, because we
// are creating an array of pointeres.
pthread_t **my_thread = new pthread_t*[numThreads];
// The pointers don't point to anything. Lets fix
// that and allocate a pthread_t for each thread
// and then make the pointers point to them.
for (int i = 0; i < numThreads; i++)
{
my_thread[i] = new pthread_t;
}
//vector <THREAD_ARG_T> arguments;
//int argCount = 0;
// Create the threads themselves (i.e. initialize
// the threads that we just made).
for (int i = 0; i < numThreads; i++)
{
// Get the argument we're going to have this thread
// point towards.
//THREAD_ARG_T argument;
//cout << "Attempting to grab data: " << *input.at(count).data_ptr <<
//" and order = " << count << endl;
// Pass in the information to the argument
//argument.data_ptr = input.at(count).data_ptr;
//argument.order = input.at(count).order;
// Decrement so we go to the previous term
//count--;
// Add this argument to our vector of arguments
//arguments.push_back(argument);
// Creater a pointer to the arguments
THREAD_ARG_T *arg_ptr = input.at(count);
count--;
// ... and convert it to the proper type
void *converted_arg_ptr = static_cast<void *>(arg_ptr);
// Create the thread
if (pthread_create (my_thread[i],
NULL,
spellCheck,
converted_arg_ptr))
{
cout << "Error creating thread " <<
i << '.' << endl;
abort();
}
// Increment the argCounter
//argCount++;
}
// Joing them all together
for (int i = 0; i < numThreads; i++)
{
// pthread_join takes a static pthread_t,
// not a pointer to a pthread t.
// Since my_thread[i] is a pthread_t *, we
// need to dereference it to get a pthread_t.
if (pthread_join (*my_thread[i], NULL) )
{
cout << "Error joining thread." << endl;
abort();
}
}
// Clean up. Since we dynamically allocated each thread,
// we need to deallocate it. But, don't deallocate a thread
// that hasn't exited! Here we know that each thread has
// exited from the pthread_join() call above.
for (int i = 0; i < numThreads; i++)
{
delete my_thread[i];
}
// Finally, deallocate the array of pthread_t pointers.
delete [] my_thread;
exit(0);
}