Download as pdf or txt
Download as pdf or txt
You are on page 1of 12

1

Parallel Computing
Practical 2
Submission date :-29-01-2022

NAME : Neha Vijay Khairnar

BRANCH: I.T.

ID: 191081036

BATCH: IV
2

Practical 2a
Aim: To write an OpenMP program for illustrating the Fork Join model.

Theory:
● OpenMP (Open Multi-Processing) is an API that supports multi-platform shared memory
multiprocessing programming in C,C++ and Fortran on most processor architectures and
operating systems, including Solaris, AIX, HP-UX, Linux, Mac OS X, and Windows platforms.
● It consists of a set of compiler directives, library routines, and environment variables that
influence run-time behavior.
● OpenMP identifies parallel regions as blocks of code that may run in parallel. Application
developers insert compiler directives into their code at parallel regions, and these directives
instruct the OpenMP run-time library to execute the region in parallel.
● In addition to providing directives for parallelization, OpenMP allows developers to choose
among several levels of parallelism. E.g., they can set the number of threads manually. It also
allows developers to identify whether data are shared between threads or are private to a
thread.
● OpenMP is available on several open-source and commercial compilers for Linux, Windows,
and Mac OS X systems.
● OpenMP is an implementation of multithreading, a method of parallelizing whereby a
master thread (a series of instructions executed consecutively) forks a specified number of
slave threads and a task is divided among them.
● The threads then run concurrently, with the runtime environment allocating threads to
different processors.
● When OpenMP encounters the directive #pragma omp parallel it creates as many threads
which are processing cores in the system. Thus, for a dual-core system, two threads are
created, for a quad-core system, four are created; and so forth. Then all the threads
simultaneously execute the parallel region. When each thread exits the parallel region, it is
terminated. OpenMP provides several additional directives for running code regions in
parallel, including parallelizing loops.
3

● The Fork and Join Model. OpenMP programs start with a master thread, running
sequentially until they reach a parallel section where they fork into multiple worker
threads. At the end of the parallel section the threads re-join into the master thread.

● The section of code that is meant to run in parallel is marked accordingly, with a
preprocessor directive that will cause the threads to form before the section is executed.
● The omp_get_num_threads() routine returns the number of threads in the team that is
executing the parallel region to which the routine region binds. If called from the
sequential part of a program, this routine returns 1.
● Each thread has an id attached to it which can be obtained using a function (called
omp_get_thread_num( ) ).
● The omp_get_thread_num() routine returns the thread number of the calling thread,
within the team that is executing the parallel region to which the routine region binds. The
thread number is an integer between 0 and one less than the value returned by
omp_get_num_threads(), inclusive. The thread number of the master thread of the team is
0. The routine returns 0 if it is called from the sequential part of a program.
● The thread id is an integer, and the master thread has an id of 0.
4

● After the execution of the parallelized code, the threads join back into the master thread,
which continues onward to the end of the program.
● By default, each thread executes the parallelized section of code independently.
● Work-sharing constructs can be used to divide a task among the threads so that each thread
executes its allocated part of the code. Both task parallelism and data parallelism can be
achieved using OpenMP in this way.
● The runtime environment allocates threads to processors depending on usage, machine
load and other factors. The number of threads can be assigned by the runtime environment
based on environment variables or in code using functions.
● The OpenMP functions are included in a header file labelled omp.h in C/C++.
● The output may also be garbled because of the race condition caused from the two threads
sharing the standard output.

Program:
#include<stdio.h>
#include<omp.h>

int main(){
int nthreads, tid;
/* Fork a team of threads giving them their own copies of variables */
#pragma omp parallel private(nthreads, tid){
/* Obtain thread number */
tid = omp_get_thread_num();
printf("Hello World from thread = %d\n", tid);
/* Only master thread does this */
if (tid == 0){
nthreads = omp_get_num_threads();
printf("Number of threads = %d\n", nthreads);
}
} /* All threads join master thread and disband */
}
5

Output:

Conclusion: Hence we successfully implemented fork join model using OpenMP and C
as programming language. We understood how threads are created and how a
master thread works and how data parallelism and task parallelism is achieved
in a synchronized manner.
6

Practical 2b
Aim: To write an OpenMP program for solving the Producer Consumer problem.
Theory:

● The Producer-Consumer problem is a classical multi-process synchronization problem, that


is we are trying to achieve synchronization between more than one process.
● There is one Producer in the producer-consumer problem, Producer is producing some
items, whereas there is one Consumer that is consuming the items produced by the
Producer. The same memory buffer is shared by both producers and consumers which is of
fixed-size.
● The task of the Producer is to produce the item, put it into the memory buffer, and again
start producing items. Whereas the task of the Consumer is to consume the item from the
memory buffer.
● Below are a few points that considered as the problems occur in Producer-Consumer:
➔ The producer should produce data only when the buffer is not full. In case it is found
that the buffer is full, the producer is not allowed to store any data into the memory
buffer.

➔ Data can only be consumed by the consumer if and only if the memory buffer is not
empty. In case it is found that the buffer is empty, the consumer is not allowed to use
any data from the memory buffer.

➔ Accessing memory buffers should not be allowed to producer and consumer at the
same time.

● In this program, the master thread will act as a producer while the other threads will wait
until the master thread creates a buffer, and once added the master notifies the threads
using a shared variable and all other threads will consume the data.
7

Fig- General working scheme of producer-consumer

Program:
#include<stdio.h>
#include<omp.h>

int main(){
int i=0;
int x=0;
#pragma omp parallel shared(i)
{
if(omp_get_thread_num()==0){
printf("Master thread with Thread ID:%d\n", omp_get_thread_num());
printf("Since it is the producer thread It is adding some data to be consumed by other
consumer threads\n");
i+=10;
x=1;

} else{
8

while(x==0)
printf("Waiting for buffer to be filled. Thread ID: %d\n",omp_get_thread_num());
#pragma critical
{
if(i>0){
printf("Data is consumed by Consumer with Thread ID: %d\n",omp_get_thread_num());
i-=5;
} else {
printf("Could not find any data for thread ID: %d\n",omp_get_thread_num());
}
}
}
}
}

Output:
9

Conclusion: Hence we studied and understood the producer consumer problem and
implemented it using OpenMP.
10

Practical 2c
Aim: To write an OpenMP Program for Matrix Multiplication.
Theory:
● Matrix multiplication is a binary operation that produces a matrix from two matrices.
● For matrix multiplication, the number of columns in the first matrix must be equal to the
number of rows in the second matrix and the result will have the same number of rows as
the 1st matrix, and the same number of columns as the 2nd matrix.
● To multiply a matrix by another matrix we need to do the "dot product" of rows and
columns.
● In this practical, we are writing a C program to perform matrix multiplication using
OpenMP.

Program:
#include<stdio.h>
#include <stdlib.h>
#include<omp.h>

int main(){
int i,j,k,m,n,p,o;
printf("Enter the number of rows in Matrix 1:");
scanf("%d",&m);
int *matrixA[m];
printf("Enter the number of columns in Matrix 1:");
scanf("%d",&n);
printf("Enter the number of rows in Matrix 2:");
scanf("%d",&o);
if(o != n){
printf("Number of columns in 1st matrix are %d and number of rows in matrix 2 are %d",n ,o
printf("\nNumber of columns in 1st matrix must be equal to number of rows in matrix 2\n");
return 0;
}
printf("Enter the number of columns in Matrix 2:");
scanf("%d",&p);
for(i=0;i<m;i++){
matrixA[i] = (int *)malloc(n*sizeof(int));
11

}
printf("----Enter the values for matrix row-wise----\n");
for(i=0;i<m;i++){
for(j=0;j<n;j++){
scanf("%d",&matrixA[i][j]);
}
}
int *matrixB[n];
for(i=0;i<n;i++){
matrixB[i] = (int *)malloc(p*sizeof(int));
}
printf("<--Now Input the values for matrix 2 row-wise-->\n");
for(i=0;i<o;i++){
for(j=0;j<p;j++){
scanf("%d",&matrixB[i][j]);
}
}
int matrixC[m][p];
#pragma omp parallel private(i,j,k) shared(matrixA,matrixB,matrixC)
{
#pragma omp for schedule(static)
for (i=0; i<m; i=i+1){
for (j=0; j<p; j=j+1){
matrixC[i][j] = 0;
for (k=0; k<n; k=k+1){
matrixC[i][j]=(matrixC[i][j])+((matrixA[i][k])*(matrixB[k][j]));
}
}
}
}
printf("The output after Matrix Multiplication is: \n");
for(i=0;i<m;i++){
for(j=0;j<p;j++){
printf("%d \t",matrixC[i][j]);
printf("\n");
}
}
return 0;
}
12

Output:

Conclusion: Hence we successfully implemented matrix multiplication using OpenMP


and C programming language.

You might also like