c++ - 声明自身 (*this) 私有(private)的类以避免竞争条件/放弃 gcc 中线程私有(private)的请求

标签 c++ gcc openmp

我想避免并行代码中的竞争条件。问题是我的类包含几个全局变量,为了简单起见,我们只说一个 x 以及一个我希望并行的 for 循环。实际代码还有一个方法,它接受一个指向类的指针,在本例中是它本身,作为它的参数,访问更多的全局变量。因此,将整个实例设为 threadprivate 可能是有意义的。我正在使用 OpenMP。

一个最小的工作示例是:

#include <iostream>
#include <omp.h>
class lotswork {
public:
    int x;
    int f[10];

    lotswork(int i = 0) { x = i; };

    void addInt(int y) { x = x + y; }

    void carryout(){

        #pragma omp parallel for
        for (int n = 0; n < 10; ++n) {
            this->addInt(n);
            f[n] = x;
        }
        for(int j=0;j<10;++j){
            std::cout << " array at " << j << " = " << f[j] << std::endl;
        }
        std::cout << "End result = " << x << std::endl;
    }
};



int main() {
    lotswork production(0);
    #pragma omp threadprivate(production)
    production.carryout();

}

我的问题是,我该怎么做?使用关键字 threadprivate 返回以下编译器错误消息: 错误:“production”在第一次使用后声明为“threadprivate” 我认为这里的编译器问题还没有 solved :

This brings us to why I used the Intel compiler. Visual Studio 2013 as well as g++ (4.6.2 on my computer, Coliru (g++ v5.2), codingground (g++ v4.9.2)) allow only POD types (source). This is listed as a bug for almost a decade and still hasn't been fully addressed. The Visual Studio error given is error C3057: 'globalClass' : dynamic initialization of 'threadprivate' symbols is not currently supported and the error given by g++ is error: 'globalClass' declared 'threadprivate' after first use The Intel compiler works with classes.

不幸的是,我无法访问英特尔的编译器,但使用的是 GCC 8.1.0。我做了一些背景研究并找到了关于这个的讨论 here ,但那条路在十年前就变冷了。我问这个问题是因为有几个人对此有疑问并通过将类指针声明为 here 来解决它。或提出糟糕的建议workarounds .后一种方法似乎被误导了,因为指针通常被声明为常量,但是当实例仍然共享时我们有 threadprivate 指针。

尝试解决

我相信我可以使用 private 关键字,但不确定如何对类的整个实例执行此操作,尽管我更喜欢 threadprivate 关键字。与上面我的 MWE 建模类似的示例也在第 7 章的图 7.17 中进行了讨论 this book , 但没有解。 (我很清楚竞争条件以及它为什么会成为问题。)

如有必要,我可以提供证据证明没有任何额外关键字的上述程序的输出是不确定的。

解决方案的另一种尝试

我现在想到了一个解决方案,但由于某种原因,它无法编译。从线程安全和逻辑的角度来看,我的问题应该通过以下代码解决。然而,一定有某种错误。

#include <iostream>
#include <omp.h>
class lotswork : public baseclass {
public:
    int x;
    int f[10];

    lotswork(int i = 0) { x = i; };

    void addInt(int y) { x = x + y; }
    
        void carryout(){
    //idea is to declare the instance private
    #pragma omp parallel firstprivate(*this){
    //here, another instance of the base class will be instantiated which is inside the parallel region and hence automatically private
    baseclass<lotswork> solver;

  #pragma omp for
  for (int n = 0; n < 10; ++n) 
      {
          this->addInt(n);
          f[n] = x;
          solver.minimize(*this,someothervariablethatisprivate);
      }
                                             } //closing the pragma omp parallel region
                for(int j=0;j<10;++j){
                    std::cout << " array at " << j << " = " << f[j] << std::endl;
                }
                std::cout << "End result = " << x << std::endl;
            }
        };
        
        
        
    int main() {
        lotswork production(0);
        #pragma omp threadprivate(production)
        production.carryout();
    
    }

因此,根据定义,这段代码应该可以解决问题,但不知何故无法编译。我如何将这段代码放在一起,以实现所需的线程安全和编译,同时考虑到 threadprivate 不是非英特尔编译器人员的选项的约束?

最佳答案

这是一个长期缺失的 GCC 功能:

对于当前的 GCC 版本,thread_local 应该可以工作,但是:

int main() {
  thread_local lotswork production(0);
  production.carryout();
}

但是,我认为这对您的情况不起作用,因为 carryout 中的并行循环仍将在单个 lotswork 实例上运行。我相信这也适用于使用 threadprivate 的原始代码。您可能需要将并行循环移到 carryout 成员函数之外。

关于c++ - 声明自身 (*this) 私有(private)的类以避免竞争条件/放弃 gcc 中线程私有(private)的请求,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54014391/

相关文章:

c++ - CGAL 如何判断三角形是否在边界上

c++ - 将静态库封装在动态链接库 (DLL) 中

c++ - 移动到函数的最后一行

C 头文件问题 : #include and "undefined reference"

使用 64 位 GCC 在 Cygwin 上编译 64 位 GSL

c - OpenMP - 为什么 firstprivate 导致错误?

c++ - 将 lambda 与自动声明结合使用还是就地使用?

c++ - 什么是 Apple GCC 中的 WSAAsyncSelect() 函数模拟?

c - 在 emacs 中将 openmp 指令缩进为 C/C++ 代码

arrays - 如何使用openmp并行化数组元素的移动