2017-09-13 5 views
0

Ich habe ein Programm, das ein Singleton verwendet. Dieses Programm lädt eine gemeinsam genutzte Objektbibliothek zur Laufzeit. Diese Bibliothek verwendet auch dasselbe Singleton. Das Problem ist, dass beim Zugriff auf den Singleton aus der Bibliothek eine neue Instanz des Singleton erstellt wird.Laufzeit dynamische Laden und Singletons

Das Programm mit -rdynamic verknüpft ist, verwende ich -fPIC für beide und das Laden geschieht wie folgt aus:

std::shared_ptr<Module> createModuleObject(const std::string& filename) 
{ 
    if (!fs::exists(filename)) 
     throw std::runtime_error("Library not found: " + std::string(filename)); 

    struct export_vtable* imports; 
    void *handle = dlopen(filename.c_str(), RTLD_LAZY | RTLD_GLOBAL); 

    if (handle) { 
     imports = static_cast<export_vtable*>(dlsym(handle, "exports")); 
     if (imports) 
      return std::shared_ptr<Module>(imports->make()); 
     else 
      throw std::runtime_error("Error trying to find exported function in library!"); 
    } else 
     throw std::runtime_error("Error trying to load library: " + std::string(filename)); 
} 

Die Bibliothek eine Klasse wie folgt exportiert:

Module* make_instance() 
{ 
    return new HelloWorld(); 
} 
struct export_vtable 
{ 
    Module* (*make)(void); 
}; 
struct export_vtable exports = { make_instance }; 

und diese Klasse nutzt vom Singleton.

Dies ist, wie das Singleton erstellt (Configuration.cpp):

std::unique_ptr<Configuration> Configuration::instance_(nullptr); 
std::once_flag Configuration::onlyOnceFlag_; 

Configuration& Configuration::instance() 
{ 
    if (instance_ == nullptr) 
    { 
     std::cout << "INSTANCE IS NULL, CREATING NEW ONE" << std::endl; 
     std::call_once(Configuration::onlyOnceFlag_, 
        [] { 
          Configuration::instance_.reset(new Configuration()); 
         }); 
    } 

    return *Configuration::instance_; 
}  

Sowohl das Programm als auch die Bibliothek Link gegen die Configuration.cpp. Wenn ich das aus der Bibliothek weglasse, erhalte ich einen undefinierten Symbolfehler, wenn ich versuche, auf den Singleton zuzugreifen.

Wer hat eine Idee, wie man das löst? Vielen Dank!

+1

Das ist einer der Gründe ist, warum Singletons eine schlechte Idee sind. Sie funktionieren nicht wie vorgesehen mit dynamisch verknüpften Bibliotheken. Bleiben Sie auch lieber bei [Scott Meyers Singleton Pattern] (https://stackoverflow.com/questions/1008019/c-singleton-design-pattern). – user0042

+0

Mit Singletons ist nichts verkehrt. Bei dieser speziellen Implementierung gibt es zwei Probleme: 1) Sie haben die Kontrolle über die Singleton-Lebensdauer aufgegeben. Das Erstellen von Singleton beim ersten Aufruf der Instanzmethode ist nie eine gute Idee. 2) Ihre Bibliothek erstellt ihr eigenes Singleton, anstatt Singleton anzufordern, das von der übergeordneten Anwendung erstellt wurde. Um diese 'instance()' Methode zu beheben, sollte aus der Hauptanwendung importiert werden. P.S. Scott Meyers Singleton Pattern sollte Antipattern genannt werden. – VTT

+0

Es sollte möglich sein, dasselbe Singleton in der Bibliothek zu verwenden, oder? Das Problem scheint der Singleton in der Bibliothek zu sein, der den anderen beschattet. Eine 'setConfiguration()' Methode oder etwas in der Bibliothek zu haben ist auch keine Option für mich, da es den Zweck irgendwie vereitelt. ** EDIT: ** was meinst du mit "aus der Hauptanwendung importiert"? – Pfaeff

Antwort

0

So habe ich es gelöst für https://github.com/kvahed/codeare/blob/master/src/core/ReconStrategy.hpp Nachdem ich das gemeinsame Objekt geladen habe ich die Instanz des globalen Singleton Workspace der geladenen Klasse in der DLL zuweisen. Alle Klassen in https://github.com/kvahed/codeare/tree/master/src/modules sind von ReconStrategy und in gemeinsamen Objekten abgeleitet. Das Gute ist, dass dieser Code portabel ist.

Bei der Konstruktion eines solchen ReconStrategy dies geschieht:

ReconContext::ReconContext (const char* name) { 
    m_dlib = LoadModule ((char*)name); 
    if (m_dlib) { 
    create_t* create = (create_t*) GetFunction (m_dlib, (char*)"create"); 
    m_strategy = create(); 
    m_strategy->Name (name); 
    m_strategy->WSpace (&Workspace::Instance()); 
    } else { 
     m_strategy = 0; 
    } 
    } 
} 

Der Schlüssel Linie hier ist m_strategy->WSpace (&Workspace::Instance());

+0

Das funktioniert nicht mehr, sobald Sie einen zweiten Singleton haben, der versucht, auf den ersten Singleton zuzugreifen (zum Beispiel ein Logging Singleton). Dann müssen Sie auch eine Zuweisungsmethode haben. Es vereitelt irgendwie den Zweck. – Pfaeff

+0

Könnte bitte jemand eine Sekunde dauern, um auf eine Antwort zu warten, bevor er einen Beitrag abstimmt, der helfen soll. Ich werde nie verstehen, woher diese Motivation kommt. Ich stimme nur böswillige Absicht und grobe Fahrlässigkeit ab. Auf den Punkt ist dies Valgrind-Test-Code und läuft den ganzen Tag auf MRI-Maschinen ohne Speicherlecks und dergleichen. Was ich oben biete, erlaubt jedem gemeinsamen Objekt, seinen lokalen Arbeitsbereich für private Matrizen und einen globalen für den Rekonstruktionsdienst zu haben, um es an Rekonstruktionsschritte in der Kette weiterzugeben. Ernsthaft, ich werde einige Leute nicht bekommen. –

+0

Also würden Sie alle Singletons in einem einzigen Arbeitsbereich-Objekt bündeln und dann Ihrer Bibliothek zuweisen? Was ist, wenn die Singletons aufeinander zugreifen müssen? Nehmen wir an, ein Logging-Singleton versucht, den Log-Level von einer Konfiguration Singleton zu bestimmen – Pfaeff