2015-03-18 19 views
8

La mia domanda riguarda l'uso di OpenMP in funzioni C++ memorizzate in librerie dinamiche. Consideriamo il seguente codice (in shared.cpp):Errore ingannevole con OpenMP in funzione caricato da librerie dinamiche

#include "omp.h" 
#include <iostream> 
extern "C" { 
int test() { 
    int N = omp_get_max_threads(); 
#pragma omp parallel num_threads(N) 
    { 
    std::cout << omp_get_thread_num() << std::endl; 
    } 
    return 0; 
} 
}; 

ho compilare il codice utilizzando g ++: g ++ -fopenmp -shared -fPIC -o shared.so shared.cpp. Quindi, utilizzare la funzione prova, ho il seguente programma (main.cpp):

#include <iostream> 
#include <dlfcn.h> 
int main() { 
    void* handle = dlopen("./shared.so", RTLD_NOW); 
    if (!handle) { 
    std::cerr << "can not open shared.so" << std::endl; 
    return 1; 
    } 
    int(*f)() = (int(*)()) dlsym(handle,"test"); 
    if (!f) { 
    std::cerr << "can not find 'test' symbol in shared.so" << std::endl; 
    return 1; 
    } 
    (*f)(); 
    if (dlclose(handle)) { 
    std::cerr << "can not close shared.so" << std::endl; 
    return 1; 
    } 
    return 0; 
} 

compilato con il comando: g ++ -o main.cpp principale -ldl Il problema è che un l'errore di segmentazione si verifica alla fine dell'esecuzione del programma. Secondo valgrind, alcuni thread sono ancora attivi a questo punto, che sembra essere coerente con il comportamento di OpenMP.

Una soluzione (per il codice C) da this post è per compilare il programma utilizzando il gcc -fopenmp bandiera, ma g ++ sembra abbastanza intelligente per rilevare che OpenMP non viene mai usata in quel programma, e l'ambiente OpenMP è mai caricato (il codice assembly di entrambe le versioni è uguale). L'unica soluzione che ho trovato è quella di effettuare una chiamata inutile ad OpenMP nel programma, che forza g ++ a caricare l'ambiente OpenMP e l'esecuzione è corretta. Ma per me questa soluzione è abbastanza brutta. Ho provato g ++ - 4.8.2, g ++ - 4.8.1, g ++ - 4.7.3 e g ++ - 4.6.4. (con icc-14, l'utilizzo dell'opzione -openmp sul programma risolve effettivamente il problema).

Qualcuno ha mai affrontato questo problema? C'è un workaround più pulito? Grazie, Thomas

Modifica provato con G ++ - 4.9.2: non riesce ancora

risposta

1

Penso che si sta vedendo un problema con libgomp, la libreria di runtime OpenMP di GCC. Prova a collegarlo con: g ++ -o main main.cpp -ldl -lgomp e il tuo segfault sarà scomparso.

libgomp ha uno stato interno inizializzato sulla prima chiamata OpenMP. Per qualche motivo, la desinizializzazione non si verifica se carichi dinamicamente una libreria OpenMP. Sembra un bug per me.

Il compilatore intel ha il proprio runtime OpenMP (libiomp5) che non presenta questo problema.