Create a week12 subdirectory in your weeklylab subdirectory and copy over some files:
cd cs31/weeklylab pwd mkdir week12 ls cd week12 pwd cp ~kwebb/public/cs31/week12/* . ls Makefile data_large.txt data_small.txt findmax.cThen type make to build the executable files.
For this exercise, we'll write a C program that searches through a (potentially very large) array to find (1) the maximum data value and (2) the number of times that value appears in the data set. Since we're learning about threads, we'll divide up our data set into partitions and assign one thread to each partition. The steps we go through here will be similar to what you'll need to do when parallelizing the game of life for lab 9.
You can invoke the program with two arguments, the file name to use when reading data and the number of threads:
# Use the "data_small.txt" input file and divide it among four threads $ ./findmax data_small.txt 4
The code to read in the input file, parse_file(), is provided for you. It returns an array of integers and sets the num_values variable so that you know how many data points you have. The provided code also sets num_threads to the value of the second parameter.
In some ways, creating threads resembles the way you created processes. For example, with processes, we used a pid_t to represent the process ID of the child process. Here, we'll use a pthread_t to represent a new thread. The exercise code allocates an array of pthread_t types, one for every thread. The thread library will fill in the details of the pthread_t when you call pthread_create. Thus, when you're creating thread N, give pthread_create the address of the Nth element of the pthread_t array, and it will fill in the thread's information so that you can reference that thread again later (e.g., join).
Also like processes, you may want to wait until a thread has terminated (and check it's status) before moving forward. For processes, we used waitpid(). For threads, we'll use pthread_join(), which takes the pthread_t of the thread you want to wait on. The pthread_join() function will also give you the thread's return value, if you want it (we don't care for this exercise).
Unlike fork(), with threads we don't create a clone of the current process. Instead, we give pthread_create the name of the function that we want it to execute in a separate thread. The function you tell it to execute must be of the form:
void *function(void *argument)
That is, the function must return a pointer (NULL is fine, if you don't care about returning anything), and it must accept exactly one pointer as an argument (NULL also fine here, if you don't want to pass anything in). The type of both pointers is the generic "void *", since the thread library has no idea what you're planning to do in the thread. This means we'll have to do some casting when we pass arguments.
Since pthread_create() only allows us to pass one argument to a thread (a pointer to something, we'll have to be creative if we want to start up a thread with more than one piece of information. The common solution is to pass a pointer to a struct, where the struct has a field for every piece of information you'd like the thread to have. The provided exercise code already defines a struct named thread_args and creates an array of those structs with one element per thread. When creating thread N, we'll fill in the parameters for thread N in the Nth element of the array. We can then pass pthread_create() a pointer to the Nth array element.
When the thread starts up, it can access the pointer argument to get access to the struct you passed it. Since the argument is declared as generic type "void *", you'll need to cast it to the type you know it is: a struct thread_args pointer. After doing that, you'll be able to use it's fields as you normally would with a struct pointer (i.e., the -> operator).
To fully solve this exercise (and lab 9), you'll need to use two forms of synchronization: mutex locks and barriers. When using one of these primitives, each thread that wishes to use it must have a pointer to the same pthread_XXX_t.