web-dev-qa-db-fra.com

Comment compiler openmp en utilisant g ++

J'ai un problème avec la compilation d'OpenMP.

Comme le code suivant:

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

Tout d'abord, je le compile en utilisant:

g++ test.cpp -fopenmp -lpthread

Et, j'ai la bonne réponse, il y a 3 fils au total.

Mais, quand je fais la compilation comme ceci:

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

il n'y a qu'un seul fil.

N'importe qui peut me dire comment compiler correctement ce code. Merci d'avance.

19
Gang.Wang

OpenMP est un ensemble de transformation de code pragmas, c'est-à-dire qu'ils ne sont appliqués qu'au moment de la compilation. Vous ne pouvez pas appliquer de transformation de code à un code objet déjà compilé (ok, vous pouvez, mais cela implique beaucoup plus de processus et dépasse la portée de ce que font la plupart des compilateurs de nos jours). Vous avez besoin -fopenmp pendant la phase de liaison uniquement pour que le compilateur lie automatiquement la bibliothèque d'exécution OpenMP libgomp - il ne fait rien d'autre au code objet.

Sur une note latérale, bien que techniquement correct, votre code utilise OpenMP d'une manière très non OpenMP. Tout d'abord, vous avez réimplémenté la construction OpenMP sections. La région parallèle de votre fonction main pourrait être réécrite d'une manière plus 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;
        }
    }
}

(si vous obtenez SIGILL lors de l'exécution de ce code avec plus de trois threads OpenMP, vous avez rencontré un bogue dans GCC, qui sera corrigé dans la prochaine version)

Deuxièmement, vous voudrez peut-être jeter un œil à la construction OpenMP task. Avec lui, vous pouvez mettre en file d'attente des morceaux de code à exécuter simultanément en tant que tâches par n'importe quel thread inactif. Malheureusement, il nécessite un compilateur qui prend en charge OpenMP 3.0, ce qui exclut MSVC++ de l'équation, mais uniquement si vous vous souciez de la portabilité vers Windows (et vous ne le faites évidemment pas, car vous utilisez des threads POSIX).

27
Hristo Iliev

Les pragmas OpenMP ne sont activés que lorsqu'ils sont compilés avec -fopenmp. Sinon, ils sont complètement ignorés par le compilateur. (Par conséquent, seulement 1 thread ...)

Par conséquent, vous devrez ajouter -fopenmp à la compilation de chaque module utilisant OpenMP. (Par opposition à la dernière étape de liaison.)

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