2016-07-19 16 views
2

Das folgende kleine Programm (online version) versucht, die Fläche eines 64 x 64-Quadrats durch rekursives Aufteilen in vier Quadrate zu berechnen, bis das kleinste Quadrat die Einheitslänge hat (kaum optimal). Aber aus irgendeinem Grund hängt das Programm. Was mache ich falsch?Einfache aufgabenbasierte OpenMP-Anwendung hängt

#include <iostream> 

unsigned compute(unsigned length) 
{ 
    if(length == 1) return length * length; 

    unsigned a[4] , area = 0 , len = length/2; 

    for(unsigned i = 0; i < 4; ++i) 
    { 
     #pragma omp task 
     { 
      a[i] = compute(len); 
     } 

     #pragma omp single 
     { 
      area += a[i]; 
     } 
    } 

    return area; 
} 

int main() 
{ 
    unsigned area , length = 64; 

    #pragma omp parallel 
    { 
     area = compute(length); 
    } 

    std::cout << area << std::endl; 
} 
+0

Haben Sie Ihr Programm debugged? – user743414

+0

Leider habe ich nicht. Ich habe Schwierigkeiten beim Einrichten des Eclipse-Parallel-Debuggers (PTP). – Olumide

Antwort

2

Die single Konstrukt dient als eine implizite Barriere für alle Threads im Team. Allerdings treffen nicht alle Threads im Team auf diesen einzelnen Block, da verschiedene Threads in unterschiedlichen Rekursionstiefen arbeiten. Aus diesem Grund hängt Ihre Anwendung.

In jedem Fall ist Ihr Code nicht korrekt. Nach Ihrer Aufgabenblockierung ist a[i] noch nicht zugewiesen, Sie können sie also nicht sofort verwenden! Sie müssen warten, bis die Aufgabe abgeschlossen ist. Natürlich sollten Sie das nicht innerhalb der Schleife tun, sonst würde das Tasking keine Parallelität ausnutzen. Die Lösung besteht darin, dies am Ende der Schleife zu tun. Auch müssen Sie a als Shared angeben, für die Ausgabe sichtbar werden:

for(unsigned i = 0; i < 4; ++i) 
{ 
    #pragma omp task shared(a) 
    { 
     a[i] = compute(len); 
    } 
} 
#pragma omp taskwait 
for(unsigned i = 0; i < 4; ++i) 
{ 
    area += a[i]; 
} 

Beachten Sie, dass die Reduktion nicht single Konstrukt gewickelt! Compute wird von einer Task ausgeführt, daher sollte nur ein Thread eine eigene lokale area haben. Allerdings müssen Sie ein single Konstrukt, bevor Sie zunächst alle Aufgaben laichen:

#pragma omp parallel 
#pragma omp single 
{ 
    area = compute(length); 
} 

Einfach gesagt dies eröffnet eine parallele Region mit einem Team von Fäden, und nur ein Thread beginnt die anfängliche Berechnung. Die anderen Threads greifen die Aufgaben auf, die später von diesem ersten Thread mit dem task-Konstrukt erzeugt werden. Darum geht es bei Tasking.

+0

Danke. Das Programm hängt nicht mehr, aber ich bekomme nicht den erwarteten Wert 4096. Ich vermute eine Race Condition. – Olumide

+1

Sie müssen 'a' als freigegeben angeben. Tut mir leid, ich habe das in meinem ersten Post verpasst. BTW: Werfen Sie einen Blick auf [diese Folien] (https://www.cs.colostate.edu/~cs475/f14/Lectures/Lec6OMPTasks.pdf). Sie erklären, mit einem ähnlichen Beispiel zu arbeiten. – Zulan

+0

Danke. Ich werde mir die Folien ansehen. Ich studiere seit ein paar Wochen OpenMP und habe noch viel zu lernen. BTW warum nicht #pragma omp Atombereich + = a [i]; 'Arbeit in der ersten for-Schleife? Ich frage mich, ob es möglich ist, das '#pragma omp taskwait' Konstrukt loszuwerden. – Olumide

1

Motiviert durch die Diskussion über die Aufgabe und wie es vermieden werden kann, zeige ich unten eine leicht modifizierte Version des ursprünglichen Codes. Bitte beachten Sie, dass die implizite Barriere am Ende des einzelnen Konstrukts in diesem Fall wirklich notwendig ist.

unsigned tp_area = 0; 
#pragma omp threadprivate(tp_area) 

void compute (unsigned length) 
{ 
    if (length == 1) 
    { 
     tp_area += 1; 
     return; 
    } 

    unsigned len = length/2; 

    for (unsigned i = 0; i < 4; ++i) 
    { 
#pragma omp task 
     { 
     compute (len); 
     } 
    } 
} 

int main() 
{ 
    unsigned area, length = 64; 

#pragma omp parallel 
    { 
#pragma omp single 
    { 
     compute (length); 
    } 
#pragma omp atomic 
    area += tp_area; 
    } 

    std::cout << area << std::endl; 
} 
+0

ersetzt habe. Ziemlich genial. Und anscheinend auch schneller. – Olumide