2016-06-13 50 views
1

这是我正在尝试做的“最小”非工作示例。在OpenMP减少中使用多态类型

此代码是用-fopenmp标志编译的。

#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; 
} 

我有3种类型的类:

  • 操作A(基类),且BC(从A派生)
  • 计算机Bar该实现并行使用OpenMP计算(通过compute()函数)并执行一些操作(从BC课程),致电operator()
  • 管理器:管理启动计算并设置不同的动作。

现在我有告诉我这infortunate错误,我cannot declare variable 'omp_priv' to be of abstract type 'A'。这很好理解。我的A类实际上是抽象的,但我希望OpenMP能够理解,我的A * action_属性来自Manager类是BC类型。但我怎么能这样做?


奇怪的是,这个代码的工作,如果:

  • 我绕过Manager类(在main()取消注释作业部)

,或者:

  • 我放弃平行主义和评论线34/35(那些以#pragma

但是,这些都是不可想象的选项。

感谢您的回答。

回答

1

使用一个A&是不行的,但是在使用A*作用:

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)(); 
} 

这样,你可以跳过整个B_or_C_type模板的事情,只是使用A。作为一个更粗的替代,你可以利用进行切换所有已知的A子类:

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

我不是很确切地知道为什么,这是行不通的。顺便说一句,它与英特尔编译器编译,但与纯虚函数调用崩溃。我原以为应该这样做:

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

但它没有。该标准似乎对我来说有点模糊,至于型号名称 s是否允许在typename-list中。在我看来,引用只是不正确的支持。