9

我打算使用 buffers std::vector<size_t> buffer(100),每个线程中的一个循环并行化,正如这段代码所建议的:

std::vector<size_t> buffer(100);
#pragma omp parallel for private(buffer)
for(size_t j = 0; j < 10000; ++j) {
    // ... code using the buffer ...
}

此代码不起作用。尽管每个线程都有一个缓冲区,但它们的大小可以为 0。

如何在每个线程的开头分配缓冲区?我还能用#pragma omp parallel for吗?我可以做得比这更优雅吗:

std::vector<size_t> buffer;
#pragma omp parallel for private(buffer)
for(size_t j = 0; j < 10000; ++j) {
    if(buffer.size() != 100) {
        #pragma omp critical
        buffer.resize(100);
    }
    // ... code using the buffer ...
}
4

2 回答 2

13

拆分 OpenMP 区域,如本问题所示。

然后在外部区域内声明向量,但在 for 循环本身之外。这将为每个线程创建一个本地向量。

#pragma omp parallel
{
    std::vector<size_t> buffer(100);

#pragma omp for
    for(size_t j = 0; j < 10000; ++j) {
    {

        // ... code using the buffer ...

    }
}
于 2013-03-11T22:56:09.793 回答
11

这个问题和公认的答案已经存在了一段时间,这里有一些进一步的信息,它们提供了对 openMP 的更多见解,因此可能对其他用户有所帮助。

在 C++ 中,privateandfirstprivate子句以不同的方式处理类对象:

从 OpenMP 应用程序接口 v3.1:

private:新列表项已初始化,或者具有未定义的初始值,就好像它是在没有初始化器的情况下在本地声明的一样。未指定调用用于类类型的不同私有变量的任何默认构造函数的顺序。

firstprivate:对于类类型的变量,调用复制构造函数来执行列表变量的初始化。

private调用默认构造函数,而firstprivate调用相应类的复制构造函数。

的默认构造函数std::vector构造一个没有元素的空容器,这就是缓冲区大小为 0 的原因。

要回答这个问题,这将是另一种无需拆分 OpenMP 区域的解决方案:

std::vector<size_t> buffer(100, 0);  
#pragma omp parallel for firstprivate(buffer)
for (size_t j = 0; j < 10000; ++j) {
  // use the buffer
}

编辑关于私有变量的一般注意事项:线程堆栈大小是有限的,除非显式设置(环境变量OMP_STACKSIZE)编译器依赖。如果您使用占用大量内存的私有变量,堆栈溢出可能会成为一个问题。

于 2013-12-12T09:16:58.393 回答