openmp
Paralelismo irregular de OpenMP
Buscar..
Observaciones
Un error común es creer que todos los subprocesos de una región paralela deberían instanciar (crear) tareas, pero este no suele ser el caso a menos que desee crear tantas tareas como el número de subprocesos multiplicado por el número de elementos que se procesen. Por lo tanto, en los códigos de tarea OpenMP encontrarás algo similar a
#pragma omp parallel
#pragma omp single
...
#pragma omp task
{ code for a given task; }
...
Procesamiento paralelo de un contenedor de listas de c ++ usando tareas OpenMP
#include <omp.h>
#include <unistd.h>
#include <iostream>
#include <list>
static void processElement (unsigned n)
{
// Tell who am I. The #pragma omp critical ensures that
// only one thread sends data to std::cout
#pragma omp critical
std::cout <<
"Thread " << omp_get_thread_num() << " processing element " << n
<< std::endl;
// Simulate some work
usleep (n*1000);
}
int main (void)
{
std::list<unsigned> lst;
// Fill the list
for (unsigned u = 0; u < 16; ++u)
lst.push_back (1+u);
// Now process each element of the list in parallel
#pragma omp parallel // Create a parallel region
#pragma omp single // Only one thread will instantiate tasks
{
for (auto element : lst)
{
#pragma omp task firstprivate (element)
processElement (element);
}
// Wait for all tasks to be finished
#pragma omp taskwait
}
return 0;
}
Este ejemplo simula el procesamiento de una lista STL (denominada lst
en el código) en paralelo a través de las construcciones de tareas OpenMP (usando la directiva de #pragma omp task
). El ejemplo crea / crea una instancia de OpenMP para cada elemento en lst
y los subprocesos de OpenMP ejecutan las tareas tan pronto como están listos para ejecutarse.
$ OMP_NUM_THREADS=4 ./a.out
Thread 0 processing element 16
Thread 3 processing element 3
Thread 2 processing element 1
Thread 1 processing element 2
Thread 2 processing element 4
Thread 1 processing element 5
Thread 3 processing element 6
Thread 2 processing element 7
Thread 1 processing element 8
Thread 3 processing element 9
Thread 2 processing element 10
Thread 1 processing element 11
Thread 0 processing element 15
Thread 3 processing element 12
Thread 2 processing element 13
Thread 1 processing element 14
Cálculo recursivo para pi usando tareas OpenMP
El siguiente código calcula el valor de PI utilizando un enfoque recursivo. Modifique el valor de MAX_PARALLEL_RECURSIVE_LEVEL
para determinar en qué recursión deja de crear tareas. Con este enfoque para crear paralelismo a partir de aplicaciones recursivas: cuantas más tareas cree, más tareas paralelas se crearán, pero también menor será el trabajo por tarea. Por lo tanto, es conveniente experimentar con la aplicación para comprender a qué nivel crear nuevas tareas no se benefician en términos de rendimiento.
#include <stdio.h>
#include <omp.h>
double pi_r (double h, unsigned depth, unsigned maxdepth, unsigned long long begin, unsigned long long niters)
{
if (depth < maxdepth)
{
double area1, area2;
// Process first half
#pragma omp task shared(area1)
area1 = pi_r (h, depth+1, maxdepth, begin, niters/2-1);
// Process second half
#pragma omp task shared(area2)
area2 = pi_r (h, depth+1, maxdepth, begin+niters/2, niters/2);
#pragma omp taskwait
return area1+area2;
}
else
{
unsigned long long i;
double area = 0.0;
for (i = begin; i <= begin+niters; i++)
{
double x = h * (i - 0.5);
area += (4.0 / (1.0 + x*x));
}
return area;
}
}
double pi (unsigned long long niters)
{
double res;
double h = 1.0 / (double) niters;
#pragma omp parallel shared(res)
{
#define MAX_PARALLEL_RECURSIVE_LEVEL 4
#pragma omp single
res = pi_r (h, 0, MAX_PARALLEL_RECURSIVE_LEVEL, 1, niters);
}
return res * h;
}
int main (int argc, char *argv[])
{
#define NITERS (100*1000*1000ULL)
printf ("PI (w/%d iters) is %lf\n", NITERS, pi(NITERS));
return 0;
}