2012-08-17 275 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