You are on page 1of 4

OpenMP

Instalare

Utilizare

Elemente cheie
Fork-join

Shared memory parallelism

Compilare program C cu suport de OpenMP: gcc -fopenmp my_program.c -o my_program


apt-get install libgomp1
In codul sursa se foloseste: #include <omp.h>
Suport in GCC, CLANG, Microsoft Visual C++, Intel C Compiler,
etc (http://openmp.org/wp/openmp-compilers/)

Setare numar thread-uri din program, la o valoare diferita de cea detectata automat de OpenMP:
omp_set_num_threads(int nr_threads) sau export OMP_NUM_THREADS=nr_threads

API

Fiecare directiva incepe cu #pragma omp


Format general: #pragma omp DIRECTIVE-NAME [CLAUSE] NEWLINE
1. DIRECTIVE-NAME

Generala

Tip

Nume directiva

parallel

Work-sharing

for

Efect

Exemplu pentru 4 thread-uri

Output pentru 4 thread-uri

Marcheaza un bloc ce se va executa in paralel de


OMP_NUM_THREADS thread-uri

#pragma omp parallel


{
printf("Hello World!\n");
}

Hello
Hello
Hello
Hello

#pragma omp for private(i)


for (i=0; i<5; i++) {
printf("%d ", i);
}

0 1 2 3 4

Lucrul util facut in cadrul unei bucle este impartit intre toate threadurile. Fiecare thread va primi cate o iteratie a for-ului.

Daca exista mai multe declaratii for imbricate, se poate folosi


impreuna cu clauza collapse(COUNT). In acest caz, intreg
numarul de iteratii ale tuturor for-urilor se vor imparti intre thread-uri.
Parametrul dat clauzei reprezinta numarul de for-uri care urmeaza a fi
implicate in operatia de collapse

#pragma omp parallel for private(j) collapse(2)


for (i = 0; i < 4; i++)
for (j = 0; j < 100; j++)
...

In acest caz, cele 4 * 100 iteratii vor fi impartite


celor 4 thread-uri

#pragma omp parallel sections


{
printf("Hi from outside thread %d\n", omp_get_thread_num());

Hi from outside thread 1


Hi from section thread 3

sections
Marcheaza o sectiune de cod ce se va executa independent de cate un
thread

World!
World!
World!
World!

#pragma omp section


printf("Hi from section thread %d\n", omp_get_thread_num());

section
}

Dr. Ing. Alecsandru Ptracu / 2016 / v.1.1

1/4

Work-sharing

Tip

Nume directiva

Efect

Exemplu pentru 4 thread-uri


#pragma omp parallel
{
#pragma omp single
{
printf("read input from thread %d\n", omp_get_thread_num());
}

single

Output pentru 4 thread-uri


read input from thread 1
compute results in thread 3
compute results in thread 0
compute results in thread 2
compute results in thread 1
write output from thread 2

printf("compute results in thread %d\n", omp_get_thread_num());

Un singur thread va executa sectiunea de cod respectiva


(nu neaparat cel master!)

#pragma omp barrier


#pragma omp single
{
printf("write output from thread %d\n", omp_get_thread_num());
}
}

#pragma omp parallel


{
#pragma omp for
for (i = 0; i < 5; i++)
a[i] = i * i;
master

#pragma omp master


{
printf("in master: thread id = %d\n", omp_get_thread_num());
for (i = 0; i < 5; i++)
printf("a[%d] = %d\n", i, a[i]);
printf("------\n");
}

Doar thread-ul master (cel cu ThreadID=0) va executa regiunea de cod

#pragma omp
#pragma omp
for (i = 0;
a[i] +=

barrier
for
i < 5; i++)
i;

in master: thread id = 0
a[0] = 0
a[1] = 1
a[2] = 4
a[3] = 9
a[4] = 16
-----thread id = 2
thread id = 3
thread id = 0
thread id = 1
-----in master: thread id = 0
a[0] = 0
a[1] = 2
a[2] = 6
a[3] = 12
a[4] = 20

Sincronizare

#pragma omp barrier


printf("thread id = %d\n", omp_get_thread_num());
barrier

Se va astepta ca toate thread-urile sa ajunga la acest punct in program

#pragma omp master


{
printf("------\n");
printf("in master: thread id = %d\n", omp_get_thread_num());
for (i = 0; i < 5; i++)
printf("a[%d] = %d\n", i, a[i]);
}
}

critical

Doar 1 singur thread va executa aceasta operatiune in cadrul unei


iteratii

//SIZE=10; a=[1,2,3,4,5,6,7,8,9,10]
max = a[0];
#pragma omp parallel for
for (i = 1; i < SIZE; i++)
{
if (a[i] > max)
{
#pragma omp critical
{
if (a[i] > max)
max = a[i];
}
}
}
printf("max = %d\n", max);

max = 10

Dr. Ing. Alecsandru Ptracu / 2016 / v.1.1

2/4

Sincronizare

Tip

Nume directiva

atomic

Efect

Exemplu pentru 4 thread-uri

Acelasi efect ca si critical, doar ca pe o regiune mai mica. De obicei o


singura instructiune

Output pentru 4 thread-uri

int count = 0;
#pragma omp parallel
{
#pragma omp atomic
count++;
}
printf("count=%d\n", count);

count=2

2. CLAUSE
Nume clauza

private (VARIABLES)

shared (VARIABLES)

default (private | shared | none)

Efect

Exemplu pentru 4 thread-uri

Output pentru 4 thread-uri

Variabilele din lista sunt private pentru fiecare thread.


Acestea isi pierd valoarea de dinainte de intrare in bloc.
Variabilele se vor separa cu virgula intre ele.

int v = 100;
printf("before block: %d\n", v);
#pragma omp parallel private(v)
{
printf("in block: %d\n", v);
}
printf("after bloc: %d\n", v);

before block: 100


in block: 0
in block: 32632
in block: 0
in block: 0
after block: 100

Variabilele din lista sunt partajate intre toate thread-urile.


Variabilele se vor separa cu virgula intre ele.

//a = [0,1]
//b = [0,1]
#pragma omp parallel shared(a,b,c,chunk)
{
int tid = omp_get_thread_num();
for (int i=0; i < N; i++)
{
c[i] = a[i] + b[i];
printf("tid=%d i=%d c[i]=%d\n",tid,i,c[i]);
}
}

tid=0
tid=0
tid=3
tid=3
tid=2
tid=2
tid=1
tid=1

i=0
i=1
i=0
i=1
i=0
i=1
i=0
i=1

c[i]=0
c[i]=2
c[i]=0
c[i]=2
c[i]=0
c[i]=2
c[i]=0
c[i]=2

Programatorul alege felul in care variabilele sunt vazute in toate thread-urile din bloc. ATENTIE! Implicit, toate variabilele sunt shared!

Variabilele din lista sunt private pentru fiecare thread. Sunt


initializate cu valoarea existenta inainte de intrarea in bloc.
Variabilele se vor separa cu virgula intre ele.

int v = 100;
printf("before block: %d\n", v);
#pragma omp parallel firstprivate(v)
{
printf("in block: %d\n", v);
}
printf("after block: %d\n", v);

before block: 100


in block: 100
in block: 100
in block: 100
in block: 100
after block: 100

before block: 100


after block: 101

lastprivate (VARIABLES)

Variabilele din lista sunt private pentru fiecare thread.


Valorile variabilelor rezultate in urma executiei codului sunt
copiate in variabilele existente dupa iesirea din bloc.
Variabilele se vor separa cu virgula intre ele.

int v = 100;
printf("before block: %d\n", v);
#pragma omp parallel for firstprivate(v) lastprivate(v)
for (int i = 0; i<2; i++)
{
v+=1;
}
printf("after block: %d\n", v);

reduction(OPERATION:VARIABLES)

//a = [1, 2, 3]; b = [1, 2, 3]; sum = 0


#pragma omp parallel for reduction(+:sum)
for (int i=0; i < n; i++)
sum = sum + (a[i] * b[i]);
printf("sum = %d\n",sum);

sum = 14

Aplica o operatie de reducere (+ - * /) asupra variabilelor din


lista. Variabilele se vor separa cu virgula intre ele.

firstprivate (VARIABLES)

Dr. Ing. Alecsandru Ptracu / 2016 / v.1.1

3/4

Nume clauza

Efect

Exemplu pentru 4 thread-uri


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

num_threads(NUMBER)

schedule(TYPE:[CHUNK-SIZE])

if(CONDITION)

Seteaza numarul de thread-uri care se vor executa in bloc.

void main() {
#pragma omp parallel num_threads(8)
{
int i = omp_get_thread_num();
printf("Hello from thread %d\n", i);
}
}

Output pentru 4 thread-uri


Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello

from
from
from
from
from
from
from
from

thread
thread
thread
thread
thread
thread
thread
thread

1
5
0
7
4
3
6
2

Modul de planificare a task-urilor pe thread-uri


CHUNK-SIZE = numarul de iteratii facute de un thread
TYPE:
- dynamic = fiecare thead va primi de lucru, pe masura ce se elibereaza
- static = se stabileste de la inceput lucrul pentru fiecare thead
- guided = combinatie dintre static si dynamic. La inceput se imparte lucrul in modul static pentru fiecare thread, apoi pe masura ce acestea termina, vor primi de lucru suplimentar, iar CHUNK-SIZE se va micsora automat

Porneste executia thread-urilor doar daca CONDITION este


true. Pentru a verifica daca regiunea curenta se executa in
paralel sau nu, se foloseste functia omp_in_parallel()

void test(int val)


{
#pragma omp parallel if (val != 0)
if (omp_in_parallel())
{
#pragma omp single
printf("val = %d, in parallel block\n", val);
}
else
{
printf("val = %d, in serial block\n", val);
}
}

val = 0, in serial block


val = 2, in parallel block

void main( )
{
test(0);
test(2);
}

Lock-uri OpenMP. Un lock (mutex) este un mecanism de sincronizare pentru a limita accesul la o resursa, intr-un mediu in care se executa mai multe thread-uri

Apel
omp_lock_t NAME
omp_init_lock(&NAME)
omp_set_lock(&NAME)
omp_unset_lock(&NAME)
omp_test_lock(&NAME)

Efect
Declaratia unui lock
Initializarea unui lock
Preluarea unui lock de catre un thread. Daca un alt thread a preluat lock-ul inainte, acesta va astepta pana cand thread-ul respectiv va elibera lock-ul
Eliberarea unui lock de catre un thread
Verifica daca un lock este preluat sau nu

omp_destroy_lock(&NAME)

Elibereaza memoria ocupata de lock

Exemplu
int x = 0;
omp_lock_t lck;
omp_init_lock (&lck);
omp_set_lock (&lck);
#pragma omp parallel shared (x)
{
#pragma omp master
{
x = x + 1;
omp_unset_lock (&lck);
}
}
omp_destroy_lock (&lck);

Dr. Ing. Alecsandru Ptracu / 2016 / v.1.1

4/4

You might also like