我想将所有线程划分为2个不同的组,因为我有两个并行任务异步运行。例如,如果共有8个线程可用,那么我会将6个线程专用于task1,另外2个专用于task2。OpenMP:将所有线程划分为不同的组
如何通过OpenMP实现此目标?
我想将所有线程划分为2个不同的组,因为我有两个并行任务异步运行。例如,如果共有8个线程可用,那么我会将6个线程专用于task1,另外2个专用于task2。OpenMP:将所有线程划分为不同的组
如何通过OpenMP实现此目标?
这是OpenMP nested parallelism的作业,从OpenMP 3开始:可以使用OpenMP tasks来启动两个独立的任务,然后在这些任务中,使用适当数量的线程并行部分。
作为一个简单的例子:
#include <stdio.h>
#include <omp.h>
int main(int argc, char **argv) {
omp_set_nested(1); /* make sure nested parallism is on */
int nprocs = omp_get_num_procs();
int nthreads1 = nprocs/3;
int nthreads2 = nprocs - nthreads1;
#pragma omp parallel default(none) shared(nthreads1, nthreads2) num_threads(2)
#pragma omp single
{
#pragma omp task
#pragma omp parallel for num_threads(nthreads1)
for (int i=0; i<16; i++)
printf("Task 1: thread %d of the %d children of %d: handling iter %d\n",
omp_get_thread_num(), omp_get_team_size(2),
omp_get_ancestor_thread_num(1), i);
#pragma omp task
#pragma omp parallel for num_threads(nthreads2)
for (int j=0; j<16; j++)
printf("Task 2: thread %d of the %d children of %d: handling iter %d\n",
omp_get_thread_num(), omp_get_team_size(2),
omp_get_ancestor_thread_num(1), j);
}
return 0;
}
一个8芯(16个硬件线程)节点上运行此,
$ gcc -fopenmp nested.c -o nested -std=c99
$ ./nested
Task 2: thread 3 of the 11 children of 0: handling iter 6
Task 2: thread 3 of the 11 children of 0: handling iter 7
Task 2: thread 1 of the 11 children of 0: handling iter 2
Task 2: thread 1 of the 11 children of 0: handling iter 3
Task 1: thread 2 of the 5 children of 1: handling iter 8
Task 1: thread 2 of the 5 children of 1: handling iter 9
Task 1: thread 2 of the 5 children of 1: handling iter 10
Task 1: thread 2 of the 5 children of 1: handling iter 11
Task 2: thread 6 of the 11 children of 0: handling iter 12
Task 2: thread 6 of the 11 children of 0: handling iter 13
Task 1: thread 0 of the 5 children of 1: handling iter 0
Task 1: thread 0 of the 5 children of 1: handling iter 1
Task 1: thread 0 of the 5 children of 1: handling iter 2
Task 1: thread 0 of the 5 children of 1: handling iter 3
Task 2: thread 5 of the 11 children of 0: handling iter 10
Task 2: thread 5 of the 11 children of 0: handling iter 11
Task 2: thread 0 of the 11 children of 0: handling iter 0
Task 2: thread 0 of the 11 children of 0: handling iter 1
Task 2: thread 2 of the 11 children of 0: handling iter 4
Task 2: thread 2 of the 11 children of 0: handling iter 5
Task 1: thread 1 of the 5 children of 1: handling iter 4
Task 2: thread 4 of the 11 children of 0: handling iter 8
Task 2: thread 4 of the 11 children of 0: handling iter 9
Task 1: thread 3 of the 5 children of 1: handling iter 12
Task 1: thread 3 of the 5 children of 1: handling iter 13
Task 1: thread 3 of the 5 children of 1: handling iter 14
Task 2: thread 7 of the 11 children of 0: handling iter 14
Task 2: thread 7 of the 11 children of 0: handling iter 15
Task 1: thread 1 of the 5 children of 1: handling iter 5
Task 1: thread 1 of the 5 children of 1: handling iter 6
Task 1: thread 1 of the 5 children of 1: handling iter 7
Task 1: thread 3 of the 5 children of 1: handling iter 15
更新:我已经改变了包含的上述线程祖先;出现了混淆,因为有(例如)两个“线1”的打印 - 在这里我还印出了祖先(例如,“1的5个孩子的线程1”与0个11个孩子的线程1 “)。
从OpenMP standard,S.3.2.4,“的omp_get_thread_num
例程返回线程数,目前球队内,调用线程的。 ”和第2.5节,“当线程遇到并行构造时,创建一个线程组到 执行并行区域[...]遇到并行构造的线程 成为新团队的主线程, ,新的并行区域的持续时间为 ,线程号为零。 ”
也就是说,在这些(嵌套的)并行区域的每一个内,创建线程组,其线程ID从零开始;但仅仅因为这些ID在队内重叠并不意味着它们是相同的线程。在这里,我强调了通过打印祖先的号码,但如果线程正在做CPU密集型工作,您还会看到有监视工具确实有16个活动线程,而不仅仅是11.
原因为什么他们是团队本地线程号码而不是全局唯一的线程号码非常简单;在嵌套和动态并行性可能发生的环境中跟踪全局唯一的线程数几乎是不可能的。假设有三组线程,分别编号为[0..5],[6,.. 10]和[11..15],中间的团队完成。我们是否在线程编号中留下空白?我们是否会中断所有线程以更改其全局数字?如果一个新的团队开始,有7个线程会怎么样?我们是在6点开始并且有重叠的线程ID,或者我们是从16开始,并在编号方面留下空隙?
感谢您的出色答案!但是,实现的一个主要缺陷是,实际上,较小的线程组基本上是较大线程组的一个子集。在你的例子中,task2也涉及所有在task1上工作的线程。我希望有些线程只适用于task1,而其他所有线程都适用于task2,但不要触及task1。在我的应用程序中,两个线程组之间不能有任何重叠。否则,由于地区利用率低,性能可能会大幅下降。 – SciPioneer 2014-08-30 03:44:12
@SciPioneer - 不,完全没有;两队在线内数字重叠,但它们是不同的线程。我已经添加了一个更新来澄清这一点。 – 2014-08-30 04:28:29
感谢您的澄清!真的帮了很多! – SciPioneer 2014-08-31 02:02:53