块中的OpenMP动态循环分解

时间:2011-04-09 14:29:37

标签: c parallel-processing openmp partitioning

我正在使用OpenMP并行执行大型循环。假设我正在处理的数组总共有N个条目。我希望一个线程执行前N / 2个条目,另一个线程执行最后一个N / 2。

我必须避免线程处理彼此相邻的条目。大小N总是比线程数大得多,所以我不需要担心锁定,如果我可以让OpenMP以我上面概述的方式分配工作。

如果在编译时知道大小N,我可以使用#pragma omp parallel for schedule(static,N/2)。不幸的是它不是。那么,我该如何动态定义块大小呢?

3 个答案:

答案 0 :(得分:4)

只要N在运行时已知,就没有问题;我不确定为什么你认为它必须在编译时知道。如果在编译时必须知道所有内容,那么OMP循环结构的用途非常有限。

#include <stdio.h>
#include <stdlib.h>
#include <omp.h>

int main(int argc, char **argv) {
    int n;
    int chunksize;

    if (argc != 2) {
        fprintf(stderr,"Usage: %s n, where n = number of iterations.\n", argv[0]);
        exit(-1);
    }
    n = atoi(argv[1]);
    if (n<1 || n>200) n = 10;

    chunksize = n/2;

    #pragma omp parallel num_threads(2) default(none) shared(n,chunksize)
    {
        int nthread = omp_get_thread_num();
        #pragma omp for schedule(static,chunksize) 
        for (int i=0; i<n; i++) {
            printf("Iter %d being done by thread %d\n", i, nthread);
        }
    }

    return 0;
}

它运行得足够简单,如此:

$ gcc -v
[...]
gcc version 4.4.0 (GCC) 

$ gcc -o loop loop.c -fopenmp

$ ./loop 10
Iter 5 being done by thread 1
Iter 6 being done by thread 1
Iter 7 being done by thread 1
Iter 8 being done by thread 1
Iter 9 being done by thread 1
Iter 0 being done by thread 0
Iter 1 being done by thread 0
Iter 2 being done by thread 0
Iter 3 being done by thread 0
Iter 4 being done by thread 0

答案 1 :(得分:2)

如果你不想像@Jonathan Dursi's answer那样使用内置的openmp调度选项,那么你可以自己实现所需的选项:

#include <stdio.h>
#include <omp.h>
/* $ gcc -O3 -fopenmp -Wall *.c && ./a.out  */

static void doloop(int n) {
  int thread_num, num_threads, start, end, i;
#pragma omp parallel private(i,thread_num,num_threads,start,end)
  {
    thread_num = omp_get_thread_num();
    num_threads = omp_get_num_threads();
    start = thread_num * n / num_threads;
    end = (thread_num + 1) * n / num_threads;

    for (i = start; i != end; ++i) {
      printf("%d %d\n", thread_num, i);
    }
  }
}

int main() {
  omp_set_num_threads(2);
  doloop(10);
  return 0;
}

输出

0 0
0 1
0 2
0 3
0 4
1 5
1 6
1 7
1 8
1 9

答案 2 :(得分:0)

我在dotNET上遇到了类似的问题,最后编写了一个智能队列对象,一旦可用,就会一次返回十几个对象。一旦我掌握了一个软件包,我就决定一个可以一次处理所有这些软件的线程。

在处理这个问题时,我记住W队列比M队列更好。最好有一个长行与多个工人,而不是每个工人有一条线。