在循环内并行化序列化计数器变量的最佳方法

时间:2016-12-09 13:20:37

标签: openmp

我正在尝试并行化这个包含" serial"的4-nested循环。 counter问题。

count = 0 
 for (i = 0; i < vel; i++) 
    for (n = 0; n < dist; n++) 
      for (j = 1; j <= Y; j++) 
        for (k = 1; k <= Z; k++) {

          index = index(X, j, k);           
          buffX[count] = array[index];

          index = index(Y, j, k);                 
          buffY[count] = array[index]; 
          ++count;
        }

我尝试过非常简单的想法,例如:

#pragma omp parallel for private(i,n,j,k,index) shared(count)   
    for (i = 0; i < vel; i++) 
        for (n = 0; n < dist; n++) 
          for (j = 1; j <= Y; j++) 
#pragma omp critical
{
          for (k = 1; k <= Z; k++) {

              index = index(X, j, k);           
              buffX[count] = array[index];
              index = index(Y, j, k);                 
              buffY[count] = array[index];
              ++count;
          }
}

但由于count,它无效。我想知道是否有众所周知的技术来并行化这种循环。

1 个答案:

答案 0 :(得分:1)

直接的方法是从嵌套循环变量计算threadlocal count变量:

for (i = 0; i < vel; i++) 
  for (n = 0; n < dist; n++) 
    for (j = 1; j <= Y; j++) 
      for (k = 1; k <= Z; k++) {
        int count = (k-1) + Z * ((j-1) + Y * (n + dist * i));
        ...

如果您担心额外费用,可以在中间设置一些中间count_j

另一种方法是手动折叠循环并使count成为主循环索引:

#pragma omp parallel for
for (count = 0; count < vel * dist * Y * Z; count++) {
    // declare locally to make sure they are threadlocal
    int k = 1 + (count % Z);
    ...

请注意,这可能会积极地影响循环的并行性能(更多迭代,更好的平衡)或负面影响(错误的缓存效果)。

一个解决方案,整个循环体只是一个关键部分将是可怕的。没有线程可以并行执行任何计算(或内存传输)。除了关键区域没有引入订单保证,使代码错误。