You are on page 1of 7

Operating Systems

Lab assignment 5: Developing multi-threaded applications

Objectives
1. To develop multi-threaded application programs
2. To demonstrate the use of threads in matrix multiplication

Guidelines
As noted in the class text there is an increasing importance of parallel processing that led to the development of
lightweight user-level thread implementations. Even so, the topic of whether threads are a better programming
model than processes or other alternatives remains open. Several prominent operating systems researchers have
argued that normal programmers should almost never use threads because (a) it is just too hard to write multi-
threaded programs that are correct and (b) most things that threads are commonly used
for can be accomplished in other, safer ways. These are important arguments to understand—even if you agree
or disagree with them, researchers point out pitfalls with using threads that are important to avoid. The most
important pitfall is the concurrent access of threads to shared memory. When threads concurrently read/write to
shared memory, program behavior is undefined. This is because thread scheduling on the CPU is non-
deterministic. The program behavior can completely change when you rerun the program.

To ensure a deterministic behavior of programs where threads cooperate to access shared memory, a
synchronization mechanism needs to be implemented. Consequently,
1. The program behavior will be related to a specific function of input, not of the sequence of which thread
runs first on the CPU.
2. The program behavior will be deterministic and will not vary from run to run.
3. These facts should not be IGNORED, otherwise the compiler will mess up the results and will not be
according what is thought would happen.

This lab is designed to give you the first hands-on programming experience on developing multi-threaded
applications. In this and the next upcoming lab, you will have a chance to work with Pthreads and develop a multi-
threaded application.

C Program with threads


In the text, the thread API has been discussed. It has been noted that threads run on the CPU in different orders.
Demonstrate each of the following steps to the TA to get a grade on this part of the lab assignment.

Lab assignment 5 1/4


Pthread_create()

Step 1. Compile and run the following program, then #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>

void *go(void *);


#define NTHREADS 10
pthread_t threads[NTHREADS];
int main() {
int i;
for (i = 0; i < NTHREADS; i++)
pthread_create(&threads[i], NULL, go, &i);
for (i = 0; i < NTHREADS; i++) {
printf("Thread %d returned\n", i);
pthread_join(threads[i],NULL);
}
printf("Main thread done.\n");
return 0;
}
void *go(void *arg) {
printf("Hello from thread %d with iteration %d\n", (int)pthread_self(), *(int *)arg);
return 0;
}

Explain what happens when you run this threadHello.c program; can you list how many threads are
created and what values of i are passed? Do you get the same result if you run it multiple times? What if
you are also running some other demanding processes (e.g., compiling a big program, playing a Flash
game on a website, or watching streaming video) when you run this program?

The function go() has the parameter arg passed a local variable. Are these variables per-thread or
shared state? Where does the compiler store these variables’ states?

The main() has local variable i. Is this variable per-thread or shared state? Where does the compiler
store this variable?

Write down your observations. You probably have seen that there is a bug in the program, where
threads may print same values of i. Why?

Step 2. Write the fix for the program in Step 1, then run your revised program to demonstrate your fix.

Matrix multiplication with threads


Step 3. Write a program that uses threads to perform a parallel matrix multiply. To multiply two matrices, C =
A*B, the result entry C(i,j) is computed by taking the dot product of the ith row of A and the jth column of
B: Ci,j = SUM A(i,k)*B(k,j) for k = 0 to N-1, where N is the matrix size. We can divide the work by creating
one thread to compute each value (or each row) in C, and then executing those threads on different
processors in parallel on multi-processor systems. As shown in the following figure, each is cell in the
resulting matrix is the sum of the multiplication of row elements of the first matrix by the column
elements of the second matrix.

Lab assignment 5 2/4


You may fill in the entries of A and B matrices (double matrixA[N][M], matrixB[M][L] ) using a random
number generator as below:
srand(time(NULL));
for (int i = 0; j < N; i++)
for (int j = 0; j < M; j++)
matrixA[i][j] = rand();

srand(time(NULL));
for (int i = 0; j < M; i++)
for (int j = 0; j < L; j++)
matrixA[i][j] = rand();

The following are important notes:


- The number of columns of the first matrix must be equal to the number of rows in the second matrix.
- The values of N, M, and L must be large to exploit parallelism (e.g. N, M, L = 1024).
- The output matrix would be defined double matrixC[N][L];
- The Matrix multiplication is a loosely coupled problem and so decomposable, i.e. multiplication of each
row of matrixA with all columns of matrix can be performed independently and in parallel
- The number of threads to be created in the program equals to N and each thread i would be performing
the following task:
for (int j = 0; j < L; j++){
double temp = 0;
for (int k = 0; k < M; k++){
temp += matrixA[i][k] * matrixB[k][j];
}
matrixC[i][j] = temp;
}

- The main thread needs to wait for all other threads before it displays the resulting matrixC

Requirements to complete the lab


1. Show the TA correct execution of the C programs.
2. Submit your answers to questions, observations, and notes as .txt file and upload to Camino
3. Submit the source code for all your programs as .c file(s) and upload to Camino.

Be sure to retain copies of your .c and .txt files. You will want these for study purposes and to resolve any grading
questions (should they arise)

Please start each program/ text with a descriptive block that includes minimally the following information:

# Name: <your name>


# Date: <date> (the day you have lab)

Lab assignment 5 3/4


# Title: Lab5 – task
# Description: This program computes … <you should
# complete an appropriate description here.>

Lab assignment 5 4/4


1 // Name: <Thomas Wooten>
2 // Date: <April 06,2021>
3 // Title: Lab 5
4 // Description: Write a program that uses threads to perform a parallel matrix multiply
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <pthread.h>
9 #include <time.h>
10
11 // Number of columns of the first matrix must be equal to the number of rows in the
second matrix.
12 // Matrice A = double matrixA[N][M]
13 // Matrice B = double matrixB[M][L]
14 // N, M, L = 1024
15 // Constants N, M, L, = VALUE (1024)
16 #define N 1024
17 #define M 1024
18 #define L 1024
19
20 // The number of threads to be created in the program equals to N (rows in first matrix)
21 #define NTHREADS 1024
22
23 //declare matrix variables
24 double matrixA[N][M];
25 double matrixB[M][L];
26 double matrixC[N][L];
27
28 // Function each thread will run
29 void *multiThread(void *arg);
30
31 // Function to print matrix ( row, col, matrixVariable)
32 void printMatrix(int row, int col, double matrix[row][col]);
33
34 // main function (driver)
35 int main() {
36
37 // performance measures variables
38 clock_t start,end;
39
40 // initilize values in matrix A
41 for (int i = 0; i < N; i++) {
42 for (int j = 0; j < M; j++) {
43 matrixA[i][j] = (double) 1.0 * rand(); //convert int to double
44 }
45 }
46
47 // initilize values in matrix B
48 for (int i = 0; i < M; i++) {
49 for (int j = 0; j < L; j++) {
50 matrixB[i][j] = (double) 1.0 * rand(); //convert int to double
51 }
52 }
53
54 // print matrix A
55 printf("Matrix A\n");
56 printMatrix(N, M, matrixA);
57 printf("\n");
58 // print matrix B
59 printf("Matrix B\n");
60 printMatrix(M, L, matrixB);
61 printf("\n");
62
63 printf("Calculating matrixA [%d][%d] * matrixB[%d][%d] .....\n", N, M, M, L);
64
65 // start performance measure
66 start = clock();
67
68 // declare threads
69 pthread_t threads[NTHREADS];
70
71 // create threads
72 for(int i = 0; i < NTHREADS; i++){
73 pthread_create(&threads[i], NULL, multiThread, i);
74 }
75
76 // join threads
77 for(int i = 0; i < NTHREADS; i++){
78 pthread_join(threads[i], NULL);
79 }
80
81 // stop performace measure
82 end = clock();
83
84 // print matrix C
85 printf("Matrix C\n");
86 printMatrix(N, L, matrixC);
87 printf("\n");
88
89 printf("Main Thread Complete\n");
90 printf("Calculation time: %f\n\n", ((double) (end - start)) / CLOCKS_PER_SEC);
91
92 return 0;
93 }
94
95 // Function each thread will run
96 void *multiThread(void *arg){
97 int i = (int*) arg;
98 for (int j = 0; j < L; j++){
99 double temp = 0;
100 for (int k = 0; k < M; k++){
101 temp += matrixA[i][k] * matrixB[k][j];
102 }
103 matrixC[i][j] = temp;
104 }
105 return NULL;
106 }
107
108 // Function to print matrix ( row, col, matrixVariable)
109 void printMatrix(int row, int col, double matrix[row][col]){
110 for (int i = 0; i < row; i++) {
111 for (int j = 0; j < col; j++) {
112 printf("[%.1f]", matrix[i][j]);
113 }
114 printf("\n");
115 }
116 }
117
1 // Name: <Thomas Wooten>
2 // Date: <April 06,2021>
3 // Title: Lab 5
4 // Description: Write the fix for the program in Step 1
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <pthread.h>
9
10 void *go(void *);
11
12 #define NTHREADS 10
13 pthread_t threads[NTHREADS];
14 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
15
16 int main() {
17
18 int i;
19
20 for (i = 0; i < NTHREADS; i++){
21 pthread_create(&threads[i], NULL, go, &i);
22 }
23
24 for (i = 0; i < NTHREADS; i++) {
25 pthread_join(threads[i],NULL);
26 printf("Thread %d returned\n", i);
27 }
28
29 pthread_mutex_destroy(&lock);
30 printf("Main thread done.\n");
31 return 0;
32 }
33
34 void *go(void *arg) {
35 static int i = 0;
36 pthread_mutex_lock(&lock);
37 printf("Hello from thread %d with iteration %d\n", (int)pthread_self(), i);
38 i=i+1;
39 pthread_mutex_unlock(&lock);
40 return 0;
41 }
42

You might also like