假设我有一个带有两个OMP线程的虚函数的基类:
class Parent {
public:
Parent() {}
~Parent() {}
virtual void f() {
#pragma omp parallel sections
{
#pragma omp section
{
// do_something_1();
}
#pragma omp section
{
// do_something_2();
}
}
}
}
然后我有一个像这样的派生类:
class Child : public Parent {
public:
Child() {}
~Child() {}
void f() {
Parent::f();
// Other thread OMD
}
}
我想最后得到来自Parent类的两个线程和来自Child的线程,但它不起作用。这种设计甚至可能吗?
答案 0 :(得分:1)
问题是OpenMP指令在Parent的虚函数内部等等 在派生类中看不到。在派生类中调用父代码时 这表明两种可能的解决方案,都有优点和缺点。
版本1将父母的操作保持为私有,但只能额外扩展一次 水平。
class Parent {
public:
void f() {
#pragma omp parallel sections
{
#pragma omp section
{
// do_something_1();
}
#pragma omp section
{
// do_something_2();
}
#pragma omp section
{
this->f_impl();
}
}
}
private:
virtual void f_impl() {}; // do nothing placeholder
}
class Child : public Parent {
private:
void f_impl() override;
}
OR
版本2可以无限期延长,但需要公开每个家长的内部。
class Parent {
public:
virtual void f() {
#pragma omp parallel sections
{
#pragma omp section
{
f_impl1();
}
#pragma omp section
{
f_impl2();
}
}
}
protected:
void f_impl1();
void f_impl2();
}
class Child : public Parent {
public:
virtual void f() {
#pragma omp parallel sections
{
#pragma omp section
{
f_impl1();
}
#pragma omp section
{
f_impl2();
}
#pragma omp section
{
f_impl3();
}
}
}
protected:
void f_impl3();
}
class Child2 : public Child {
public:
virtual void f() {
#pragma omp parallel sections
{
#pragma omp section
{
f_impl1();
}
#pragma omp section
{
f_impl2();
}
#pragma omp section
{
f_impl3();
}
#pragma omp section
{
f_impl4();
}
}
}
protected:
void f_impl4();
}
答案 1 :(得分:0)
在这样的环境中,我宁愿建议使用任务,并确保一切都在并行环境中执行,例如:
// prepare the parallel context somewhere outside
#pragma omp parallel
#pargma omp single
run();
class Parent {
public:
Parent() {}
~Parent() {}
virtual void f() {
#pragma omp task
{
// do_something_1();
}
// do_something_2();
#pragma omp taskwait
// It's not nice for reasoning about code to keep tasks running here
}
}
class Child : public Parent {
public:
Child() {}
~Child() {}
void f() {
// swap the order in the code
// to account for taskwait at the end of paraent::f
#pragma omp task
{
// Other thread OMD
}
Parent::f();
// if you feel like it, you can also add a taskwait here
}
}
如您所见,如果您在应用程序中确保并行上下文(但使用单个代码执行),则可以轻松地使用任务来实现派生调用之间的并行化。但是,请小心在函数调用结束时执行任务,因为这可能很危险。确保调用者知道何时必须taskwait
以确保操作完成 - 或者交换调用者以使调用者并行执行与被调用者无关的任务。
如果没有线程团队存在,也可以按需创建并行上下文,但我认为这样不太干净且更危险。