0

我正在尝试运行以下代码来了解 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”中的值。

我将不胜感激有关此问题的帮助。谢谢。

4

2 回答 2

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 节):

具有相同调度和迭代计数的不同循环区域,即使它们发生在同一个并行区域中,也可以在线程之间以不同的方式分配迭代。唯一的例外是静态计划......

现在,由于您没有指定任何时间表,因此以下规则成立:

如果循环指令没有调度子句,则 def-sched-var ICV 的当前值确定调度

如果def-sched-var确定一个schedule(static)(正如我所经历的那样),那么您的程序的最终打印将始终是 k = 4

于 2013-06-25T18:11:28.787 回答
0

您混淆了“最后”的两个不同概念。

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

这并没有说明事情的执行顺序,而您假设“最后一个”是指时间上最后一个要执行的线程。

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

于 2013-06-26T09:56:53.260 回答