为什么OpenMP lastprivate会产生错误的结果?

时间:2013-06-25 16:20:59

标签: c openmp

我正在尝试运行以下代码以了解OpenMP lastprivate构造的功能。根据lastprivate的定义,如果我声明一个变量lastprivate,它对每个线程都是私有的,并且按顺序执行并行循环的最后一次迭代的线程的值被复制到该区域之外的变量。 这是代码:

int main(void) 
{
    omp_set_num_threads(5);
    int i;
    int k =3;
    #pragma omp parallel private(i)
    {
        #pragma omp for lastprivate(k) 
        for(i=0; i< 5; i++ )
        {
            int iam = omp_get_thread_num();
            k = iam;
            printf("k=%d, iam=%d\t",k, iam);
        }
    }

    printf("\n k = %d", k);
}

它产生如下输出:

k=0, iam=0  k=4, iam=4  k=3, iam=3  k=2, iam=2  k=1, iam=1  
k = 4

当我们有一组线程在'for'中工作时,我们无法保证最后执行哪个线程。因此,相应地,最后一个线程的值应该反映在全局“k”中。但是,无论我运行代码多少次,全局(即并行部分结束后)的'k'值仍为4。

从打印值开始,我们可以看到线程1最后执行。即使我们假设打印件不能可靠地获得精确运行的线程序列,但是线程4总是最后运行似乎很明显,从而反映出它在'k'中的值。

我很感激有关这个问题的帮助。感谢。

2 个答案:

答案 0 :(得分:1)

为了确定哪个线程最后执行,您应该打印迭代索引的值(而不是复制线程ID):

#include<stdio.h>
#include<omp.h>

int main() {
  int kk;
#pragma omp parallel
  {
#pragma omp for schedule(runtime) lastprivate(kk) 
    for(int ii=0; ii < 1000; ii++ ) {
      kk = omp_get_thread_num();
      printf("ii = %d, kk = %d\n",ii,kk);
    }
  }
  printf("kk = %d\n", kk);
  return 0;
}

如果您运行此程序,您会注意到执行迭代999的线程设置了kk的值。

关于这句话(强调我的):

  

当我们有一组线程工作在'for',时,我们无法保证哪个线程最后执行

你所说的通常是正确的,但有一个例外(OpenMP 3.1标准的第2.5节):

  

具有相同计划和迭代计数的不同循环区域,   即使它们出现在同一个平行区域,也可以分布   线程之间的迭代不同。 唯一的例外是   静态计划 ...

现在,由于您未指定任何计划,因此遵循以下规则:

  

如果loop指令没有schedule子句,那么当前   def-sched-var ICV的值决定了时间表

如果def-sched-var确定了schedule(static)(正如我经历的那样多次),那么您的计划的最终版本将始终 k = 4 < / p>

答案 1 :(得分:0)

你混淆了两个不同的“最后”的想法。

标准说“当一个lastprivate子句出现在指令上,用于标识工作共享构造时,每个新列表项的值来自相关循环的顺序最后一次迭代”

这没有说明事情执行的顺序,而你假设“last”意味着暂时执行的最后一个线程。

因此,如果你有静态循环调度,保证最高编号的线程将执行最后一次循环迭代,因此保存的值将始终是来自编号最高的线程,并且它与特定(随机)无关线程碰巧执行的顺序。