我不确定为什么OpenMP会使用这么多线程。它似乎与Microsoft实现无关,因为我也尝试过显示相同行为的英特尔库。 我的代码中有一些并行部分是计算绑定的,不应该创建和使用比我有内核更多的线程。但我观察到的是,对于n个启动线程,OpenMP创建了n * Cores线程。这看起来像一个大线程泄漏给我。
如果我执行"小"在服务器上运行的32位应用程序可能会失败,因为1000个OpenMP线程需要2 GB的地址空间已经没有为应用程序留下内存。这不应该发生。我期望从最先进的线程池重用其线程并带走不再使用的线程。
我曾尝试使用omp_set_num_threads(8)将线程池大小限制为8个内核,但这似乎只限制了每个启动线程实例的线程数。我做错了还是OpenMP不是故意这样用的?
在我的8核机器上,我的AsyncWorker类中的5个启动线程将分配由OpenMP创建的38个线程。我希望只创建8个线程,这些线程应该在所有5个启动线程中重用。
#include <atomic>
#include <thread>
#include <omp.h>
#include <chrono>
#include <vector>
#include <memory>
class AsyncWorker {
private:
std::vector<std::thread> threads;
public:
AsyncWorker()
{
}
void start() // add one thread that starts an OpenMP parallel section
{
threads.push_back(std::thread(&AsyncWorker::threadFunc, this));
}
~AsyncWorker()
{
for (auto &t : threads)
{
t.join();
}
}
private:
void threadFunc()
{
std::atomic<int> counter;
auto start = std::chrono::high_resolution_clock::now();
std::chrono::milliseconds durationInMs;
while (durationInMs.count() <5000l)
{
// each instance seems to get its own thread pool.
// Why? And how can I limit the threadpool to the number of cores and when will the threads be closed?
#pragma omp parallel
{
counter++;
auto stop = std::chrono::high_resolution_clock::now();
durationInMs = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
}
}
}
};
int main() {
//omp_set_dynamic(0);
//omp_set_nested(0);
//omp_set_num_threads(8);
{
AsyncWorker foo;
foo.start(); // 1
foo.start(); // 2
foo.start(); // 3
foo.start(); // 4
foo.start(); // 5
system("pause");
}
return 0;
}
答案 0 :(得分:3)
OpenMP使用的线程数是按并行部分设置的,并且您同时生成5个并行部分。因此你得到40个主题。
似乎您正在寻找基于任务的并行性。在OpenMP中,您可以通过启动并行区域然后根据需要创建任务来实现此目的。从头顶开始,这个模式的代码写得像这样:
// Start parallel region
#pragma omp parallel
{
// Only let a single thread create the tasks
#pragma omp single
{
for(int i = 0; i < 40; i++)
{
// Actually create the task that needs to be performed
#pragma omp task
{
heavy_work();
}
}
}
}
这样你只能有8个并行的线程。
答案 1 :(得分:2)
OpenMP并不意味着以这种方式使用。混合使用OpenMP和其他线程方法是灾难的一种方法,除非非常仔细地进行。即便如此,结果也是不可预测的。 OpenMP标准故意不再定义这种互操作性,供应商可以按照自己认为合适的方式自由提供(如果他们认为合适)。
omp_set_num_threads(8)
没有按照您的想法行事。它设置当没有num_threads()
子句时当前线程遇到的并行区域的线程数。此外,omp_set_nested(0)
已经(或可能)没有任何影响,因为您没有从OpenMP线程启动并行区域,而是从C ++ 11线程启动。可以通过OMP_THREAD_LIMIT
环境变量设置OpenMP线程总数的全局限制,但这仅在OpenMP 3.0及更高版本中可用,并且MSVC(永远?)陷入OpenMP 2.0时代。
可能的行动方针是: