2012-08-17 71 views
16

我有關於openmp編譯的問題。如何使用g ++編譯openmp

如下面的代碼:

#include <iostream> 
#include <pthread.h> 
#include <omp.h> 
#include <semaphore.h> 
#include <stack> 
using namespace std; 
sem_t empty,full; 
stack<int> stk; 
void produce(int i) 
{ 
    { 
    sem_wait(&empty); 
      cout<<"produce "<<i*i<<endl; 
      stk.push(i*i); 
    sem_post(&full); 
    } 
} 
void consume1(int &x) 
{ 
    sem_wait(&full); 
      int data=stk.top(); 
      stk.pop(); 
      x=data; 
    sem_post(&empty); 
} 
void consume2() 
{ 
    sem_wait(&full); 
      int data=stk.top(); 
      stk.pop(); 
      cout<<"consume2 "<<data<<endl; 
    sem_post(&empty); 
} 
int main() 
{ 
    sem_init(&empty,0,1); 
    sem_init(&full,0,0); 
    pthread_t t1,t2,t3; 
    omp_set_num_threads(3); 
    int TID=0; 
    #pragma omp parallel private(TID) 
    { 
      TID=omp_get_thread_num(); 
      if(TID==0) 
      { 
      cout<<"There are "<<omp_get_num_threads()<<" threads"<<endl; 
      for(int i=0;i<5;i++) 
        produce(i); 
      } 
      else if(TID==1) 
      { 
        int x; 
        while(true) 
        { 
          consume1(x); 
          cout<<"consume1 "<<x<<endl; 
        } 
      } 
      else if(TID==2) 
      { 
        int x; 
        while(true) 
        { 
          consume1(x); 
          cout<<"consume2 "<<x<<endl; 
        } 
      } 
    } 
    return 0; 
} 

首先,我用編譯:

g++ test.cpp -fopenmp -lpthread 

而且,我答對了,有3個線程完全。

但是,當我做這樣的編譯:

g++ -c test.cpp -o test.o 
g++ test.o -o test -fopenmp -lpthread 

也僅僅只有一個線程。

任何人都可以告訴我如何正確編譯此代碼。先謝謝你。

+3

我想OpenMP編譯指示會被忽略,除非你有'-fopenmp'。所以你需要在所有具有OpenMP編譯指示的模塊上使用'-fopenmp'。 – Mysticial 2012-08-17 08:29:21

+0

@Mysticial你認爲我應該在將.cpp編譯爲.o文件時添加-fopenmp嗎? – 2012-08-17 08:34:07

+1

是的。嘗試'g ++ -c test.cpp -o test.o -fopenmp'。如果它有效,我會做出答案。 – Mysticial 2012-08-17 08:35:14

回答

15

OpenMP編譯指示僅在編譯時使用-fopenmp。否則,編譯器會完全忽略它們。 (因此,只有1個線程...)

因此,您需要將-fopenmp添加到每個使用OpenMP的單個模塊的編譯中。 (而不是僅僅最後的鏈接步驟。)

g++ -c test.cpp -o test.o -fopenmp 
g++ test.o -o test -fopenmp -lpthread 
22

OpenMP是一組代碼變換編譯指示,即它們是在編譯時只適用。你不能將代碼轉換應用到已經編譯好的目標代碼上(好吧,你可以,但它涉及的過程要多得多,大多數編譯器目前還沒有這麼做)。在鏈接階段,您只需要-fopenmp,以便編譯器自動鏈接OpenMP運行時庫libgomp - 它不會對目標代碼做任何其他操作。

在附註中,雖然技術上正確,但您的代碼以非OpenMP方式執行OpenMP。首先,您已經重新實現了OpenMP sections構造。在main功能並行區域可能更OpenMP的方式改寫:

#pragma omp parallel sections 
{ 
    #pragma omp section 
    { 
     cout<<"There are "<<omp_get_num_threads()<<" threads"<<endl; 
     for(int i=0;i<5;i++) 
      produce(i); 
    } 
    #pragma omp section 
    { 
     int x; 
     while(true) 
     { 
      consume1(x); 
      cout<<"consume1 "<<x<<endl; 
     } 
    } 
    #pragma omp section 
    { 
     int x; 
     while(true) 
     { 
      consume1(x); 
      cout<<"consume2 "<<x<<endl; 
     } 
    } 
} 

(如果你SIGILL而這段代碼運行三個以上的OpenMP線程,你遇到了GCC中的bug,這將是在即將發佈的版本中修復)

其次,您可能需要查看OpenMP task構造。藉助它,您可以將代碼片段排列爲任何空閒線程的任務併發執行。不幸的是,它需要一個支持OpenMP 3.0的編譯器,該編譯器從等式中排除了MSVC++,但前提是您關心的是Windows的可移植性(顯然您並不需要,因爲您使用的是POSIX線程)。

+3

+1超越了呼叫的責任,更真切地看待OP的代碼。 – Mysticial 2012-08-17 14:13:35