【发布时间】:2021-03-07 08:31:25
【问题描述】:
我已将我遇到的问题提炼为最基本的问题。这是第一个示例代码:
#include <vector>
#include <math.h>
#include <thread>
std::vector<double> vec(10000);
void run(void)
{
for(int l = 0; l < 500000; l++) {
#pragma omp parallel for
for(int idx = 0; idx < vec.size(); idx++) {
vec[idx] += cos(idx);
}
}
}
int main(void)
{
#pragma omp parallel
{
}
std::thread threaded_call(&run);
threaded_call.join();
return 0;
}
编译为(在 Ubuntu 20.04 上):g++ -fopenmp main.cpp -o main
编辑:版本:g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0
在 Ryzen 3700x(8 核,16 线程)上运行:运行时间 ~43 秒,系统监视器中报告的所有 16 个逻辑内核都在 ~80%。 p>
接下来取出#pragma omp parallel指令,所以main函数变成:
int main(void)
{
std::thread threaded_call(&run);
threaded_call.join();
return 0;
}
现在运行时间 ~9s,系统监视器中报告的所有 16 个逻辑核心均以 100%。
我还在 Windows 10 上使用 MSVC 进行了编译,无论是否存在 #pragma omp 并行指令,cpu 利用率始终为 ~100%。是的,我完全知道这条线应该什么都不做,但是使用 g++ 它会导致上述行为;也只有在线程上调用 run 函数时才会发生这种情况,而不是直接发生。我尝试了各种编译标志(-O 级别),但问题仍然存在。我想下一步是查看汇编代码,但我看不出这只是 g++ 中的一个错误。任何人都可以对此有所了解吗?将不胜感激。
此外,调用 omp_set_num_threads(1);在循环之前的“void run(void)”函数中,为了检查单个线程需要多长时间,给出 ~70s 运行时间,只有一个线程处于 100%(如预期的那样)。
进一步,可能相关的问题(尽管这可能是我缺乏理解):调用 omp_set_num_threads(1);在“int main(void)”函数中(在定义 threaded_call 之前)在使用 g++ 编译时不执行任何操作,即所有 16 个线程仍然在 for 循环中执行,而与虚假的 #pragma omp 并行指令无关。使用 MSVC 编译时,这只会导致一个线程按预期运行 - 根据 omp_set_num_threads 的文档,我虽然这应该是正确的行为,但对于 g++ 则不然。为什么不呢,这是另一个错误吗?
编辑:我现在了解最后一个问题 (Overriding OMP_NUM_THREADS from code - for real),但仍然未解决原始问题。
【问题讨论】:
-
你应该添加你正在使用的 g++ 版本
-
将 OpenMP 与任何其他线程范例(例如 POSIX 线程或 C++ 线程库)混合使用超出了 OpenMP 规范的范围。它可能有效,也可能无效和/或导致奇怪的效果。在你的情况下,是后者。
-
在
main()中调用omp_set_num_threads(1)不起作用,因为它只会影响进行调用的线程中遇到的并行区域。 -
@Hristo Iliev 我明白你在说什么,并且很乐意接受这个作为答案(我已经修改了我的项目以避免这个问题)。然而,在我看来,这确实是一个糟糕的规范。 OpenMP 非常广泛地用于共享内存设备上的并行性,甚至带有 g++,并且 std::thread 是标准的并且也非常广泛地使用。将两者一起使用并不是没有道理的-例如分派一个或多个进程来运行计算,每个进程都有一定数量的 OpenMP 线程。
-
@Hristo Iliev 是的,谢谢你关于 omp_set_num_threads,也可以在这里找到 (stackoverflow.com/questions/56361293/…)