我们如何准备小内存池,其中每个线程可以独立访问某些位置范围?



假设下面的函数调用:

// BigObj is a class instance that consumes memory 
void f(const BigObj& in, BigObj& out) {
BigObj tmp1, tmp2, tmp3;
// function calls on in, tmp1, tmp2, tmp3 and output assign out to some value 
}

int main() {
vector<BigObj> vec_in;
vector<BigObj> vec_out;
...// vec_in here has many elements
...// vec_out has the same size of vec_in
#pragma omp parallel for
for (size_t i = 0; i < vec.size(); i++) {
f(vec_in[i], vec_out[i]);
}
}

f由多线程调用。

这里的问题是有时间上巨大的物体tmp1,tmp2,tmp3。 因此,一旦每个线程调用f,它就会分配和解除分配所有时态变量,这需要很长时间。

为了避免这种情况,我想删除本地变量 tmp1、tmp2 和 tmp3 ,而是创建 BigObj 的 3 个全局数组(首先在 for 循环之前初始化)作为内存池,以便第 i 个线程只能访问第 i 个元素。

BigObj tmp1_pool[num_thread];
BigObj tmp2_pool[num_thread];
BigObj tmp2_pool[num_thread];

如果我准备这种东西,我怎么能用杂注 omp 指令呢? 将线程 ID 传递给函数是最佳选择吗?(如果是这样,反正我不知道该怎么做...

对于您的用例,您可以使用threadprivate声明变量 global 。

BigObj tmp1, tmp2, tmp3;
#pragma omp threadprivate(tmp1, tmp2, tmp3)

这意味着,每个线程都有自己的默认构造的tmp1等副本,您可以安全地将其用作并行区域中的临时副本。

BigObj tmp1_pool[num_thread];这样的数组或向量可以工作。但是,存在引入虚假共享和破坏性能的危险。可以正确有效地执行此操作,但是仅使用threadprivate要简单得多。

避免全局变量的另一种选择是为每个并行区域设置一个临时集,例如:

struct Tmp { BigObj tmp1; BigObj tmp2; BigObj tmp3; };
void f(const BigObj& in, BigObj& out, Tmp& tmp) {
}

#pragma omp parallel
{
Tmp tmp;
#pragma omp for
for (size_t i = 0; i < vec.size(); i++) {
f(vec_in[i], vec_out[i], tmp);
}
}

此方法的优点是可以更轻松地推理生存期和依赖项 - 但代价是出于性能原因显式传递数据。 最后,您必须在全局变量和杂货数据之间做出决定。

最新更新