Erreur de compilation du prédicat de contrôle non valide avec OpenMP

Je crée un vérificateur de base de nombres premiers, basé sur C – déterminer si un nombre est premier , mais en utilisant OpenMP.

int isPrime(int value) { omp_set_num_threads(4); #pragma omp parallel for for( int j = 2; j * j <= value; j++) { if ( value % j == 0) return 0; } return value; } 

Lors de la compilation avec -fopenmp , la version 4.7.2 de GCC est erronée et indique invalid controlling predicate par rapport à la boucle for.

Il semble que cette erreur soit causée par le carré j dans la boucle for. Est-il possible de contourner ce problème tout en obtenant le résultat souhaité de l’algorithme?

return n’est pas autorisé à l’intérieur de la boucle car cela entraînerait une sortie avant les accolades.

Notez la définition donnée ci-dessous:

D’après la spécification OpenMP V2.5, 1.2.2 Terminologie du langage OpenMP, p2: 17-

bloc structuré – Pour C / C ++, une instruction exécutable, éventuellement composée, avec une seule entrée en haut et une seule sortie en bas.

Un bloc structuré commence par open { et se termine par la fermeture } . Le return est contenu dans ces accolades, de sorte que ce programme viole également la définition OpenMP pour un bloc structuré, car il possède deux sorties (une au return et une à la sortie à travers l’accolade).

OpenMP impose les cinq ressortingctions suivantes sur les boucles pouvant être threadées:

  • La variable de boucle doit être de type entier signé. Les entiers non signés, tels que DWORD, ne fonctionneront pas.
  • L’opération de comparaison doit être sous la forme variable_robe < , <= , > ou >= loop_invariant_integer
  • La troisième expression ou partie incrémentée de la boucle for doit être une addition ou une soustraction d’entier et une valeur invariante de la boucle.
  • Si l'opération de comparaison est < ou <= , la variable de boucle doit être incrémentée à chaque itération et inversement, si l'opération de comparaison est > ou >= , la variable de boucle doit être diminuée à chaque itération.
  • La boucle doit être un bloc de base, ce qui signifie qu'aucun saut de l'intérieur de la boucle à l'extérieur n'est autorisé, à l'exception de l'instruction exit qui met fin à l'application entière. Si les instructions goto ou break sont utilisées, elles doivent sauter dans la boucle et non en dehors de celle-ci. Il en va de même pour la gestion des exceptions. les exceptions doivent être capturées dans la boucle.

Selon le standard OpenMP (§2.5.1, p.40), les formes acceptables du prédicat de contrôle de la boucle for sont les suivantes:

  • var relationnel-op b , et
  • b relationnel-op var

Votre utilisation de j * j <= value est une violation flagrante de cette exigence. Le raisonnement est qu'il nécessite que le compilateur émette un code qui calcule la racine carrée entière de la value au moment de l'exécution, cette dernière n'étant pas définie pour certaines valeurs, en particulier les valeurs négatives.

Vous pouvez remplacer j * j <= value par j <= sqrt_value , où sqrt_value est la racine carrée entière de value , mais le problème serait d'avoir un autre chemin de sortie dans le bloc structuré à l'intérieur de la boucle. Malheureusement, il n’existe pas de solution simple dans ce cas, car OpenMP ne prend pas en charge la terminaison prématurée des boucles parallèles.