DEPARTAMENTO DE INFORMÁTICA
Fundamentos de Sistemas de Operação 24/25
Concurrent Programming with Pthreads
LAB 4
Introduction and Lab objective
A thread (or lightweight process) represents an execution flow within the context of a process that can be
scheduled independently of other threads. All threads residing in a particular process share its context,
e.g., the threads may communicate using the process’ global variables and they may use its resources as
long as the process exists.
POSIX Threads is a standard API defining a set of operations for thread management, namely thread
creation and control (priority definition, thread suspension and deletion) and thread synchronization.
Implementations of the standard are known as POSIX Threads or Pthreads.
The objective of this lab is the utilization of the Pthreads API for concurrent and parallel programming
using the C language.
Using the Pthreads API
The following program (lab-04s.c) fills a big array of integers with random values between 0 and 3; after
this, it will count the number of elements equal to 3 that exist in the array.
#define SIZE 256*1024*1024
int *array;
int length, count;
int count3s() {
count = 0;
for (int i=0; i < length; i++)
if (array[i] == 3) count++;
}
int main( ) {
array= (int *)malloc(SIZE*sizeof(int));
length = SIZE;
srand(0); // always the same sequence
for (int i=0; i < length; i++){
array[i] = rand() % 4;
}
count3s();
printf("Count of 3s = %d\n", count);
return 0;
}
The number’s sequence generated by the function rand( ) is always the same because it uses a constant
value as seed. Execute the previous program several times and verify that the result is always the same.
You may get the time it takes to execute the program using the time command, as in
time ./lab-04s
1
Parallel version
Use the Pthreads library calls to create a parallel version of this sequential program. The program should
be modified so that it uses a given numbers of threads to count the number 3; each thread counts the
number 3 in a distinct part (a distinct slice) of the array (why this is a good strategy?).
#define SIZE 256*1024*1024
int *array;
int length, count;
int length_per_thread;
void *count3s_thread(. . .) {
// TODO: The code executed by each thread; the name count3s_thread is just a suggestion
}
void count3s(int nthreads){
// TODO: The code with the creation of multiple threads to count 3s
}
int main( int argc, char *argv[]){
if ( argc != 2 ) {
printf("Usage: %s <number_of_threads>\n", argv[0]);
printf("%d must be divisible by <number of threads>\n", SIZE);
return 1;
}
int n = atoi(argv[1]);
if ( (SIZE % n) != 0 ) {
printf("%d must be divisible by <number of threads>\n", SIZE);
return 1;
}
array= (int *)malloc(SIZE*sizeof(int));
length = SIZE;
length_per_thread = SIZE / n;
printf("Using %d threads; length_per_thread = %d\n", n, length_per_thread);
srand(0);
for (int i=0; i < length; i++){
array[i] = rand() % 4;
}
count3s(n);
printf("Count of 3s = %d\n", count);
return 0;
}
Complete the program (lab-04p.c) and test with only one thread and verify that the result is the same as
the sequential version. When compiling with gcc in Linux add the -pthread option (see Makefile). After
execute the program with more than one thread and verify that the result is probably wrong and different
for each run (if possible, try on a computer/VM with more than one core). Why the wrong results?
Correct Parallel Execution
Modify the code from the previous step to correct the problem.
Bibliography
• Lectures 7 and 8.
• Concurrency from FSO recommended book [Link]
[Link] and following chapters.
• On-line manual pages (man) for the Pthreads library.