Pourquoi l’opérateur! = N’est-il pas autorisé avec OpenMP?

J’essayais de comstackr le code suivant:

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

J’ai cette erreur: erreur: prédicat de contrôle invalide .

Je vérifie le guide de référence openMP et il dit que pour le parallèle, “only” permet à l’un des opérateurs suivants: <> =.

Je ne comprends pas pourquoi ne pas autoriser i != j Je pourrais comprendre si c’était le calendrier statique, car openMP doit pré-calculer le nombre d’itérations assignées à chaque thread. Mais je ne peux pas comprendre pourquoi cette limitation dans un tel cas, par exemple. Des indices?


EDIT: même si je fais for(i = 0; i != 100; i++) , bien que je puisse simplement mettre “<" ou "<=".

.

J’ai envoyé un email aux développeurs OpenMP à ce sujet, la réponse que j’ai eue:

Pour un int signé, le comportement de bouclage est indéfini. Si nous autorisons != , Les programmeurs peuvent avoir un compte-rendu inattendu. Le problème est de savoir si le compilateur peut générer du code pour calculer un nombre de déclenchements pour la boucle.

Pour une boucle simple, comme:

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

le compilateur peut déterminer qu'il existe 'n' itérations, si n> = 0 , et zéro itération si n <0 .

Pour une boucle comme:

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

encore une fois, un compilateur devrait être capable de déterminer qu'il y a 'n' itérations, si n> = 0 ; si n <0 , nous ne soaps pas combien d’itérations il a.

Pour une boucle comme:

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

le compilateur peut générer du code pour calculer le nombre de déclenchements (nombre d'itérations de boucle) en tant que floor ((n + 1) / 2) si n> = 0 et 0 si n <0 .

Pour une boucle comme:

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

le compilateur ne peut pas déterminer si "je" basha jamais "n". Et si 'n' est un nombre impair?

Pour une boucle comme:

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

le compilateur peut générer du code pour calculer le nombre de déclenchements en tant que étage ((n + k-1) / k) si n> = 0 et 0 si n <0 , car le compilateur sait que la boucle doit compter; dans ce cas, si k <0 , ce n'est pas un programme OpenMP légal.

Pour une boucle comme:

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

le compilateur ne sait même pas si je compte ou non. Il ne sait pas si "je" basha jamais "n". Ce peut être une boucle infinie.

Crédits : OpenMP ARB

Contrairement à ce à quoi il peut ressembler, la schedule(dynamic) ne fonctionne pas avec le nombre dynamic d’éléments. Plutôt l’assignation de blocs d’itération aux threads est ce qui est dynamic. Avec la planification statique, cette affectation est précalculée au début de la construction de partage de tâches. Avec la planification dynamic, les blocs d’itération sont dissortingbués aux threads sur la base du premier arrivé, premier servi.

La norme OpenMP est assez claire: la quantité d’itératons est précalculée une fois que la construction de partage de travail est rencontrée. Le compteur de boucle ne peut donc pas être modifié dans le corps de la boucle (spécification OpenMP 3.1, §2.5.1 – Construction de boucle):

Le nombre d’itérations pour chaque boucle associée est calculé avant l’entrée dans la boucle la plus externe. Si l’exécution d’une boucle associée modifie l’une des valeurs utilisées pour calculer l’un des nombres d’itérations, le comportement n’est pas spécifié.

Le type entier (ou type, pour Fortran) utilisé pour calculer le nombre d’itérations de la boucle réduite est défini par l’implémentation.

Une boucle de partage de travail a des itérations logiques numérotées 0,1, …, N-1 où N est le nombre d’itérations de boucle, et la numérotation logique indique la séquence d’exécution des itérations si la ou les boucles associées ont été exécutées par un seul fil. La clause schedule indique comment les itérations des boucles associées sont divisées en sous-ensembles contigus non vides, appelés morceaux, et comment ces blocs sont répartis entre les threads de l’équipe. Chaque thread exécute son ou ses blocs atsortingbués dans le contexte de sa tâche implicite. L’expression chunk_size est évaluée à l’aide des éléments de liste d’origine de toute variable rendue privée dans la construction de boucle. Il n’est pas précisé si, dans quel ordre ou combien de fois, des effets secondaires de l’évaluation de cette expression se produisent. L’utilisation d’une variable dans une expression de clause schedule d’une construction de boucle entraîne une référence implicite à la variable dans toutes les constructions englobantes.

La justification de cette ressortingction d’opérateur relationnel est assez simple: elle fournit une indication claire sur la direction de la boucle, facilite le calcul du nombre d’itérations et fournit une sémantique similaire à la directive de partage de travail OpenMP en C / C ++ et Fortran. . En outre, d’autres opérations relationnelles nécessiteraient une inspection minutieuse du corps de la boucle afin de comprendre comment se déroule la boucle, ce qui serait impraticable dans de nombreux cas et rendrait la mise en œuvre fastidieuse.

OpenMP 3.0 a introduit la construction de task explicite qui permet la parallélisation des boucles avec un nombre inconnu d’itérations. Il y a cependant un inconvénient: les tâches introduisent une surcharge importante et l’itération d’une tâche par boucle n’a de sens que si ces itérations prennent un certain temps à s’exécuter. Sinon, le temps système dominerait le temps d’exécution.

La réponse est simple. OpenMP ne permet pas la terminaison prématurée d’une équipe de threads. Avec == ou! =, OpenMP n’a aucun moyen de déterminer quand la boucle s’arrête. 1. Un ou plusieurs threads peuvent atteindre la condition de terminaison, qui peut ne pas être unique. 2. OpenMP n’a aucun moyen d’arrêter les autres threads qui pourraient ne jamais détecter la condition.

Si je devais voir la déclaration

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

utilisé à la place de la déclaration

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

Je me demandais pourquoi le programmeur avait fait ce choix, peu importe que cela puisse signifier la même chose. Il se peut que OpenMP fasse un choix syntaxique difficile afin de forcer une certaine clarté du code.

Voici le code qui pose des défis pour l'utilisation de != Et peut aider à expliquer pourquoi il n'est pas autorisé.

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

Notez que i est incrémenté à la fois dans l'instruction for ainsi que dans la boucle elle-même, ce qui conduit à la possibilité (mais pas à la garantie) d'une boucle infinie.

Si le prédicat est < le comportement de la boucle peut toujours être bien défini dans un contexte parallèle sans que le compilateur doive vérifier dans la boucle les modifications apscopes à i et déterminer comment ces modifications affecteront les limites de la boucle.

Si le prédicat est != Alors le comportement de la boucle n'est plus bien défini et son étendue peut être infinie, ce qui empêche une subdivision parallèle facile.

Je pense qu’il n’ya peut-être pas d’autre raison que d’avoir étendu les fonctionnalités existantes pour aller aussi loin.

IIRC à l’origine, ceux-ci devaient être statiques pour pouvoir déterminer au moment de la compilation comment générer le code de boucle … cela pourrait simplement être une gueule de bois.