在OpenMP简化中使用多态类型

时间:2016-06-13 14:31:27

标签: c++ inheritance polymorphism openmp reduction

这是一个" minimal"我正在尝试做的非工作示例。

此代码使用-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()
  • 经理:管理启动计算并设置不同的操作。

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

奇怪的是,此代码在以下情况下有效:

  • 我绕过Manager课程(main()
  • 中取消评论工作部分

或如果:

  • 我放弃并行和评论第34/35行(以#pragma开头的那些)

然而,这些都是不可想象的选择。

感谢您的回答。

1 个答案:

答案 0 :(得分: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) )

但事实并非如此。关于 typename-list 中允许哪种类型名称,标准似乎有点模糊。在我看来,引用只是没有得到正确支持。

相关问题