OpenMP嵌套for循环给出了意想不到的结果

时间:2015-07-18 09:18:42

标签: c for-loop openmp nested-loops

我正在学习OpenMP,以下带有嵌套for循环的代码会给出意想不到的结果和线程数> 1.我希望只有外环在这里并行化,我希望有4行输出。我使用的是gcc 4.8.4。

#pragma omp parallel
{
      const int nthreads = omp_get_num_threads();
      const int ithread = omp_get_thread_num();

      #pragma omp for
      for (out = 0; out < 2; out++) {
        for (in = 0; in < 2; in++) {
          printf("id= %d of %d, out= %d, in= %d\n", ithread, nthreads, out, in);
        }
      }
}

如果我设置OMP_NUM_THREADS=1,我会得到4行的预期输出:

id= 0 of 1, out= 0, in= 0
id= 0 of 1, out= 0, in= 1
id= 0 of 1, out= 1, in= 0
id= 0 of 1, out= 1, in= 1

但是,OMP_NUM_THREADS=2错过了一行输出!

id= 0 of 2, out= 0, in= 0
id= 1 of 2, out= 1, in= 0
id= 0 of 2, out= 0, in= 1

将内循环设置为for (in = 0; in < 3; in++)仅提供4行输出而不是预期的6!

id= 0 of 2, out= 0, in= 0
id= 1 of 2, out= 1, in= 0
id= 0 of 2, out= 0, in= 1
id= 1 of 2, out= 1, in= 2

我在这里做了什么非常错的事吗?请帮我解决这个问题。感谢。

2 个答案:

答案 0 :(得分:0)

看起来你的内部循环变量是在并行块开始之前声明的。这意味着它在所有线程之间隐式共享。也许你正试图将2D循环并行化,但你所尝试的并不会实现这一点;相反,每个内部循环将以非确定性方式与其他正在运行的内部循环冲突。

如果要并行化2D循环,必须对所有元素使用单个循环,然后手动计算索引,例如: for(int i=0;i<2*2;i++){ int out=i/2; int in=i%2; ... }。现在你可以在没有问题的情况下使i并行循环。正如高性能标记指出的那样,有一个专用的构造:OpenMP and nested loops?

如果您只使用并行化单个维度(这通常就足够了),您需要在并行循环中声明内部变量:

int out;
#pragma omp parallel for
for(out=0;out<2;out++){
    int in;
    for(in=0;in<2;in++){
        // action
    }
}

或明确标记内部变量private:

int in, out;
#pragma omp parallel for private(in)
for(out=0;out<2;out++){
    for(in=0;in<2;in++){
        // action
    }
}

这两个都使外循环并行,并且内循环对每个线程都是私有的,从而防止一个线程的当前状态改变另一个线程的状态。如果你在c-c99之前,第二种风格很有用,但是我建议只是在循环中移动声明更能表现出意图。

此问题包含有关设置私有变量的一些有用说明:OpenMP: are local variables automatically private?

最后,您应该避免直接从多个线程打印到同一输出;这些函数的线程安全性是模糊的(虽然特别是在Linux上它似乎更好地定义)。最好将打印抽象为线程安全缓冲区并使用单个线程来写入缓冲区。

答案 1 :(得分:0)

我看到两个问题:

  • 我看不出第一个omp并行语句是什么,应该删除它
  • 应将
  • 声明为私有(以便每个线程都有自己的副本)

    #pragma omp parallel for private(in) /* each thread needs its own copy of in */
      for (out = 0; out < 2; out++) {
        for (in = 0; in < 2; in++) {
          printf("id= %d of %d, out= %d, in= %d\n", ithread, nthreads, out, in);
        }
      }
    

    }