Dépendance des fonctions openMP

Nov 24 2020

J'ai 5 fonctions A, B, C, D, E.

Pour exécuter DI il faut que B, C soit exécuté, pour exécuter EI il faut que A, D soit exécuté.

J'ai essayé ça

int main()
{
    #pragma omp parallel num_threads(5) 
    {
        long t1 = clock();
        int a = 0, b = 0, c = 0, d = 0, e = 0;
        int th = omp_get_thread_num();
        if (th == 0) {
            a += A();
            printf("A is finished after %d\n", clock() - t1);
        }
        if (th == 1) {
            b += B();
            printf("B is finished after %d\n", clock() - t1);
        }
        if (th == 2) {
            c += C();
            printf("C is finished after %d\n", clock() - t1);
        }
        if (th == 3 && (b == 1 && c == 1)) {
            d += D();
            printf("D is finished after %d\n", clock() - t1);
        }
        if (th == 4 && (a == 1 && d == 1)) {
            e += E();
            printf("E is finished after %d\n", clock() - t1);
        }

    }
    return 0;
}

mais D, E n'ont pas exécuté

Toutes ces fonctions renvoient 1 jusqu'à présent à des fins de débogage

Réponses

1 dreamcrash Nov 24 2020 at 16:58

Les variables a, b, cet d,ne peuvent pas être utilisés pour communiquer entre les threads parce qu'ils sont privés . Par conséquent, chaque thread en a sa propre copie privée. De plus, ce n'est normalement pas une bonne idée de les utiliser à des fins de synchronisation.

Dans votre code, vous thread=3n'attendriez jamais if (th == 3 && (b == 1 && c == 1))parce que:

  1. bet csont privées, donc thread=3a b=0et c=0peu importe ce que les autres threads ont fait à leurs copies des variables b=0et c=0.
  2. Rien n'indique à ce thread d'attendre ( par exemple, un constructeur similaire à la synchronisation).

Si vous souhaitez que les threads attendent les uns les autres, utilisez à la omp barrierplace. Tous les threads devront appeler la barrière avant de pouvoir procéder à leur calcul.

 int main()
    {
        #pragma omp parallel num_threads(5) 
        {
            long t1 = clock();
            int a = 0, b = 0, c = 0, d = 0, e = 0;
            int th = omp_get_thread_num();
            if (th == 0) {
                a += A();
                printf("A is finished after %d\n", clock() - t1);
            }
            if (th == 1) {
                b += B();
                printf("B is finished after %d\n", clock() - t1);
            }
            if (th == 2) {
                c += C();
                printf("C is finished after %d\n", clock() - t1);
            }
            // Threads will wait for each other here
            #pragma omp barrier 
            if (th == 3) {
                d += D();
                printf("D is finished after %d\n", clock() - t1);
            }
            // Threads will wait for each other here
            #pragma omp barrier 
            if (th == 4) {
                e += E();
                printf("E is finished after %d\n", clock() - t1);
            }
        }
        return 0;
    }

Une approche plus sophistiquée consisterait à utiliser des tâches avec des dépendances une fonctionnalité publiée sur la norme OpenMP 4.0. Il y a déjà une belle explication sur le fonctionnement de cette fonctionnalité sur ce fil.

int a = 0, b = 0, c = 0, d = 0, e = 0;
#pragma omp parallel num_threads(5) shared(a, b, c, d)
{
  #pragma omp single nowait
  {
      long t1 = clock();

      int th = omp_get_thread_num();
      #pragma omp task  depend (out:a) 
      {
          a += A();
          printf("A is finished after %d\n", clock() - t1);
      }
      #pragma omp task depend (out:b) 
      {
         b += B();
         printf("B is finished after %d\n", clock() - t1);
      }
      #pragma omp task depend (out:c) 
      { 
          c += C();
          printf("C is finished after %d\n", clock() - t1);
      }
     #pragma omp task depend (in:a, b) depend(out:d) 
     {
        d += D(); 
        printf("D is finished after %d\n", clock() - t1);
     }
     #pragma omp task depend (in:a, b)  
     {
       e += E();
       printf("E is finished after %d\n", clock() - t1);
     }
  }
}
return 0;
}
2 HristoIliev Nov 24 2020 at 17:43

Une bonne solution OpenMP serait d'utiliser des tâches avec des dépendances de données:

    #pragma omp parallel num_threads(3)
    #pragma omp single
    {
        double t1 = omp_wtime();
        int a = 0, b = 0, c = 0, d = 0, e = 0;
        #pragma omp task shared(a) depend(out: a)
        {
            a += A();
            printf("A is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(b) depend(out: b)
        {
            b += B();
            printf("B is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(c) depend(out: c)
        {
            c += C();
            printf("C is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(b,c,d) depend(in: b,c) depend(out: d)
        {
            d += D();
            printf("D is finished after %f\n", omp_wtime() - t1);
        }
        #pragma omp task shared(a,d,e) depend(in: a,d)
        {
            e += E();
            printf("E is finished after %f\n", omp_wtime() - t1);
        }

    }

Ici, la tâche Aest marquée comme producteur pour la valeur de aavec depend(out: a)et la tâche Dest marquée comme producteur de davec depend(out: d). La tâche Eest marquée comme consommateur de ces deux valeurs avec depend(in: a,d). Suite aux dépendances de sortie (producteur) et d'entrée (consommateur), le runtime OpenMP construit un DAG d'exécution (graphe acyclique dirigé) qui lui indique le bon ordre d'exécution de toutes les tâches. Vous n'avez pas non plus besoin de cinq threads - trois suffisent.

Avoir le code de tâche dans une singleconstruction est OpenMP très idiomatique.

Les dépendances de tâches ont été introduites par OpenMP 4.0 en 2013, donc tout compilateur moderne à l'exception de MSVC ++ devrait prendre en charge cette fonctionnalité.