Supongamos un programa que realiza dos tareas ejecutadas secuencialmente. Podemos tener una ejecución mas rápida si ejecutamos las dos tareas a la vez, OpenMP nos permite esto mediante las sections, secciones de código ejecutadas por una única hebra.
Como puedes ver en el siguiente código, las dos tareas se ejecutan de modo secuencial, y se calcula el tiempo transcurrido mediante la función omp_getwtime.
#include <omp.h> #include <iostream> #include <stdlib.h> #include <time.h> using namespace std; void tarea_uno(){ sleep(2); } void tarea_dos(){ sleep(4); } int main (){ double timeIni, timeFin; timeIni = omp_get_wtime(); cout<<"Ejecutando tarea 1"<<endl; tarea_uno(); cout<<"Ejecutando tarea 2"<<endl; tarea_dos(); timeFin = omp_get_wtime(); cout<<"Tiempo tardado = "<< timeFin - timeIni <<" segundos"<<endl; }
Observamos el tiempo tardado en la ejecución es la suma de los tiempos de las tareas.
Los tiempos tomados en este programa no cambiaran significativamente si no se ejecuta en una maquina con mas de 1 núcleo de procesamiento.
A continuación vemos como se resuelve el problema.
int main (){ int thread; double timeIni, timeFin; timeIni = omp_get_wtime(); omp_set_num_threads(2); #pragma omp parallel private(thread) { thread = omp_get_thread_num(); #pragma omp sections { #pragma omp section { cout<<"Hebra "<<thread<<" Ejecutando tarea 1"<<endl; tarea_uno(); } #pragma omp section { cout<<"Hebra "<<thread<<" Ejecutando tarea 2"<<endl; tarea_dos(); } }//Fin Sections }//Fin Parallel timeFin = omp_get_wtime(); cout<<"Tiempo tardado = "<< timeFin - timeIni <<" segundos"<<endl; }
Si observamos el tiempo de ejecución del programa ha sido igual a la tarea que mas tarda.
Añadimos la siguiente salida para saber en que instante de tiempo abandonan las hebras el bloque sections.
}//Fin Sections cout<<"Hebra "<<thread<<" salio del sections en el instante = "<<omp_get_wtime() - timeIni <<endl; }//Fin Parallel
Como vemos en la ejecución del código a pesar de que las tareas tienen 2 segundos de diferencia las dos hebras salen de la región sections a la vez. OpenMP realiza una sincronización de las hebras y su variables compartidas.
Para evitar esa sincronización a la salida de algunas directivas se ha de añadir la clausula nowait.
Como se observa en la salida, las hebras no se sincronizan al final del sections.
Cuando el numero de hebras es superior al numero de section simplemente las hebras sin trabajo se quedan ociosas, o si esta presente nowait siguen ejecutando código después del sections.
Cuando el numero de section es superior al numero de hebras, se reparten las section entre las hebras disponibles, cuando una de ellas termine de ejecutar una de ellas seguirá por otra, así hasta que todos los section sean ejecutados por una hebra.