我打算使用缓冲区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 ...
}
答案 0 :(得分:9)
拆分OpenMP区域,如this question。
所示然后在外部区域内声明向量,但在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 ...
}
}
答案 1 :(得分:9)
问题和接受的答案已经存在了一段时间,这里有一些进一步的信息可以提供对openMP的更多见解,因此可能对其他用户有所帮助。
在C ++中,private
和firstprivate
子句以不同方式处理类对象:
从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
)编译器相关。如果使用具有大内存占用量的私有变量,则堆栈溢出可能会成为问题。