Computación paralela multinúcleo de memoria compartida OpenMP

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í".
Insertar descripción de la imagen aquí

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
Insertar descripción de la imagen aquí

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.
    Insertar descripción de la imagen aquí

4.Modelo Fork-Join_

OpenMP utiliza un Fork-Joinmodelo 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.
    Insertar descripción de la imagen aquí

En la figura anterior, parallel regiones 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. barrierMecanismo de sincronización

barrierSe utiliza para la sincronización de subprocesos de código en el dominio paralelo. Cuando la ejecución del subproceso llega, barrierdebe detenerse y esperar hasta que se hayan ejecutado todos los subprocesos barrier, luego continuará ejecutándose, logrando así la sincronización de subprocesos.
Insertar descripción de la imagen aquí

#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 parallellas 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 privatey se pueden utilizar sharedpara declarar el estado compartido de las variables.

(5) Mecanismo de sincronización: puede utilizar #pragma omp barrierinstrucciones 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

reduction6.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 sumescriben en paralelo al mismo tiempo, lo que provoca conflictos. Para resolver este problema, puedes usar reduction.

6.2 reductionIntroducción

reduction(操作符:变量) 

Tomemos sumcomo 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. reductionTambié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_irepresenta la suma obtenida por el i-ésimo hilo.

Supongo que te gusta

Origin blog.csdn.net/m0_37605642/article/details/132675523
Recomendado
Clasificación