在 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 :
- Actions:
A
(基础 class),以及 B
和 C
(源自 A
)
- Computer :
Bar
使用 OpenMP 实现并行计算(通过 compute()
函数)并执行一些操作(来自 B
或C
class) 通过调用 operator()
.
- Manager :管理计算的启动并设置不同的操作。
现在我有一个不幸的错误,告诉我我 cannot declare variable 'omp_priv' to be of abstract type 'A'
。这是很好理解的。我的 A
class 实际上是抽象的,但我希望 OpenMP 能够理解我的 Manager
class 的 A * action_
属性是 B
或C
类型。但是我该怎么做呢?
奇怪的是这段代码在以下情况下有效:
- 我绕过
Manager
class(取消注释 main()
中的工作部分)
或者如果:
- 我放弃并行和注释行 34 / 35(以
#pragma
开头的那些)
然而,这些都不是可以想象的选项。
感谢您的回答。
使用 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,这个标准对我来说似乎有点模糊。在我看来,引用没有得到正确支持。
这是一个 "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 :
- Actions:
A
(基础 class),以及B
和C
(源自A
) - Computer :
Bar
使用 OpenMP 实现并行计算(通过compute()
函数)并执行一些操作(来自B
或C
class) 通过调用operator()
. - Manager :管理计算的启动并设置不同的操作。
现在我有一个不幸的错误,告诉我我 cannot declare variable 'omp_priv' to be of abstract type 'A'
。这是很好理解的。我的 A
class 实际上是抽象的,但我希望 OpenMP 能够理解我的 Manager
class 的 A * action_
属性是 B
或C
类型。但是我该怎么做呢?
奇怪的是这段代码在以下情况下有效:
- 我绕过
Manager
class(取消注释main()
中的工作部分)
或者如果:
- 我放弃并行和注释行 34 / 35(以
#pragma
开头的那些)
然而,这些都不是可以想象的选项。
感谢您的回答。
使用 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 );
}
我不太清楚为什么这不起作用。顺便说一句,它使用 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,这个标准对我来说似乎有点模糊。在我看来,引用没有得到正确支持。