在 OpenMP 中使用私有版本的全局外部变量
Using private versions of global extern variables with OpenMP
我有两个全局外部变量。我希望每个线程都有自己的私有副本和另一个的共享副本。 objective 是让每个线程都在私有版本上工作,然后将信息组合到第二个中。
这可能看起来有点矫枉过正,但这是我真正在做的事情的 MWE:
外部变量在Globals.h文件中定义:
extern vector<int> TestVector;
extern vector<vector<int>> CombinedTestVector;
并且在 Globals.cpp 文件中:
vector<int> TestVector;
vector<vector<int>> CombinedTestVector;
已执行 MyFunc.cpp(包含许多内容,包括 Globals.h)
void MyFunc(int NumberOfIterations)
{
int iter;
SetupTestVector();
cout << "Test vector initially looks like:\n";
PrintTestVector();
# pragma omp parallel for default(shared) private(iter) firstprivate(TestVector)
for (iter = 0; iter < NumberOfIterations; iter++)
{
int MyThreadNum = omp_get_thread_num();
RemoveOneFromYourThreadIndex(MyThreadNum);
# pragma omp critical
{
cout << " Thread " << MyThreadNum << ", TestVector now looks like:\n";
cout << " ";
PrintTestVector();
}
CombinedTestVector.push_back(TestVector);
}
# pragma omp barrier
cout << "Combined vector looks like:\n";
PrintCombinedVector();
}
///////////////////////////////////////////////////////////////////////
void SetupTestVector()
{
TestVector.push_back(10);
TestVector.push_back(11);
TestVector.push_back(12);
TestVector.push_back(13);
TestVector.push_back(14);
}
///////////////////////////////////////////////////////////////////////
void PrintTestVector()
{
for (size_t i = 0; i < TestVector.size(); i++)
{
cout << TestVector.at(i) << " ";
}
cout << "\n";
}
///////////////////////////////////////////////////////////////////////
void RemoveOneFromYourThreadIndex(int ThreadIndex)
{
TestVector.at(ThreadIndex) -= 1;
TestVector.push_back(ThreadIndex);
}
///////////////////////////////////////////////////////////////////////
void PrintCombinedVector()
{
for (size_t i = 0; i < CombinedTestVector.size(); i++)
{
for (size_t j = 0; j < CombinedTestVector.at(i).size(); j++)
{
cout << CombinedTestVector.at(i).at(j) << " ";
}
cout << "\n";
}
cout << "\n";
}
如果我使用 NumberOfIterations = 1 执行此操作,我得到:
Test vector initially looks like:
10 11 12 13 14
Thread 0, TestVector now looks like:
9 11 12 13 14 0
Combined vector looks like:
10 11 12 13 14
所以你可以看到组合向量没有得到我要求的结果...如果用 3 个线程执行,情况更糟:
Test vector initially looks like:
10 11 12 13 14
Thread 2, TestVector now looks like:
9 10 11 13 14 2 0 1
Thread 0, TestVector now looks like:
9 10 11 13 14 2 0 1
Thread 1, TestVector now looks like:
9 10 11 13 14 2 0 1
Combined vector looks like:
10 11 12 13 14
10 10 11 13 14 2
10 11 12 13 14
如何获得预期的行为,即离开:
Test vector initially looks like:
10 11 12 13 14
Thread 0, TestVector now looks like:
9 11 12 13 14 0
Thread 1, TestVector now looks like:
10 10 12 13 14 1
Thread 1, TestVector now looks like:
10 11 11 13 14 2
Combined vector looks like:
9 11 12 13 14 0
10 10 12 13 14 1
10 11 11 13 14 2
这里似乎对 firstprivate
和相关人员的实际工作存在误解。他们不做的是神奇地使全局变量在每个线程中引用不同的副本。相反,他们会在本地范围 中为您提供副本(如果您使用firstprivate
,则从全局范围复制)。
这样想:
# pragma omp parallel for default(shared) private(iter) firstprivate(TestVector)
for (iter = 0; iter < NumberOfIterations; iter++)
{
thread_local vector<int> TestVector = ::TestVector; /* OMP MAGIC */
int MyThreadNum = omp_get_thread_num();
// etc. ...lots of stuff that completely ignores your local copy
// (The function calls still operate on the global TestVector!)
CombinedTestVector.push_back(TestVector);
}
那么问题就很清楚了:在 RemoveOneFromYourThreadIndex
中,您引用的是 global TestVector
,而不是在您的部分范围内的那个firstprivate
。您需要将 那个本地实例 传递给 RemoveOneFromYourThreadIndex
(以及应该在 TestVector
上运行的所有其他函数)。
此外,CombinedTestVector.push_back(TestVector);
未同步,因此存在竞争条件,您也应该解决该问题。
关于代码质量的其他评论:
- Don't do
using namespace std;
.
- 不要使用全局变量,它们会很快变得一团糟。你有
Globals.h
的事实非常令人担忧。
- 我鼓励变量和函数以小写字母开头,而不是大写字母。
我有两个全局外部变量。我希望每个线程都有自己的私有副本和另一个的共享副本。 objective 是让每个线程都在私有版本上工作,然后将信息组合到第二个中。
这可能看起来有点矫枉过正,但这是我真正在做的事情的 MWE:
外部变量在Globals.h文件中定义:
extern vector<int> TestVector;
extern vector<vector<int>> CombinedTestVector;
并且在 Globals.cpp 文件中:
vector<int> TestVector;
vector<vector<int>> CombinedTestVector;
已执行 MyFunc.cpp(包含许多内容,包括 Globals.h)
void MyFunc(int NumberOfIterations)
{
int iter;
SetupTestVector();
cout << "Test vector initially looks like:\n";
PrintTestVector();
# pragma omp parallel for default(shared) private(iter) firstprivate(TestVector)
for (iter = 0; iter < NumberOfIterations; iter++)
{
int MyThreadNum = omp_get_thread_num();
RemoveOneFromYourThreadIndex(MyThreadNum);
# pragma omp critical
{
cout << " Thread " << MyThreadNum << ", TestVector now looks like:\n";
cout << " ";
PrintTestVector();
}
CombinedTestVector.push_back(TestVector);
}
# pragma omp barrier
cout << "Combined vector looks like:\n";
PrintCombinedVector();
}
///////////////////////////////////////////////////////////////////////
void SetupTestVector()
{
TestVector.push_back(10);
TestVector.push_back(11);
TestVector.push_back(12);
TestVector.push_back(13);
TestVector.push_back(14);
}
///////////////////////////////////////////////////////////////////////
void PrintTestVector()
{
for (size_t i = 0; i < TestVector.size(); i++)
{
cout << TestVector.at(i) << " ";
}
cout << "\n";
}
///////////////////////////////////////////////////////////////////////
void RemoveOneFromYourThreadIndex(int ThreadIndex)
{
TestVector.at(ThreadIndex) -= 1;
TestVector.push_back(ThreadIndex);
}
///////////////////////////////////////////////////////////////////////
void PrintCombinedVector()
{
for (size_t i = 0; i < CombinedTestVector.size(); i++)
{
for (size_t j = 0; j < CombinedTestVector.at(i).size(); j++)
{
cout << CombinedTestVector.at(i).at(j) << " ";
}
cout << "\n";
}
cout << "\n";
}
如果我使用 NumberOfIterations = 1 执行此操作,我得到:
Test vector initially looks like:
10 11 12 13 14
Thread 0, TestVector now looks like:
9 11 12 13 14 0
Combined vector looks like:
10 11 12 13 14
所以你可以看到组合向量没有得到我要求的结果...如果用 3 个线程执行,情况更糟:
Test vector initially looks like:
10 11 12 13 14 Thread 2, TestVector now looks like:
9 10 11 13 14 2 0 1
Thread 0, TestVector now looks like:
9 10 11 13 14 2 0 1
Thread 1, TestVector now looks like:
9 10 11 13 14 2 0 1
Combined vector looks like:
10 11 12 13 14
10 10 11 13 14 2
10 11 12 13 14
如何获得预期的行为,即离开:
Test vector initially looks like:
10 11 12 13 14 Thread 0, TestVector now looks like:
9 11 12 13 14 0
Thread 1, TestVector now looks like:
10 10 12 13 14 1
Thread 1, TestVector now looks like:
10 11 11 13 14 2
Combined vector looks like:
9 11 12 13 14 0
10 10 12 13 14 1
10 11 11 13 14 2
这里似乎对 firstprivate
和相关人员的实际工作存在误解。他们不做的是神奇地使全局变量在每个线程中引用不同的副本。相反,他们会在本地范围 中为您提供副本(如果您使用firstprivate
,则从全局范围复制)。
这样想:
# pragma omp parallel for default(shared) private(iter) firstprivate(TestVector)
for (iter = 0; iter < NumberOfIterations; iter++)
{
thread_local vector<int> TestVector = ::TestVector; /* OMP MAGIC */
int MyThreadNum = omp_get_thread_num();
// etc. ...lots of stuff that completely ignores your local copy
// (The function calls still operate on the global TestVector!)
CombinedTestVector.push_back(TestVector);
}
那么问题就很清楚了:在 RemoveOneFromYourThreadIndex
中,您引用的是 global TestVector
,而不是在您的部分范围内的那个firstprivate
。您需要将 那个本地实例 传递给 RemoveOneFromYourThreadIndex
(以及应该在 TestVector
上运行的所有其他函数)。
此外,CombinedTestVector.push_back(TestVector);
未同步,因此存在竞争条件,您也应该解决该问题。
关于代码质量的其他评论:
- Don't do
using namespace std;
. - 不要使用全局变量,它们会很快变得一团糟。你有
Globals.h
的事实非常令人担忧。 - 我鼓励变量和函数以小写字母开头,而不是大写字母。