C++ 类声明自己(*this)private以避免竞争条件/放弃对gcc中threadprivate的追求

C++ 类声明自己(*this)private以避免竞争条件/放弃对gcc中threadprivate的追求,c++,gcc,openmp,C++,Gcc,Openmp,我想避免并行代码中的竞争条件。问题是,我的类包含几个全局变量,为了简单起见,假设只有一个x,还有一个for循环,我希望使其并行。实际代码还有一个方法,该方法将指向类的指针(在本例中为类本身)作为其参数,访问更多全局变量。因此,让整个实例threadprivate可能是有意义的。我正在使用OpenMP。MWE是 #include <iostream> #include <omp.h> class lotswork { public: int x; int f

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

#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不是非英特尔编译器人员的选项这一约束条件吗?非常感谢您的帮助。

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

在当前的GCC版本中,
thread\u local
有望工作,不过:

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

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

这里似乎对OpenMP构造有一些混淆
threadprivate
与thread\u local非常相似,用于创建静态生存期对象的每个线程副本,可以是全局变量,也可以是静态变量。如前所述,这存在一些实现问题,但即使实现可以处理该类,对非静态局部变量使用
threadprivate
也会产生错误

至于错误,很难说没有输出,但可能有多种原因:

  • 不匹配的右大括号。将
    {
    放置在pragma行的末尾不会打开块,它需要位于下一行
  • 这样私有化封闭类实例是无效的
  • 如果需要在每个线程中创建封闭类的私有副本,可以通过将类复制到并行区域内声明的变量中:

    #pragma omp parallel
    {
      lotswork tmp(*this);
      // do things with private version
    }
    
    但是请注意,整个内容都是私有的,因此这意味着原始副本中的
    f
    将不会更新,除非您在私有副本上执行
    addInt
    等同物,然后在原始副本上执行
    f[n]
    赋值

    编辑:我最初提到使用
    default(firstprivate)
    子句,但是 default子句仅为FORTRAN提供private和first private C++中的相同效果,将上面的和复制构造成每个新实例, 或者默认情况下使用带有capture by value的lambda,然后使用firstprivate,
    *this
    需要c++17才能工作,但完全符合要求:

    auto fn = [=,*this](){
      // do things with private copies
      // all updates to persist in shared state through pointers
    };
    #pragma omp parallel firstprivate(fn)
    fn();
    

    我对这个问题做了大量的研究,似乎很多人都关心这个问题。与其匿名地、毫无帮助地提供downvote,为什么不提供应该改进的建议呢?不是downvoter,但如果您包含一个,足以使您认为应该改进的自包含、正确的代码片段可编译但不公平。我稍微改变了这个问题。你能解释一下为什么你想在并行区域之间保存私有变量吗?我通常能找到一个解决办法,我几乎不需要线程私有。解释你想做什么。你确定你不会把<代码>私有< /代码>与C++对应。“能见度"在类层次结构和OpenMP的
    private
    (对应于在每个线程的基础上进行复制)中,这两个概念都是完全正交的。到目前为止,我真的不明白您的问题是什么,以及您试图实现什么…感谢您指出这一点。我可能会咬紧牙关,声明一个关于f我的一个微不足道的地区的私有变量。“默认值(firstprivate)”不起作用,或者至少CLion抱怨说它期望“无”或“共享”。我将阅读OpenMP文档以了解您的建议,“有可能将私有或firstprivate设为默认值”所以我检查了一下,您所说的仅在Fortran中是正确的,请看这里,尽管有一条神秘的提示“[h]无论如何,实际实现可能会提供此选项。”是的,不会编译,并给出错误“在“firstprivate”之前预期为“non”或“shared”我猜LLNL的好人指的是OpenMP的定制版本?你说得很对。即使是我们这些帮助编写东西的人有时也会犯这些错误。回答编辑。
    auto fn = [=,*this](){
      // do things with private copies
      // all updates to persist in shared state through pointers
    };
    #pragma omp parallel firstprivate(fn)
    fn();