punto producto paralelizar omp ejemplos calculo aprender c++ c multithreading parallel-processing openmp

c++ - producto - ¿Por qué no se permite el operador!=Con OpenMP?



paralelizar en c (5)

Intentaba compilar el siguiente código:

#pragma omp parallel shared (j) { #pragma omp for schedule(dynamic) for(i = 0; i != j; i++) { // do something } }

Me sale este error: error: predicado de control no válido .

Verifico la guía de referencia de openMP y dice que para el paralelo para "solo" permite uno de los siguientes operadores: <<=>>.

No entiendo por qué no permitir i != j Pude entender si era el horario estático, ya que openMP necesita calcular previamente el número de iteraciones asignadas a cada hilo. Pero no puedo entender por qué esta limitación en tal caso, por ejemplo. Alguna pista ?

EDITAR: incluso si hago for(i = 0; i != 100; i++) , aunque podría simplemente poner "<" o "<=".


.

Envié un correo electrónico a los desarrolladores de OpenMP sobre este tema, la respuesta que obtuve fue:

Para int firmado, el comportamiento de envolvente no está definido. Si permitimos != , Los programadores pueden obtener tripcount inesperado. El problema es si el compilador puede generar código para calcular un recuento de viajes para el ciclo.

Para un bucle simple, como:

for( i = 0; i < n; ++i )

el compilador puede determinar que hay ''n'' iteraciones, si n> = 0 , y cero iteraciones si n <0 .

Para un bucle como:

for( i = 0; i != n; ++i )

de nuevo, un compilador debería poder determinar que hay ''n'' iteraciones, si n> = 0 ; si n <0 , no sabemos cuántas iteraciones tiene.

Para un bucle como:

for( i = 0; i < n; i += 2 )

el compilador puede generar código para calcular el recuento de viajes (conteo de iteración de bucle) como piso ((n + 1) / 2) si n> = 0 , y 0 si n <0 .

Para un bucle como:

for( i = 0; i != n; i += 2 )

el compilador no puede determinar si ''i'' llegará alguna vez a ''n''. ¿Qué pasa si ''n'' es un número impar?

Para un bucle como:

for( i = 0; i < n; i += k )

el compilador puede generar código para calcular el conteo de viajes como piso ((n + k-1) / k) si n> = 0 , y 0 si n <0 , porque el compilador sabe que el ciclo debe contar hacia arriba; en este caso, si k <0 , no es un programa legal OpenMP.

Para un bucle como:

for( i = 0; i != n; i += k )

el compilador ni siquiera sabe si estoy contando hacia arriba o hacia abajo. No sabe si ''yo'' alguna vez golpeará ''n''. Puede ser un ciclo infinito.

Créditos : OpenMP ARB


Al contrario de lo que puede parecer, la schedule(dynamic) no funciona con una cantidad dinámica de elementos. Más bien, la asignación de bloques de iteración a hilos es lo que es dinámico. Con la programación estática, esta asignación se calcula previamente al comienzo de la construcción de trabajo compartido. Con la programación dinámica, los bloques de iteración se distribuyen a los hilos por orden de llegada.

El estándar OpenMP es bastante claro de que la cantidad de iteraciones se calcula previamente una vez que se encuentra la construcción de trabajo compartido, por lo tanto, el contador de bucles no se puede modificar dentro del cuerpo del bucle (especificación OpenMP 3.1, §2.5.1 - Construcción de bucle):

El recuento de iteraciones para cada ciclo asociado se calcula antes de la entrada al ciclo más externo. Si la ejecución de cualquier bucle asociado cambia cualquiera de los valores utilizados para calcular cualquiera de los recuentos de iteración, entonces el comportamiento no está especificado.

El tipo de entero (o tipo, para Fortran) utilizado para calcular el recuento de iteraciones para el ciclo contraído es implementación definida.

Un ciclo de intercambio de trabajo tiene iteraciones lógicas numeradas 0,1, ..., N-1 donde N es el número de iteraciones de bucle, y la numeración lógica denota la secuencia en la que se ejecutarían las iteraciones si se ejecutaran los bucles asociados. por un solo hilo. La cláusula schedule especifica cómo las iteraciones de los loops asociados se dividen en subconjuntos contiguos no vacíos, llamados fragmentos, y cómo estos fragmentos se distribuyen entre los hilos del equipo. Cada subproceso ejecuta su (s) fragmento (s) asignado (s) en el contexto de su tarea implícita. La expresión chunk_size se evalúa utilizando los elementos de la lista original de cualquier variable que se haga privada en la construcción del bucle. No se especifica si, en qué orden, o cuántas veces, ocurre algún efecto secundario de la evaluación de esta expresión. El uso de una variable en una expresión de cláusula de schedule de una construcción de bucle causa una referencia implícita a la variable en todas las construcciones envolventes.

El razonamiento detrás de esta restricción de operador relacional es bastante simple: proporciona una indicación clara de la dirección del ciclo, facilita el cálculo del número de iteraciones y proporciona una semántica similar de la directiva de trabajo compartido de OpenMP en C / C ++ y Fortran. . También otras operaciones relacionales requerirían una inspección minuciosa del cuerpo del bucle para comprender cómo va el bucle, lo que sería inaceptable en muchos casos y haría la implementación engorrosa.

OpenMP 3.0 introdujo el constructo de task explícito que permite la paralelización de bucles con un número desconocido de iteraciones. Sin embargo, hay una trampa: las tareas introducen una sobrecarga considerable y la única tarea por iteración de bucle solo tiene sentido si estas iteraciones tardan bastante tiempo en ejecutarse. De lo contrario, la sobrecarga dominaría el tiempo de ejecución.


Creo que tal vez no haya una buena razón para no tener que extender la funcionalidad existente para llegar tan lejos.

En un principio, el IIRC tenía que ser estático para poder determinar en tiempo de compilación cómo generar el código del bucle ... podría ser una resaca de eso.


La respuesta es simple. OpenMP no permite la terminación prematura de un equipo de hilos. Con == o! =, OpenMP no tiene forma de determinar cuándo se detiene el ciclo. 1. Uno o más hilos podrían golpear la condición de terminación, que podría no ser única. 2. OpenMP no tiene manera de cerrar los otros hilos que quizás nunca detecten la condición.


Si tuviera que ver la declaración

for(i = 0; i != j; i++)

utilizado en lugar de la declaración

for(i = 0; i < j; i++)

Me quedaría preguntándome por qué el programador había hecho esa elección, sin importar que pueda significar lo mismo. Puede ser que OpenMP esté haciendo una elección sintáctica difícil para forzar una cierta claridad de código.

Aquí hay un código que plantea desafíos para el uso de != Y puede ayudar a explicar por qué no está permitido.

#include <cstdio> int main(){ int j=10; #pragma omp parallel for for(int i = 0; i < j; i++){ printf("%d/n",i++); } }

observe que i se incrementa tanto en el enunciado for como en el propio bucle, lo que conduce a la posibilidad (pero no a la garantía) de un ciclo infinito.

Si el predicado es < entonces el comportamiento del bucle puede estar bien definido en un contexto paralelo sin que el compilador tenga que verificar dentro del bucle los cambios en i y determinar cómo esos cambios afectarán los límites del bucle.

Si el predicado es != Entonces el comportamiento del bucle ya no está bien definido y puede ser infinito en extensión, lo que impide una fácil subdivisión paralela.