在 OpenMP 缩减中使用多态类型

Using polymorphic type in 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 种 classes :


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


奇怪的是这段代码在以下情况下有效:

或者如果:

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

感谢您的回答。

使用 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:

的所有已知子类使用 make a switch
void compute( A & action ) {
    B * pb = dynamic_cast<B*>( &action );
    if ( pb ) compute( *pb );
    C * pc = dynamic_cast<C*>( &action );
    if ( pc ) compute( *pc );
}

我不太清楚为什么这不起作用。顺便说一句,它使用 Intel 编译器进行编译,但使用纯虚函数调用时会崩溃。我原以为应该这样做:

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

但事实并非如此。关于 typename-list 中允许什么样的 type name,这个标准对我来说似乎有点模糊。在我看来,引用没有得到正确支持。