c++ - 对 OpenMP 上下文中的 firstprivate 和 threadprivate 感到困惑

标签 c++ openmp

假设我在一个对象中打包了一些资源,然后根据这些资源进行一些计算。我通常做的是初始化并行区域外的对象,然后使用firstprivte关键字

int main()
{
        // initialize Widget objs
         Widget Widobj{params1,params2,params3...};

        #pragma omp parallel for firstprivate(Widobj)
        for (int i=0; i< N; ++i)
          {
             // computation based on resources in Widobj
          }

}

而且我认为在这种情况下,每个线程都会独立处理 Widobj 中的资源,并且我想每个线程都会有一个 Widobj 的拷贝(可能是一个深层拷贝,对吗?)。现在我对另一个关键字 threadprivate 感到困惑,threadprivate 在这种情况下如何工作?在我看来它们非常相似

最佳答案

当对象声明为firstprivate 时,复制构造函数被调用,而当使用private 时,默认构造函数被调用。我们将在下面解决 threadprivate。证明(英特尔 C++ 15.0):

#include <iostream>
#include <omp.h>

class myclass {
    int _n;
public:
    myclass(int n) : _n(n) { std::cout << "int c'tor\n"; }

    myclass() : _n(0) { std::cout << "def c'tor\n"; }

    myclass(const myclass & other) : _n(other._n)
    { std::cout << "copy c'tor\n"; }

    ~myclass() { std::cout << "bye bye\n"; }

    void print() { std::cout << _n << "\n"; }

    void add(int t) { _n += t; }
};

myclass globalClass;

#pragma omp threadprivate (globalClass)

int main(int argc, char* argv[])
{
    std::cout << "\nBegninning main()\n";

    myclass inst(17);

    std::cout << "\nEntering parallel region #0 (using firstprivate)\n";
#pragma omp parallel firstprivate(inst)
    {
        std::cout << "Hi\n";
    }

    std::cout << "\nEntering parallel region #1 (using private)\n";
#pragma omp parallel private(inst)
    {
        std::cout << "Hi\n";
    }

    std::cout << "\nEntering parallel region #2 (printing the value of "
                    "the global instance(s) and adding the thread number)\n";
#pragma omp parallel
    {
        globalClass.print();
        globalClass.add(omp_get_thread_num());
    }

    std::cout << "\nEntering parallel region #3 (printing the global instance(s))\n";
#pragma omp parallel
    {
        globalClass.print();
    }

    std::cout << "\nAbout to leave main()\n";
    return 0;
}

给予

def c'tor

Begninning main()
int c'tor

Entering parallel region #0 (using firstprivate)
copy c'tor
Hi
bye bye
copy c'tor
Hi
bye bye
copy c'tor
Hi
bye bye
copy c'tor
Hi
bye bye

Entering parallel region #1 (using private)
def c'tor
Hi
bye bye
def c'tor
Hi
bye bye
def c'tor
Hi
bye bye
def c'tor
Hi
bye bye

Entering parallel region #2 (printing the value of the global instance(s) and adding the thread number)
def c'tor
0
def c'tor
0
def c'tor
0
0

Entering parallel region #3 (printing the global instance(s))
0
1
2
3

About to leave main()
bye bye
bye bye

如果复制构造函数执行深拷贝(如果您必须自己编写它应该这样做,如果您不这样做并且有动态分配的数据则默认执行),那么您将获得对象的深拷贝。这与不使用现有对象初始化私有(private)拷贝的 private 相反。

threadprivate 的工作方式完全不同。首先,它仅适用于全局或静态变量。更重要的是,它本身就是一个指令,不支持任何其他子句。您在某处编写了 threadprivate pragma 行,然后在并行 block 之前编写了 #pragma omp parallel。还有其他差异(对象在内存中的存储位置等),但这是一个好的开始。

让我们分析一下上面的输出。 首先,请注意,在进入区域#2 时,调用默认构造函数创建线程专用的新全局变量。这是因为在进入第一个并行区域时,全局变量的并行拷贝尚不存在。

接下来,正如 NoseKnowsAll 认为的最关键的区别,线程私有(private)全局变量在不同的并行区域中是持久的。在区域 #3 中没有构造,我们看到从区域 #2 添加的 OMP 线程数被保留。另请注意,在区域 2 和 3 中没有调用析构函数,而是在离开 main() 之后(由于某种原因只有一个(主)拷贝 - 另一个是 inst . 这可能是一个错误...)。

这让我们明白了我使用英特尔编译器的原因。 Visual Studio 2013 和 g++(在我的电脑上是 4.6.2,Coliru (g++ v5.2)codingground (g++ v4.9.2))只允许 POD类型(source)。这被列为近十年来的错误,但仍未得到完全解决。 给出的 Visual Studio 错误是

error C3057: 'globalClass' : dynamic initialization of 'threadprivate' symbols is not currently supported

而g++给出的错误是

error: 'globalClass' declared 'threadprivate' after first use

英特尔编译器使用类。

还有一点。如果你想复制主线程变量的值,你可以使用 #pragma omp parallel copyin(globalVarName) .请注意,这不适用于我们上面示例中的类(因此我将其省略)。

来源:OMP tutorial : private , firstprivate , threadprivate

关于c++ - 对 OpenMP 上下文中的 firstprivate 和 threadprivate 感到困惑,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32347008/

相关文章:

c++ - Linux/C++ 帮助 glade3 和 gtkmm

c++ - 与 boost 波链接时的链接器 'undefined references'错误

c++ - 获取插入点的窗口坐标 - Cocoa

c++ - 为什么我的 openGL 椭圆是尖的?

c - 确定运行线程的套接字/处理器

c++ - 如何解读英特尔 VTune Amplifier 的 Locks&Waits

c++ - Vector of class类型导致Unresolved external symbol错误LNK2019

c++ - 增加 openMP 中的数组索引

c++ - 在 C++ OpenMP 代码中测量执行时间

c++ - OpenMP C++ 并行性能优于八核集群的双核笔记本电脑