1. Materiales de referencia
openMP_demo
Introducción a OpenMP
Tutorial de OpenMP (1) Análisis en profundidad de las cláusulas de reducción de OpenMP
2. Introducción a OpenMP
1. Introducción a OpenMP
OpenMP (Open Multi-Processing) es una solución de programa multiproceso para sistemas paralelos de memoria compartida, compatible con C/C++. OpenMP proporciona una descripción abstracta de alto nivel de algoritmos paralelos, que pueden implementar computación paralela en múltiples núcleos de procesador y mejorar la eficiencia de ejecución del programa. El compilador procesa automáticamente el programa en paralelo de acuerdo con las instrucciones pragma agregadas al programa. El uso de OpenMP reduce la dificultad y complejidad de la programación paralela. Cuando el compilador no admite OpenMP, el programa degenerará en un programa normal (en serie) y las instrucciones OpenMP existentes en el programa no afectarán la compilación y operación normales del programa.
Muchos entornos de compilación convencionales tienen OpenMP incorporado. En Visual Studio, iniciar OpenMP es muy simple. Haga clic derecho en el proyecto->Propiedades->Propiedades de configuración->C/C++>Idioma->Soporte OpenMP y seleccione "Sí".
2. Modelo de memoria compartida
OpenMP está diseñado para máquinas de memoria compartida multiprocesador y multinúcleo.El número de unidades de procesamiento (núcleos de CPU) determina el paralelismo de OpenMP。
3. Modelo híbrido paralelo
OpenMP es adecuado para el paralelismo de un solo nodo y MPI se combina con OpenMP para lograr un paralelismo de memoria distribuida, que a menudo se denomina modelo de paralelismo híbrido .
- OpenMP se utiliza para trabajos computacionales intensivos en cada nodo (una computadora);
- MPI se utiliza para implementar la comunicación y el intercambio de datos entre nodos.
4.Modelo Fork-Join
_
OpenMP utiliza un Fork-Join
modelo de ejecución paralela.
- Bifurcación: el hilo principal crea un conjunto de hilos paralelos;
- Unirse: Los hilos del equipo realizan cálculos por separado en el área paralela, se sincronizarán y finalizarán, dejando solo el hilo principal.
En la figura anterior, parallel region
es un dominio paralelo. Los subprocesos múltiples son concurrentes dentro del dominio paralelo y la ejecución lineal la realiza el subproceso principal (maestro) entre dominios paralelos.
5. barrier
Mecanismo de sincronización
barrier
Se utiliza para la sincronización de subprocesos de código en el dominio paralelo. Cuando la ejecución del subproceso llega, barrier
debe detenerse y esperar hasta que se hayan ejecutado todos los subprocesos barrier
, luego continuará ejecutándose, logrando así la sincronización de subprocesos.
#include <stdio.h>
int main(void)
{
int th_id, nthreads;
#pragma omp parallel private(th_id)
{
th_id = __builtin_omp_get_thread_num();
printf("Hello World from thread %d\n", th_id);
#pragma omp barrier
if (th_id == 0) {
nthreads = __builtin_omp_get_num_threads();
printf("There are %d threads\n", nthreads);
}
}
return 0;
}
yoyo@yoyo:~/PATH/TO$ gcc -fopenmp demo.c -o demo
yoyo@yoyo:~/PATH/TO$ ./demo
Hello World from thread 10
Hello World from thread 3
Hello World from thread 2
Hello World from thread 6
Hello World from thread 4
Hello World from thread 7
Hello World from thread 0
Hello World from thread 5
Hello World from thread 11
Hello World from thread 8
Hello World from thread 1
Hello World from thread 9
There are 12 threads
3. Operaciones comunes
1. Instrucciones de uso común
# 安装OpenMP
sudo apt-get install libomp-dev
# 使用gcc编译OpenMP程序
gcc -fopenmp demo.c -o demo
# 使用g++编译OpenMP程序
g++ -fopenmp demo.cpp -o demo
2. Operaciones importantes
(1) Área paralela: utilice #pragma omp parallel
las instrucciones paraDefinir regiones paralelas。
(2) Número de hilo: omp_get_thread_num()
función de usoObtener el número del hilo actual。
(3) Número total de subprocesos: omp_get_num_threads()
función de usoObtener el número total de hilos。
(4) Intercambio de datos: palabras clave como private
y se pueden utilizar shared
para declarar el estado compartido de las variables.
(5) Mecanismo de sincronización: puede utilizar #pragma omp barrier
instrucciones paraImplementar sincronización de subprocesos。
3. Compruebe si OpenMP es compatible
#include <stdio.h>
int main()
{
#if _OPENMP
printf("support openmp\n");
#else
printf("not support openmp\n");
#endif
return 0;
}
yoyo@yoyo:~/PATH/TO$ gcc -fopenmp demo.c -o demo
yoyo@yoyo:~/PATH/TO$ ./demo-1
support openmp
4.Hello World
#include <stdio.h>
int main(void)
{
#pragma omp parallel
{
printf("Hello, world. \n");
}
return 0;
}
yoyo@yoyo:~/PATH/TO$ gcc -fopenmp demo.c -o demo
yoyo@yoyo:~/PATH/TO$ ./demo
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Hello, world.
Dado que no se especifica la cantidad de subprocesos, el número predeterminado es la cantidad de núcleos de CPU.
#include <stdio.h>
int main(void)
{
// 指定线程数量
#pragma omp parallel num_threads(6)
{
printf("Hello, world. \n");
}
return 0;
}
5.#pragma omp parallel for
omp_get_thread_num
: Obtiene la identificación del hilo actual;
#include <stdio.h>
#include <omp.h>
#include <stdlib.h>
int main(void) {
#pragma omp parallel for
for (int i=0; i<12; i++) {
printf("OpenMP Test, th_id: %d\n", omp_get_thread_num());
}
return 0;
}
yoyo@yoyo:~/PATH/TO$ gcc -fopenmp demo.c -o demo
yoyo@yoyo:~/PATH/TO$ ./demo
OpenMP Test, th_id: 8
OpenMP Test, th_id: 3
OpenMP Test, th_id: 1
OpenMP Test, th_id: 9
OpenMP Test, th_id: 5
OpenMP Test, th_id: 0
OpenMP Test, th_id: 6
OpenMP Test, th_id: 11
OpenMP Test, th_id: 2
OpenMP Test, th_id: 7
OpenMP Test, th_id: 4
OpenMP Test, th_id: 10
reduction
6.Operación de protocolo
6.1 Introducción
#include <stdio.h>
#include <omp.h>
#include <stdlib.h>
int main(void) {
int sum = 0;
#pragma omp parallel for
for (int i=1; i<=100; i++) {
sum += i;
}
printf("%d", sum);
return 0;
}
yoyo@yoyo:~/PATH/TO$ gcc -fopenmp demo.c -o demo
yoyo@yoyo:~/PATH/TO$ ./demo
1173yoyo@yoyo:~/PATH/TO$ ./demo
2521yoyo@yoyo:~/PATH/TO$ ./demo
3529yoyo@yoyo:~/PATH/TO$ ./demo
2174yoyo@yoyo:~/PATH/TO$ ./demo
1332yoyo@yoyo:~/PATH/TO$ ./demo
1673yoyo@yoyo:~/PATH/TO$ ./demo
1183yoyo@yoyo:~/PATH/TO$
Ejecutado varias veces, los resultados son diferentes cada vez porque los subprocesos compiten por el mismo recurso. Para sum += i;
esta línea, se puede reescribir como sum = sum + i
, varios subprocesos sum
escriben en paralelo al mismo tiempo, lo que provoca conflictos. Para resolver este problema, puedes usar reduction
.
6.2 reduction
Introducción
reduction(操作符:变量)
Tomemos sum
como ejemplo la función de suma:
#include <stdio.h>
#include <omp.h>
#include <stdlib.h>
int main(void) {
int sum = 0;
#pragma omp parallel for reduction(+:sum)
for (int i=1; i<=100; i++) {
sum += i;
}
printf("%d", sum);
return 0;
}
yoyo@yoyo:~/PATH/TO$ gcc -fopenmp demo.c -o demo
yoyo@yoyo:~/PATH/TO$ ./demo
5050yoyo@yoyo:~/PATH/TO$ ./demo
5050yoyo@yoyo:~/PATH/TO$ ./demo
5050yoyo@yoyo:~/PATH/TO$ ./demo
5050yoyo@yoyo:~/PATH/TO$ ./demo
5050yoyo@yoyo:~/PATH/TO$ ./demo
5050yoyo@yoyo:~/PATH/TO$
En el código anterior, reduction(+:sum)
significa que la suma de la variable se copia en cada hilo y luego la variable copiada se usa en el hilo, de esta manera no hay problema de competencia de datos, porque los datos de suma utilizados son diferentes para cada hilo. reduction
También hay un signo más , +
que indica cómo proceder.operación de protocolo. La llamada operación de reducción simplemente significa que se manipulan gradualmente varios datos y finalmente se obtienen datos que no se pueden reducir.
Por ejemplo, en el programa anterior, la operación de especificación es +
, por lo que es necesario operar los datos del subproceso 1 y el subproceso 2 +
, es decir, el valor suma del subproceso 1 se suma al valor suma del subproceso 2, y luego el resultado se asigna a la suma de la variable global. Los otros hilos se pueden deducir por analogía y la suma de la variable global final es el resultado correcto.
Si hay 4 subprocesos, entonces hay 4 sumas locales de subprocesos y cada subproceso copia una copia de la suma. Entonces el resultado de la operación de reducción es igual a:
( ( ( suma 1 + suma 2 ) + suma 3 ) + suma 4 ) (((suma_1 + suma2) + suma_3) + suma_4)( ( ( suma1+suma 2 ) _ _+suma _ _3)+suma _ _4)
dondesum_i
representa la suma obtenida por el i-ésimo hilo.