POSIX Pthreads
Goals
- Practice working with multi-threaded C programs. This lab will give you a good introduction on how to work with the Pthread library. You will be focusing on applying some of the most important concepts discussed in lecture. (Later labs will delve deeper into the topic.)
- Practice working with C function pointers. The C language has a very interesting feature that allows programs to use functions as parameters to other functions. The concept and the syntax for function pointers can be a little intimidating, but this is something you will have to master in order to use Pthreads.
Credits
The material developed for this lab was developed by Prof. L. Felipe Perrone. Permission to reuse this material in parts or in its entirety is granted provided that this “credits” note is not removed. Additional students files associated with this lab, as well as any existing solutions can be provided upon request by e- mail to: perrone[at]bucknell[dot]edu
Set Up
Follow the Github Classroom instructions to accept and set up the repo for the lab. Name the directory for this lab ~/csci315/Labs/Lab3. Copy the following C source code to your local working directory for this lab:
~cs315/Labs/Lab3/summation.c
This program requires two command line arguments to execute:
- numthreads – an integer value that specifies how many threads will be created, and
- increment – the number of integer values that each thread will work with.
The task performed by this code is simple: It creates the specified number of threads and assigns to each one of them an interval of integer numbers, say [a,b). Each thread computes a value s, which is the summation of the squares of the integers in its interval, that is:
a^2 + (a+1)^2 + (a+2)^2 + … + (b-2)^2 + (b-1)^2
Essentially, this program “parallelizes” the computation of the summation of the squares of integers in the interval [0, numthreads*increment) balancing the load equally among the number of threads specified. We say “parallelizes” in quotes because in a single-core machine, the threads would execute not in parallel, but rather concurrently: splitting the time of one single CPU. If this code runs on a multi-core machine the threads may really run in parallel (this depends on the set up of the library and the OS).
IMPORTANT: The code given to you in the file summation.c is likely to compile with warnings. It is your task to ensure to you eliminate these warnings in the files you will generate using this code as starting point!
Problem 3 [15 points]
In order to compile and link this program, you cannot simply do
$ gcc -std=gnu99 -Wall summation.c -o summation
3.1 Try to compile with the command above to see what happens. Report the undefined symbols that the list of undefined references you see using this Google Form.
It turns out that this program uses functions that are defined in libraries that are not being linked with your code by default. The two libraries in question, for this program, are the math library (which, among many other functions, defines pow(3)) and the pthread library (which defines all the data types and functions for POSIX threads).
Read the manual page of pow(3) and find any text that says “link with…” Pass the flag you find to gcc, when compiling the code. (By the way, this is a linker flag!) This links the math library with your program.
3.2 Write the linker flag that you discovered you need to use in the lab Google Form.
In order to put this flag to use, you should simply append that little bit of text to the invocation of gcc above.
3.3 Write out the correct command to compile summation.c in the lab Google Form.
Now, append to the last invocation of gcc you used the flag -lpthread – the -l is telling gcc this is a linker flag, the pthread names the library to link. If all went as expected, you should now have an executable to run.
Create a rule in your Makefile to compile summation.c into an executable. This rule should be activated when one calls make without any command line arguments (such would be a default target).
When you are done with this, you need to:
- cd ~/csci315/Labs/Lab3
- git pull
- git add [all relevant files needed]
- git commit -m “Lab 3.3 completed”
- git push
Problem 4 [20 points]
Run your summation executable few times, passing different values of number of threads and increment. Start with two threads and a somewhat large increment. Then keeping the increment value fixed, increase the number of threads to see how things might change.
Read the source summation.c carefully and do your best to understand how it works. Now, respond to the questions below in the lab Google Form, writing as concisely and clearly as possible.
- Explain the mechanism by which the main thread passes arguments to the other threads it creates.
- Lines 87, 88, and 89 make calls to function calloc(3). Explain what this function does and why it is preferable to malloc(3) in this type of circumstance. (Hint: Consider the data type that is being dynamically allocated.)
- Explain what is means for a thread to be in detached state (line 95 in source code). Discuss whether or not this program should create detached threads.
- Explain the mechanisms by which the main thread receives the results from each computation thread and by which it synchronizes with them.
- What would happen to the execution of the program if one of the child threads should decide to call exit(3) halfway through its computation? (Modify your source code to include this change and experiment with it. When you are done, leave this line commented out.)
- What would happen if one of the child threads should decide to call execl(3) to run “/bin/ls” in the executable’s current working directory? (Again, modify your source code to include this change and experiment with it. When you are done, leave this line commented out.)
When you are done with this, you need to:
- cd ~/csci315/Labs/Lab3
- git pull
- git add [all relevant files]
- git commit -m “Lab 3.4 completed”
- git push
Problem 5 [15 points]
Copy your summation.c to a new file summation5.c, which will compute the time it takes to execute to completion. To accomplish this, you should instrument the program to call gettimeofday(2) right when starts and then again when it ends.
With a little bit of arithmetic, using the two struct timeval values returned, you can compute the time it took the program to run. Be careful to do the right arithmetic when you subtract two time values. Have this time printed to the standard output exactly before the program terminates. Print the starting and ending time using the following print statements, along with the original print statement that prints the total value,
printf(“Total value computed = %lf\n”, summation); // given in the summation.c
printf(“Starting time : %s\n”, timestring); // you need to construct the time string by calling the proper C functions
printf(“Ending time : %s\n”, timestring); // you need to construct the time string by calling the proper C functions
printf(“Elapse time (u sec) : %ld\n”, elapse_time);
Here is a sample output.
Total value computed = 506.000000 Starting time : Wed Jun 28 11:14:40 2023 Ending time : Wed Jun 28 11:14:40 2023 Elapse time (u sec) : 268
Update your Makefile so it will compile summation5.c properly.
When you are done with this, you need to:
- cd ~/csci315/Labs/Lab3
- git pull
- git add [all relevant files]
- git commit -m “Lab 3.5 completed”
- git push
Problem 6 [20 points]
Copy your summation5.c to a new file summation6.c. In this new version, each thread will compute the time that it takes to execute individually and print the result to the standard output. Furthermore, have each thread print to the standard output the current time before it returns to the main thread. Note that you will have to use a combination of gettimeofday(2) and ctime(3) to produce a human readable date. That is, in addition to the output seen in Problem 5, each thread should print something like the following before returning to the calling thread.
Current time in thread 1234 is : Wed Jun 28 11:14:40 2023
Note that here you will need to print the thread ID as well as the current time. In addition, note that the thread should just call gettimeofday(2) once within the thread code to get the needed information.
Update your Makefile so it will compile summation6.c properly.
Additionally, write in the lab Google Form the responses to the following questions.
6.1 Can you guarantee that the date printed by each thread is always the termination time of that very thread? Briefly explain your reasons.
- cd ~/csci315/Labs/Lab3
- git pull
- git add [all relevant files]
- git commit -m “Lab 3.6 completed”
- git push
Hand In
Before turning in your work for grading, create a text file in your Lab 3 directory called submission.txt. In this file, provide a list to indicate to the grader, problem by problem, if you completed the problem and whether it works to specification. Wrap everything up by turning in this file:
- git pull
- git add ~/csci315/Labs/Lab3/submission.txt
- git commit -m “Lab 3 completed”
- git push
Grading Rubric
Problem 3 [15 points total]
- [3 points] Problem 3.1 – In lab Google Form: identify all undefined reference(s) in summation.c
- [3 points] Problem 3.2 – In lab Google Form: identify the linker flag to use the math library
- [3 points] Problem 3.3 – In lab Google Form: list the correct command to compile summation.c
- [3 points] Program summation.c now compiles correctly with the flags you added in Makefile
- [3 points] The compiled program executes correctly.
Problem 4 [20 points total]
- [3 points] Problem 4.1 – In lab Google Form: passing arguments to threads
- [3 points] Problem 4.2 – In lab Google Form: how calloc may be better than malloc
- [3 points] Problem 4.3 – In lab Google Form: thread detached state
- [3 points] Problem 4.4 – In lab Google Form: thread synchronization and returning results
- [4 points] Problem 4.5 – In lab Google Form: what happens when one thread calls exit
- [4 points] Problem 4.6 – In lab Google Form: what happens when one thread calls execl
Problem 5 [15 points total]
- [10 points] Problem 5.1 – Program summation5.c compiles correctly with proper use of gettimeofday.
- [5 points] Problem 5.2 – Correct results are generated.
Problem 6 [20 points]
- [10 points] Problem 6.1 – Program summation6.c compiles correctly with proper use of gettimeofday in both the calling thread and the child thread.
- [5 points] Problem 6.2 – Correct results are generated.
- [5 points] Problem 6.3 – In lab Google Form: explain if the time in threads are true time when the threads exit.
Note: [up to -10 points] An incorrect or incomplete Makefile to build all programs in lab and pre-lab.