2013-11-21 6 views
6

Ich arbeite gerade an einer Matrixberechnung mit OpenMP. Ich habe mehrere Schleifen in meinem Code, und stattdessen für jede Schleife #pragma omp parallel für [...] (die alle Threads erstellen und zerstören sie direkt danach) Ich möchte alle von ihnen am Anfang erstellen, und lösche sie am Ende des Programms um Overhead zu vermeiden. Ich mag so etwas wie:So verschachteln Sie parallele Schleifen in einer sequenziellen Schleife mit OpenMP

#pragma omp parallel 
{ 
    #pragma omp for[...] 
    for(...) 

    #pragma omp for[...] 
    for(...) 
} 

Das Problem ist, dass ich einige Teile haben diejenigen, die durch nur einen Thread ausführen, aber in einer Schleife, die Schleifen enthalten diejenigen parallel ausführen sein ... Diese ist, wie es aussieht:

//have to be execute by only one thread 
int a=0,b=0,c=0; 
for(a ; a<5 ; a++) 
{ 

    //some stuff 

    //loops which have to be parallelize 
    #pragma omp parallel for private(b,c) schedule(static) collapse(2) 
    for (b=0 ; b<8 ; b++); 
     for(c=0 ; c<10 ; c++) 
     { 
      //some other stuff 
     } 

    //end of the parallel zone 
    //stuff to be execute by only one thread 

} 

(die Loop-Grenzen in meinem Beispiel sind recht klein in meinem Programm die Anzahl der Iterationen bis 20.000 ... geht kann.) Eine meiner ersten Idee war, etwas zu tun, wie diese :

//have to be execute by only one thread 
#pragma omp parallel //creating all the threads at the beginning 
{ 
    #pragma omp master //or single 
    {   
     int a=0,b=0,c=0; 
     for(a ; a<5 ; a++) 
     { 

      //some stuff 

      //loops which have to be parallelize 
      #pragma omp for private(b,c) schedule(static) collapse(2) 
      for (b=0 ; b<8 ; b++); 
       for(c=0 ; c<10 ; c++) 
       { 
        //some other stuff 
       } 

      //end of the parallel zone 
      //stuff to be execute by only one thread 

     } 
    } 
} //deleting all the threads 

Es kompiliert nicht, ich bekomme diesen Fehler von gcc: "Work-Sharing-Region möglicherweise nicht eng geschachtelt innerhalb der Arbeit teilen, kritisch, geordnet, Master oder explizite Task-Region".

Ich weiß, es kommt sicherlich von der "falschen" Verschachtelung, aber ich kann nicht verstehen, warum es nicht funktioniert. Muss ich vor der Parallelzone eine Barriere hinzufügen? Ich bin ein wenig verloren und weiß nicht, wie ich es lösen soll.

Vielen Dank im Voraus für Ihre Hilfe. Prost.

Antwort

3

In den letzten Ihrer Code-Umrisse deklarieren Sie eine parallele Region, innerhalb der eine Master-Direktive verwendet, um sicherzustellen, dass nur der Master-Thread einen Block ausführt, und innerhalb des Master-Blocks eine Schleife über alle Threads zu parallelisieren. Sie behaupten zu wissen, dass die Compilerfehler durch falsche Verschachtelung entstehen, aber wundern Sie sich, warum es nicht funktioniert.

Es funktioniert nicht, da das Verteilen von Arbeit auf mehrere Threads innerhalb einer Code-Region, die nur ein Thread ausführt, keinen Sinn macht.

Ihr erster Pseudo-Code ist besser, aber Sie wollen wahrscheinlich es wie folgt verlängern:

#pragma omp parallel 
{ 
    #pragma omp for[...] 
    for(...) 

    #pragma omp single 
    { ... } 

    #pragma omp for[...] 
    for(...) 
} 

Die single Richtlinie stellt sicher, dass der Code-Block es umschließt nur von einem Thread ausgeführt wird. Anders als die master Direktive single bedeutet auch eine Barriere am Ausgang; Sie können dieses Verhalten mit der Klausel nowait ändern.

+0

Vielen Dank für Ihre Antwort. Ich werde versuchen, meinen Code neu zu ordnen, um eine leichtere Parallelstruktur zu haben. – user3014051

3

Die meisten OpenMP Laufzeiten "erstellen nicht alle Threads und zerstören sie direkt danach". Die Threads werden am Anfang des ersten OpenMP-Abschnitts erstellt und beim Beenden des Programms zerstört (zumindest so funktioniert es bei Intels OpenMP-Implementierung). Es gibt keinen Leistungsvorteil durch die Verwendung einer großen parallelen Region anstelle von mehreren kleineren.

Intels Laufzeiten (die Open Source ist und gefunden werden kann here) hat Optionen zu steuern, was Threads tun, wenn sie keine Arbeit mehr haben. Standardmäßig drehen sie sich eine Weile (falls das Programm sofort einen neuen parallelen Abschnitt startet), dann werden sie sich schlafen legen. Wenn sie schlafen, wird es etwas länger dauern, sie für den nächsten parallelen Abschnitt zu starten, aber das hängt von der Zeit zwischen Regionen ab, nicht von der Syntax.

Verwandte Themen