2012-08-17 12 views
16

Mam problem z kompilacją openmp.Jak skompilować openmp używając g ++

Podobnie jak w poniższym kodzie:

#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; 
} 

Po pierwsze, skompilować go za pomocą:

g++ test.cpp -fopenmp -lpthread 

I mam właściwą odpowiedź, istnieją 3 nitki całkowicie.

Ale kiedy robię kompilacji takiego:

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

istnieje już tylko jeden wątek.

Każdy może mi powiedzieć, jak poprawnie skompilować ten kod. Z góry dziękuję.

+3

Myślę, że pragmy OpenMP są ignorowane, chyba że masz '-fopenmp'. Więc będziesz potrzebować '-fopenmp' na wszystkich modułach, które mają pragmy OpenMP. – Mysticial

+0

@Mysticial Myślisz, że powinienem dodać -fopenmp podczas kompilowania pliku .cpp do .o? –

+1

Tak. Wypróbuj 'g ++ -c test.cpp -o test.o -fopenmp'. Zrobię odpowiedź, jeśli to zadziała. – Mysticial

Odpowiedz

15

Pragmy OpenMP są włączane tylko po skompilowaniu z -fopenmp. W przeciwnym razie są one całkowicie ignorowane przez kompilator. (Stąd tylko 1 wątek ...)

Dlatego do kompilacji każdego modułu korzystającego z OpenMP należy dodać -fopenmp. (A nie tylko ostatni etap łączenia.)

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

OpenMP jest zestaw kodu transformującego pragma, to są one stosowane tylko w czasie kompilacji. Nie możesz zastosować transformacji kodu do już skompilowanego kodu obiektowego (ok, możesz, ale jest to znacznie bardziej angażujący proces i poza zakresem tego, co większość kompilatorów robi obecnie). Podczas fazy połączenia potrzebujesz tylko -fopenmp, aby kompilator automatycznie łączył bibliotekę wykonawczą OpenMP libgomp - nie robi nic więcej dla kodu obiektowego.

Na marginesie, choć technicznie poprawny, twój kod robi OpenMP w sposób bardzo nie-OpenMP. Najpierw ponownie zaimplementowano konstrukcję OpenMP sections. Region równolegle w funkcji main może być przepisany w bardziej OpenMP sposób:

#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; 
     } 
    } 
} 

(jeśli masz SIGILL podczas uruchamiania tego kodu z więcej niż trzech OpenMP wątków, masz napotkał błąd w GCC, który będzie poprawione w nadchodzącym wydaniu)

Po drugie, warto przyjrzeć się konstrukcji OpenMP task. Dzięki niemu można kolejkować fragmenty kodu, które mają być wykonywane jednocześnie jako zadania przez dowolny wątek. Niestety wymaga kompilatora obsługującego OpenMP 3.0, który wyklucza MSVC++ z równania, ale tylko wtedy, gdy zależy Ci na przenośności do Windowsa (i oczywiście nie, ponieważ używasz wątków POSIX).

+3

+1 za wykroczenie poza wezwanie do obowiązku dokładniejszego przyjrzenia się kodowi PO. – Mysticial