2017-09-06 90 views
0

我看到的所有openmp教程示例都是爲for循環創建線程。但我需要爲普通的語句組創建線程,這些語句可能會聚集到函數中。例如,像下面這樣:爲函數創建openmp線程

#include <stdio.h> 
#include <omp.h> 
int A() { printf("in A:%d\n", omp_get_thread_num()); } 
int B() { printf("in B:%d\n", omp_get_thread_num()); } 
int D() { printf("in D:%d\n", omp_get_thread_num()); } 
int E() { printf("in E:%d\n", omp_get_thread_num()); } 
int F() { printf("in F:%d\n", omp_get_thread_num()); } 
int G() { printf("in G:%d\n", omp_get_thread_num()); } 
int H() { printf("in H:%d\n", omp_get_thread_num()); } 
int C() { 
    printf("in C:%d\n", omp_get_thread_num()); 
    #pragma omp parallel num_threads(2) 
    { 
     D(); // want to execute D,E in separate threads 
     E(); 
    } 
    F(); 
} 
main() { 
    omp_set_nested(1); 
    printf("in main:%d\n", omp_get_thread_num()); 
    G(); 
    #pragma omp parallel num_threads(3) 
    { 
     A(); // want to execute A,B,C in separate threads 
     B(); 
     C(); 
    } 
    H(); 
} 

在上面的代碼,我希望每個函數恰好一次執行,但在不同的線程。 (所以我可能在上面的代碼中使用了僞指令,請根據需要糾正它。)

如何使用openmp編寫這種嵌套並行函數?這些函數會共享所有可用的全局變量,還是有辦法指定哪些變量將由哪些函數共享?

EDITS:在閱讀下面的Jorge Bellon的回答後,我編碼了以下內容,並在代碼後顯示其輸出。看起來像許多函數正在使用線程0,這不是我想要的 - 我希望函數能夠並行執行。另外,我只需要一次執行G,所以看起來像我必須刪除「num_threads(3)」行。讓我知道什麼是解決這個問題。

// compile this with: g++ -fopenmp 
int A() { printf("in H:%d\n", omp_get_thread_num()); sleep(1); } 
// similarly for B, D, E, F, G, H 
int C() { 
    printf("in C:%d\n", omp_get_thread_num()); sleep(1); 
    #pragma omp task 
    D(); 
    #pragma omp task 
    E(); 
    #pragma omp taskwait 
    F(); sleep(1); 
} 
main() { 
    omp_set_nested(1); 
    printf("in main:%d\n", omp_get_thread_num()); 
    #pragma omp parallel num_threads(3) 
    G(); 
    #pragma omp task 
    A(); 
    #pragma omp task 
    B(); 
    #pragma omp task 
    C(); 
    #pragma omp taskwait 
    H(); 
} 
// outputs: 
in main:0 
in G:1 
in G:0 
in G:2 
in A:0 
in B:0 
in C:0 
in D:0 
in E:0 
in F:0 
in H:0 

回答

1

並行這種代碼的最好方法是使用OpenMP task結構。您的並行區域將創建一個線程池,主線程將創建外部任務,其餘線程將在可用時儘快處理這些任務。

// [...] 

int C() { 
    // You can create tasks within tasks 
    // In this example is better to place {D,E} and {E} in tasks 
    // and omit the task construct of C function call 
    #pragma omp task 
    { 
    D(); 
    E(); 
    } 
    // if F() needs D and E to finish, a taskwait is necessary 
    F(); 
} 

main() { 
    // omp_set_nested no longer necessary 
    printf("in main:%d\n", omp_get_thread_num()); 
    G(); 
    #pragma omp parallel num_threads(3) 
    #pragma omp single 
    { 
    // a single thread creates the tasks 
    // other threads in the team will be able to execute them 
    // want to execute A,B,C in separate threads 
    #pragma omp task 
    A(); 
    #pragma omp task 
    B(); 
    #pragma omp task 
    C(); 
    // wait until all the tasks have been finished 
    #pragma omp taskwait 
    } 
    H(); 
} 

每個函數是否在不同的線程中執行完全取決於程序在運行時的狀態。這意味着如果所有其他線程都忙,某些任務可能會在同一個線程中執行,這不是特別的問題。

您可以使用task dependences(自OpenMP 4起)來控制是否允許在創建時執行任務。

+0

謝謝。我試過你的解決方案,但看起來像我只有一個線程。請參閱上述問題中添加的詳細信息。 – R71

+0

我不需要超出本地連接的任務,所以我不需要任務依賴關係的細節。 – R71

+0

您需要指定線程將並行運行的範圍。在你顯示的基於任務的代碼中,並行範圍只有'G();'。您需要使用尖括號'{}'(參見我的示例)來定義並行部分將包括以下所有行,直到主函數結束。要知道任務是否並行運行,請將'get_thread_num()'返回值添加到'printf'中,以便知道哪個線程正在運行該任務。 –

0

以下解決方案是用C++ 11線程實現的。一個詳細的openmp版本仍然有待解決。

// compile this with: g++ -pthread -std=gnu++0x 
#include <stdio.h> 
#include <unistd.h> // for sleep 
#include <thread> 
#include <iostream> 
#include <sstream> 
using namespace std; 
int A() { stringstream ss; ss << this_thread::get_id(); 
      printf("in A:%s\n", ss.str().c_str()); sleep(1); } 
// similarly for B, D, E, F, G, H 
int C() { 
    stringstream ss; ss << this_thread::get_id(); 
    printf("in C:%s\n", ss.str().c_str()); sleep(1); 
    std::thread thread_1(D); 
    std::thread thread_2(E); 
    thread_1.join(); 
    thread_2.join(); 
    F(); sleep(1); 
} 
main() { 
    printf("in main\n"); 
    G(); 
    std::thread thread_1(A); 
    std::thread thread_2(B); 
    std::thread thread_3(C); 
    thread_1.join(); 
    thread_2.join(); 
    thread_3.join(); 
    H(); 
} 
// outputs: 
in main 
in G:0x600000060 
in A:0x60005aa10 
in B:0x60005ab10 
in C:0x60005ae40 
in D:0x60005af40 
in E:0x60005b040 
in F:0x60005ae40 
in H:0x600000060