2012-06-25 93 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