2016-06-13 19 views
1

Hier ist ein "minimal" nicht funktionierendes Beispiel von dem, was ich versuche zu tun. Dieser Code wird mit -fopenmp Flag kompiliert.Verwenden von polymorphe Typ in OpenMP-Reduktion

#include <omp.h> 
#include <iostream> 

class A { 
public: 
    virtual void operator()() = 0 ; 

    void combine(const A & rhs) { 
     // do reduction stuff 
     std::cout << "Combine thread : " << omp_get_thread_num() << std::endl; 
    } 
}; 

class B : public A { 
public: 
    void operator()() { 
     // do some B specific stuff 
     std::cout << "B " ; 
    } 
} ; 

class C: public A { 
public: 
    void operator()() { 
     // do some C specific stuff 
     std::cout << "C " ; 
    } 
} ; 

class Computer { 
public: 
    template<typename B_or_C_type> 
    void compute(B_or_C_type & action) { 
     #pragma omp declare reduction (combine_actions : B_or_C_type : omp_out.combine(omp_in)) initializer (omp_priv(omp_orig)) 
     #pragma omp parallel for schedule(dynamic) reduction(combine_actions : action) 
     for(unsigned i = 0; i < 100; ++i) { 
      // do long computation 
      action() ; 
     } 
     std::cout << std::endl; 
    } 
} ; 

class Manager { 
public: 
    Manager(Computer * computer) : computer_(computer), action_(NULL) 
    {} 

    template<typename B_or_C_type> 
    void set_action(B_or_C_type * action) 
    { 
     action_ = action ; 
    } 

    void run() 
    { 
     computer_->compute(*action_) ; 
    } 

private: 
    Computer * computer_ ; 
    A * action_ ; 
} ; 


int main() { 
    Computer computer; 
    B b ; 
    C c ; 

    // Not working 
    Manager manager(&computer) ; 
    manager.set_action(&b) ; 
    manager.run() ; 
    manager.set_action(&c) ; 
    manager.run() ; 

    //Working 
    // computer.compute(b) ; 
    // computer.compute(c) ; 

    return 0; 
} 

Ich habe 3 Arten von Klassen:

  • Aktionen: A (Basisklasse) und B und C (abgeleitet von A)
  • Computer-: Bar, die parallel realisieren Berechnung (durch compute() Funktion) mit OpenMP und einige Aktionen (von einem B oder C Klasse) durch den Aufruf operator().
  • Manager: Das verwaltet den Start der Berechnung und setzt die verschiedenen Aktionen.

Im Moment habe ich diesen infortunate Fehler, der mir, dass ich cannot declare variable 'omp_priv' to be of abstract type 'A' erzählt. Das ist gut verständlich. Meine A Klasse ist in der Tat abstrakt, aber ich wünschte, OpenMP konnte verstehen, dass mein A * action_ Attribut von Manager Klasse B oder C Typ ist. Aber wie könnte ich das tun?


Das Seltsame ist, dass dieser Code funktioniert, wenn:

  • ich umgehen die Manager Klasse (uncomment Arbeitsabschnitt in main())

oder wenn:

  • Ich verzichte auf Parallelismus und nenne die Zeile 34/35 (die mit #pragma)

Diese sind jedoch keine denkbaren Optionen.

Vielen Dank für Ihre Antworten.

Antwort

1

Mit Hilfe eines A& nicht funktioniert, aber mit einem A* tut:

B_or_C_type * action_ptr = &action; 
#pragma omp declare reduction (combine_actions : B_or_C_type* : omp_out->combine(*omp_in)) initializer (omp_priv(omp_orig)) 
#pragma omp parallel for schedule(dynamic) reduction(combine_actions : action_ptr) 
for(unsigned i = 0; i < 100; ++i) { 
    // do long computation 
    (*action_ptr)(); 
} 

diese Weise können Sie die ganze B_or_C_type Vorlage Sache überspringen und nur A verwenden.

void compute(A & action) { 
    B * pb = dynamic_cast<B*>(&action); 
    if (pb) compute(*pb); 
    C * pc = dynamic_cast<C*>(&action); 
    if (pc) compute(*pc); 
} 

Ich bin nicht ganz genau sicher, warum dies nicht funktioniert: Als eine grobe Alternative könnten Sie einen Schalter für alle bekannten Unterklassen von A machen nutzen. Übrigens kompiliert es sich mit dem Intel-Compiler, stürzt aber mit einem reinen virtuellen Funktionsaufruf ab.Ich hätte gedacht, das sollte tun:

#pragma omp declare reduction (combine_actions : B_or_C_type& : omp_out->combine(*omp_in)) initializer (omp_priv(omp_orig)) 

Aber es tut es nicht. Der Standard scheint mir ein wenig vage zu sein, welche Art von Typ-Name s in der Typname-Liste zulässig sind. Es scheint mir, dass Referenzen nicht korrekt unterstützt werden.