簡體   English   中英

在OpenMP上下文中對firstprivate和threadprivate感到困惑

[英]Confused about firstprivate and threadprivate in OpenMP context

假設我在對象中打包了一些資源,然后根據資源執行一些計算。 我通常做的是初始化並行區域之外的對象,然后使用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

輸入並行區域#0(使用firstprivate)
復制c'tor
你好
再見
復制c'tor
你好
再見
復制c'tor
你好
再見
復制c'tor
你好
再見

輸入並行區域#1(使用私有)
def c'tor
你好
再見
def c'tor
你好
再見
def c'tor
你好
再見
def c'tor
你好
再見

輸入並行區域#2(打印全局實例的值並添加線程號)
def c'tor
0
def c'tor
0
def c'tor
0
0

輸入並行區域#3(打印全局實例)
0
1
2
3

即將離開main()
再見
再見

如果復制構造函數執行深層復制(如果您必須編寫自己的復制,並且默認情況下,如果您沒有,並且具有動態分配的數據),那么您將獲得對象的深層副本。 這是相對於private不與現有對象初始化私有副本。

threadprivate工作方式完全不同。 首先,它僅適用於全局或靜態變量。 更重要的是,它本身就是一個指令,並且不支持任何其他條款。 你可以在某處編寫threadprivate pragma行,然后在並行塊之前編寫#pragma omp parallel 還有其他差異(在內存中存儲對象等),但這是一個良好的開端。

讓我們分析一下上面的輸出。 首先,請注意,在進入區域#2時,將調用默認構造函數,為線程創建一個私有的新全局變量。 這是因為在進入第一個並行區域時,全局變量的並行副本尚不存在。

接下來,當NoseKnowsAll考慮最關鍵的區別時,線程私有全局變量通過不同的並行區域持久化。 在區域#3中沒有構造,我們看到保留了來自區域#2的添加的OMP線程號。 還要注意,在區域2和3中沒有調用析構函數,而是在離開main() (由於某種原因只有一個(主)副本 - 另一個是inst 。這可能是一個錯誤......)。

這讓我們知道為什么我使用英特爾編譯器。 Visual Studio 2013以及g ++(我的計算機上的4.6.2, Coliru(g ++ v5.2)編碼地(g ++ v4.9.2) )僅允許POD類型( )。 這被列為近十年的錯誤,但仍未完全解決。 給出的Visual Studio錯誤是

錯誤C3057:'globalClass':當前不支持'threadprivate'符號的動態初始化

並且g ++給出的錯誤是

錯誤:'globalClass'在首次使用后聲明為'threadprivate'

英特爾編譯器適用於類。

再說一遍。 如果要復制主線程變量的值,可以使用#pragma omp parallel copyin(globalVarName) 請注意,這符合類作為在上面的例子中工作(因此我離開它)。

來源: OMP教程私有firstprivatethreadprivate

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM