我想将所有线程分成两个不同的组,因为我有两个并行的任务来异步运行。例如,如果有8个线程可用,我会想要6个专用于task1的线程,另外2个专用于task2。
如何使用OpenMP实现这一目标?
答案 0 :(得分:6)
这是OpenMP nested parallelism的作业,从OpenMP 3开始:您可以使用OpenMP tasks启动两个独立任务,然后在这些任务中,使用相应数量的线程的并行部分。 / p>
作为一个简单的例子:
#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
已更新 :我已将上述内容更改为包含线程祖先;因为有(例如)两个&#34;线程1&#34; s打印出来 - 这里我也打印了祖先(例如,&#34; 1&#5的5个孩子中的第1个线程) 34; vs&#34; 0和#34;的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开始它们并在编号中留下空白?