45

在 OpenMP 中使用时,线程会被分配到部分omp sections内的块中,还是将每个线程分配给每个部分?

什么时候nthreads == 3

#pragma omp sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

输出:

id=1
id=1

但是当我执行以下代码时:

#pragma omp sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

#pragma omp sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

输出:

id=1
id=1

id=2
id=2

从这些输出中,我无法理解 OpenMP 中节的概念是什么。

4

9 回答 9

102

OP 发布的代码永远不会并行执行,因为parallel关键字没有出现。OP 的 id 与 0 不同的事实表明,他的代码可能嵌入在并行指令中。但是,这在他的帖子中并不清楚,并且可能会使初学者感到困惑。

最小的合理示例是(对于 OP 发布的第一个示例):

#pragma omp parallel sections
{
    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }

    #pragma omp section
    { 
        printf ("id = %d, \n", omp_get_thread_num());
    }
}

在我的机器上,这打印

id = 0,
id = 1,

表明这两个部分正在由不同的线程执行。

值得注意的是,然而,这段代码不能提取比两个线程更多的并行度:如果它用更多的线程执行,其他线程就没有任何工作要做,只会闲置。

于 2013-10-09T20:29:43.160 回答
28

并行部分的想法是向编译器提示可以并行执行各种(内部)部分,例如:

#pragma omp parallel sections
{
   #pragma omp section
   {
      /* Executes in thread 1 */
   } 
   #pragma omp section
   {
      /* Executes in thread 2 */
   } 
   #pragma omp section
   {
      /* Executes in thread 3 */
   } 
   /* ... */
}

这是对编译器的提示,但不保证会发生,尽管它应该发生。您的输出是预期的;它说在线程 id 1 和线程 2 中执行了 #se​​ctions。输出顺序是不确定的,因为您不知道哪个线程将首先运行。

于 2010-05-05T06:17:01.677 回答
13

将第一行从

#pragma omp 部分

进入

#pragma omp 并行部分

“parallel”指令确保将两个部分分配给两个线程。然后,您将收到以下输出 id = 0, id = 1,

于 2013-11-15T21:05:22.767 回答
11

您缺少parallel关键字。关键字触发openmpparallel并行运行。

于 2014-05-09T02:55:59.630 回答
5

根据OpenMP 标准 3.1,第 2.5.2 节(强调我的):

section 构造是一种非迭代工作共享构造,它包含一组结构化块,这些块将分布在团队中的线程之间并由它们执行。每个结构化块 由团队中的一个线程在其隐式任务的上下文中执行一次。

...

section 结构中的每个结构化块前面都有一个 section 指令,除了可能的第一个块,前面的 section 指令是可选的。在团队中的线程之间调度结构化块的方法是实现定义的。除非指定 nowait 子句,否则在 section 构造的末尾有一个隐式障碍。

因此,将这些规则应用于您的案例,我们可以争辩说:

  1. sections指令中标识的不同结构化块由一个线程执行一次。换句话说,你总是有四个打印,无论线程的数量是多少
  2. 第一个中的块将在第二个中的块(也以不确定的顺序执行sections之前sections执行(以不确定的顺序)。这是因为工作共享结构末端的隐含障碍
  3. 调度是实现定义的,因此您无法控制已分配给定部分的线程

因此,您的输出是由于您的调度程序决定将不同的块分配给团队中的线程的方式。

于 2013-10-10T21:08:14.113 回答
3

将更多信息添加到输出行并添加更多部分(如果您有线程数)可能会有所帮助

#pragma omp parallel sections
{
    #pragma omp section
    {
        printf ("section 1 id = %d, \n", omp_get_thread_num()); 
    }
    #pragma omp section
    {
        printf ("section 2 id = %d, \n", omp_get_thread_num());
    }
    #pragma omp section
    {
        printf ("section 3 id = %d, \n", omp_get_thread_num());
    }
}

然后你可能会得到更有趣的输出,如下所示:

section 1 id = 4,
section 3 id = 3,
section 2 id = 1,

它显示了如何通过任何可用线程以任何顺序执行这些部分。

于 2013-12-29T17:26:25.383 回答
0

请注意,“nowait”告诉编译器线程不需要等待退出该部分。在 Fortran 中,“nowait”位于循环或部分的末尾,这使得这一点更加明显。

于 2013-09-13T20:06:38.057 回答
0

#pragma omp parallel是最初创建(分叉)线程的原因。只有在创建线程时,其他 Openmp 构造才会有意义。

因此,方法1:

// this creates the threads
#pragma omp parallel
{
   #pragma omp sections
   {
     #pragma omp section
     {
        // code here
     }
     #pragma omp section
     {
        // code here
     }
   }
}

或者

方法二:

// this creates the threads and creates sections in one line
#pragma omp parallel sections
   #pragma omp section
   {
      // code here
   }
   #pragma omp section
   {
      // code here
   }
}
于 2021-03-27T04:40:37.323 回答
-4

如果你真的想在不同的section启动不同的线程,该nowait子句告诉编译器线程不需要等待进入一个section。

#pragma omp parallel sections nowait
{
   ...
}
于 2012-11-07T20:15:28.763 回答