c ++在派生函数中启动OMP线程

时间:2017-11-24 19:53:13

标签: c++ multithreading openmp

假设我有一个带有两个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的线程,但它不起作用。这种设计甚至可能吗?

2 个答案:

答案 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以确保操作完成 - 或者交换调用者以使调用者并行执行与被调用者无关的任务。

如果没有线程团队存在,也可以按需创建并行上下文,但我认为这样不太干净且更危险。