2012-06-25 74 views
4

我在调整思路以适应OpenMP的做事方式时遇到了困难。OpenMP - 在每次循环迭代中启动一个新线程

粗略地说,我要的是:

for(int i=0; i<50; i++) 
{ 
    doStuff(); 
    thread t; 
    t.start(callback(i)); //each time around the loop create a thread to execute callback 
} 

我想我知道如何做到这一点在C++ 11做的,但我需要能够实现使用OpenMP类似的东西。

+0

什么升压线程或QT线程? OpenMP适用于数值计算,因为与普通的线程框架相比,线程有很多开销。如果你想要线程化,你将在使用线程框架方面取得更好的成功。 – tune2fs

+0

OpenMP不起作用。你想要显式的线程控制,OpenMP(特别是'parallel for'构造)全部关于*隐藏*显式线程控制。 –

+0

我想,由于数据依赖性,上面给出的示例不能完全按照这种方式完成。这个样本很难判断。您需要改变处理问题的方式,使其适用于OpenMP。见下文。 –

回答

7

与您想要的最接近的是OpenMP任务,可用于OpenMP v3.0及更高版本的编译器。它是这样:

#pragma omp parallel 
{ 
    #pragma omp single 
    for (int i = 0; i < 50; i++) 
    { 
     doStuff(); 
     #pragma omp task 
     callback(i); 
    } 
} 

这段代码可以使毛在一个线程只能执行,它会创建将调用callback()使用不同的参数50 OpenMP的任务。然后它会在退出并行区域之前等待所有任务完成。空闲线程将执行任务(可能是随机的)。 OpenMP在每个并行区域的末尾施加了一个隐式屏障,因为它的fork-join执行模型要求只有主线程在并行区域之外运行。

下面是一个示例程序(ompt.cpp):

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

void callback (int i) 
{ 
    printf("[%02d] Task stated with thread %d\n", i, omp_get_thread_num()); 
    sleep(1); 
    printf("[%02d] Task finished\n", i); 
} 

int main (void) 
{ 
    #pragma omp parallel 
    { 
     #pragma omp single 
     for (int i = 0; i < 10; i++) 
     { 
     #pragma omp task 
     callback(i); 
     printf("Task %d created\n", i); 
     } 
    } 
    printf("Parallel region ended\n"); 

    return 0; 
} 

编译和执行:

$ g++ -fopenmp -o ompt.x ompt.cpp 
$ OMP_NUM_THREADS=4 ./ompt.x 
Task 0 created 
Task 1 created 
Task 2 created 
[01] Task stated with thread 3 
[02] Task stated with thread 2 
Task 3 created 
Task 4 created 
Task 5 created 
Task 6 created 
Task 7 created 
[00] Task stated with thread 1 
Task 8 created 
Task 9 created 
[03] Task stated with thread 0 
[01] Task finished 
[02] Task finished 
[05] Task stated with thread 2 
[04] Task stated with thread 3 
[00] Task finished 
[06] Task stated with thread 1 
[03] Task finished 
[07] Task stated with thread 0 
[05] Task finished 
[08] Task stated with thread 2 
[04] Task finished 
[09] Task stated with thread 3 
[06] Task finished 
[07] Task finished 
[08] Task finished 
[09] Task finished 
Parallel region ended 

注意,任务不会在他们创建相同的顺序执行。

GCC在4.4以前的版本中不支持OpenMP 3.0。无法识别OpenMP指令会被忽略和生成的可执行文件会在连续的代码段:

$ g++-4.3 -fopenmp -o ompt.x ompt.cpp 
$ OMP_NUM_THREADS=4 ./ompt.x 
[00] Task stated with thread 3 
[00] Task finished 
Task 0 created 
[01] Task stated with thread 3 
[01] Task finished 
Task 1 created 
[02] Task stated with thread 3 
[02] Task finished 
Task 2 created 
[03] Task stated with thread 3 
[03] Task finished 
Task 3 created 
[04] Task stated with thread 3 
[04] Task finished 
Task 4 created 
[05] Task stated with thread 3 
[05] Task finished 
Task 5 created 
[06] Task stated with thread 3 
[06] Task finished 
Task 6 created 
[07] Task stated with thread 3 
[07] Task finished 
Task 7 created 
[08] Task stated with thread 3 
[08] Task finished 
Task 8 created 
[09] Task stated with thread 3 
[09] Task finished 
Task 9 created 
Parallel region ended 
+0

谢谢,这看起来不错,但似乎没有像我期望的那样运行。它似乎没有立即返回控制回到循环。例如,在第一次循环迭代之后,我希望控制返回到回调(i)后面的语句,在这种情况下是for循环的i ++语句。 – user1478842

+0

您是否在启用OpenMP支持的情况下进行编译?你使用什么编译器(+版本)?它适用于科学Linux上的GCC 4.4.5和ICC 12.1.3。 –

+0

@ user1478842,看我更新的答案。 –

0

例如看看http://en.wikipedia.org/wiki/OpenMP

#pragma omp for

是你的朋友。 OpenMP不需要你考虑线程。您只需声明(!)您想要并行运行的内容,并且OpenMP兼容编译器在编译期间在代码中执行所需的转换。

OpenMP的规格也非常有用。他们解释相当不错可以做什么,以及如何:http://openmp.org/wp/openmp-specifications/

你的样本可能是这样的:在for循环并行运行

#pragma omp parallel for 
for(int i=0; i<50; i++) 
{ 
    doStuff(); 
    thread t; 
    t.start(callback(i)); //each time around the loop create a thread to execute callback 
} 

一切。你必须注意数据依赖。 'doStuff()'函数在您的伪代码中按顺序运行,但是会在我的示例中并行运行。你还需要指定哪些变量是线程私有的,以及类似于#pragma语句中的那些变量。

+1

现在,您将OpenMP与显式线程混合在一起,而不是OP想要的东西。 –

+0

通过了解OpenMP,我明白他有一个普遍问题。 –

+0

这不是我正在寻找的东西,谢谢你的回应。 – user1478842