在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中各节的概念。
答案 0 :(得分:92)
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,
显示这两个部分正由不同的线程执行。
值得注意的是,然而这段代码无法提取比两个线程更多的并行性:如果它是用更多线程执行的,那么其他线程就没有任何工作要做,只会闲置。
答案 1 :(得分:26)
并行部分的想法是给编译器一个提示,即各个(内部)部分可以并行执行,例如:
#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 */
}
/* ... */
}
这是对编译器的暗示,但不保证会发生,尽管应该如此。你的输出是预期的;它说#sections在线程id 1和线程2中执行。输出顺序是非确定性的,因为你不知道首先运行什么线程。
答案 2 :(得分:12)
从
更改第一行#pragma omp sections
进入
#pragma omp parallel sections
“parallel”指令确保将两个部分分配给两个线程。 然后,您将收到以下输出 id = 0, id = 1,
答案 3 :(得分:9)
您缺少parallel
个关键字。
parallel
关键字并行触发openmp运行。
答案 4 :(得分:4)
根据OpenMP standard 3.1,第2.5.2节(强调我的):
sections构造是一个非迭代的工作共享构造 包含一组要分布在其中的结构化块 并由团队中的线程执行。每个结构化块都是 在其上下文中由团队中的一个执行一次 隐含的任务。
...
sections结构中的每个结构化块前面都有一个 section指令除了可能是第一个块之外,其中a 前面的section指令是可选的。 调度方法 团队中线程之间的结构化块是实现 定义即可。在部分的末尾有一个隐含障碍 除非指定了nowait子句,否则构造。
因此,将这些规则应用于您的案例,我们可以说:
sections
指令中标识的不同结构化块由一个线程执行一次。换句话说,你总是有四个打印,无论哪个线程sections
中的块将以非确定性顺序执行之前第二个sections
中的块(也以非确定性执行)订购)。这是因为工作共享结构因此,您的输出是由于您的调度程序决定将不同的块分配给团队中的线程的方式。
答案 5 :(得分:2)
向输出行添加更多信息并添加更多部分(如果您有线程数)可能会有所帮助
#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,
显示了如何通过任何可用的线程以任何顺序执行这些部分。
答案 6 :(得分:0)
请注意,'nowait'告诉编译器线程不需要等待 退出 部分。在Fortran中,'nowait'出现在循环或部分的末尾,这使得这更加明显。
答案 7 :(得分:0)
#pragma omp parallel
是最初创建(分叉)线程的原因。只有在创建线程时,其他 Openmp 结构才有意义。
因此, 方法一:
// 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
}
}
答案 8 :(得分:-3)
如果你想在不同的部分真正启动不同的线程,nowait
子句告诉编译器线程不需要等待进入一个部分。
#pragma omp parallel sections nowait
{
...
}