【问题标题】:"omp parallel for" does not work in "omp parallel"“omp parallel for”在“omp parallel”中不起作用
【发布时间】:2021-08-20 21:37:08
【问题描述】:

我希望得到以下输出:

My rank is: 0 num is: 0
My rank is: 1 num is: 1
My rank is: 2 num is: 2
My rank is: 3 num is: 3

来自以下代码:

#pragma omp parallel
{
   int my_rank = omp_get_thread_num();

   #pragma omp parallel for num_threads(4)
   for(int i = 0; i < 4; i++){       
       printf("My rank is: %d num is: %d\n",my_rank, i);       
   }
}

但它给出以下输出:

My rank is: 0 num is: 0
My rank is: 0 num is: 1
My rank is: 0 num is: 2
My rank is: 0 num is: 3
My rank is: 2 num is: 0
My rank is: 2 num is: 1
My rank is: 2 num is: 2
My rank is: 2 num is: 3
My rank is: 3 num is: 0
My rank is: 3 num is: 1
My rank is: 3 num is: 2
My rank is: 3 num is: 3
My rank is: 1 num is: 0
My rank is: 1 num is: 1
My rank is: 1 num is: 2
My rank is: 1 num is: 3

有什么问题?

【问题讨论】:

    标签: c multithreading parallel-processing openmp pragma


    【解决方案1】:

    你不应该重复parallel,你已经在一个parallel块中,所以你只需要pragma omp for来循环,并且每个执行parallel块的线程都会自动占用循环的一部分,如果您指定pragma omp for。如果你想指定线程数,你可以先pragma omp parallel num_threads(4) 然后pragma omp for。在任何情况下,对于这么简单的一段代码,您都可以删除似乎不需要的整个外部块。

    这是正确的版本:

    #pragma omp parallel num_threads(4)
    {
      int my_rank = omp_get_thread_num();
    
      #pragma omp for
      for(int i = 0; i < 4; i++){       
          printf("My rank is: %d num is: %d\n", my_rank, i);       
      }
    }
    

    或者简单地说:

    #pragma omp parallel for num_threads(4)
    for(int i = 0; i < 4; i++){       
        printf("My rank is: %d num is: %d\n", omp_get_thread_num(), i);       
    }
    

    【讨论】:

    • 第一个也不起作用。第二个有效,但我想为其他目的运行一次 omp_get_thread_num()。
    • @salimtop 两个示例都是正确的,如果第一个示例不起作用,那么您的代码还有其他问题:请参阅here
    • 哦,对不起,我才意识到 omp for 中没有并行。成功了
    【解决方案2】:

    @Marco Bonelli 的答案很准确,我只是想进一步了解幕后发生的事情。

    默认情况下,nested parallelism禁用。尽管如此,您可以通过以下任一方式明确启用 nested parallelism

       omp_set_nested(1);
    

    或通过将OMP_NESTED 环境变量设置为true。

    同样从OpenMP standard我们知道:

    当一个线程遇到一个并行结构时,一组线程是 创建以执行并行区域。 遇到并行构造的线程变为 新团队的主线程,线程号为零 新平行区域的持续时间。新团队中的所有线程, 包括主线程,执行区域。一旦球队在 创建后,团队中的线程数保持不变 该平行区域的持续时间。

    来自source,您可以阅读以下内容。

    OpenMP 并行区域可以相互嵌套。 如果嵌套 并行性被禁用,然后由一个线程创建的新团队 在平行区域内遇到平行构造包括 只有遇到的线程。如果启用了嵌套并行, 那么新团队可能包含多个线程。

    这解释了为什么当你添加第二个parallel regionie,#pragma omp parallel for num_threads(4))时只有一个线程per 团队执行封闭代码( for 循环)。换句话说,从第一个parallel region4线程被创建,每个线程在遇到第二个parallel region时将创建一个新团队并成为该团队的主人(即,将拥有ID=0在新创建的团队中)。 但是,由于您没有显式启用嵌套并行性,因此这些团队中的每一个都仅由一个线程组成。因此,4 各有一个线程的团队将执行 for 循环。因此,您将有以下语句:

       printf("My rank is: %d num is: %d\n",my_rank, i); 
    

    正在打印4 x 4 = 16 times循环迭代的总数乘以4 团队中的线程总数)。这就是您得到以下输出的原因:

    My rank is: 0 num is: 0
    My rank is: 0 num is: 1
    My rank is: 0 num is: 2
    My rank is: 0 num is: 3
    My rank is: 2 num is: 0
    My rank is: 2 num is: 1
    My rank is: 2 num is: 2
    My rank is: 2 num is: 3
    My rank is: 3 num is: 0
    My rank is: 3 num is: 1
    My rank is: 3 num is: 2
    My rank is: 3 num is: 3
    My rank is: 1 num is: 0
    My rank is: 1 num is: 1
    My rank is: 1 num is: 2
    My rank is: 1 num is: 3
    

    下图提供了该流程的可视化:

    请记住,在上图中,我假设循环之间的迭代有一定的static 循环分布,我并不是暗示循环迭代将始终像这样在 OpenMP 标准的所有实现中进行划分。

    我希望得到以下输出:

    My rank is: 0 num is: 0
    My rank is: 1 num is: 1
    My rank is: 2 num is: 2
    My rank is: 3 num is: 3
    

    很明显,您正在寻找的是:

     #pragma omp parallel for num_threads(4)
     for(int i = 0; i < 4; i++){       
         printf("My rank is: %d num is: %d\n", omp_get_thread_num(), i);       
     }
    

    #pragma omp parallel for

    将创建一个parallel region(如前所述),并且将使用default chunk sizedefault schedule为该区域的threads分配它所包含的循环的迭代,即通常 static。但请记住,default scheduleOpenMP 标准的不同具体实现之间可能会有所不同。

    您可以从OpenMP 5.1 阅读更正式的描述:

    worksharing-loop 结构指定一个或一个的迭代 更多相关的循环将由线程中的线程并行执行 团队在他们的隐含任务的背景下。 迭代是 分布在团队中已经存在的线程中 执行工作共享循环区域所在的并行区域 绑定

    Moreover,

    并行循环结构是指定并行循环的快捷方式 包含带有一个或多个相关联的循环构造的构造 循环,没有其他语句。

    或者非正式地,#pragma omp parallel for 是构造函数 #pragma omp parallel#pragma omp for 的组合。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 2018-07-20
      • 2021-06-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多