Singleton gemeinsam in shared object und loader verwenden [gelöst]
-
Hallo Jungs,
ich hab hier das Problem, dass ich ein Singleton sowohl in einem shared object als auch im Loader gemeinsam verwenden will. Als Loader bezeichne ich hier das "main()" Modul, welches "dlopen()" auf das shared object (ich nenns hier mal shobj) aufruft.
Im sourcecode des shobj wird, wie üblich, mit Singleton::getInstance() auf das Singleton zugegriffen. Die static Variablen des Singletons sind dagegen im Loader definiert.
Nur funktioniert das Ganze leider nicht wie erwartet: Zunächst wird im Loader, in der main() Routine mit Singleton::getInstance() eine neue Instanz erzeugt, was ja ok ist. Aber dann, nach meinem dlopen und dem Aufruf des shobj, wird von diesem eine zweite Instanz erstellt, was ich ja genau nicht will.
Hier nochmal zur Verdeutlichung mein getInstance(), nix besonderes, typisch Singleton eben (die Singleton-Klasse heisst hier "Tracer"):
Tracer *Tracer::getInstance() { if (g_instance == 0) { std::cout << __PRETTY_FUNCTION__ << ", new instance requested, "; g_instance = new Tracer(); } std::cout << __PRETTY_FUNCTION__ << ", instance is: " << g_instance << "\n"; return g_instance; }
Zur Kontrolle hab ich mal die cout Aufrufe reingebastelt, und wie Ihr am __PRETTY_FUNCTION__ seht ist es g++ unter Linux:
ed@summini:~/SBH/prj/Phoenix/cvs8/rpg2cpp/jn/src/app/prototype$ g++ --version g++ (GCC) 4.2.3 (Ubuntu 4.2.3-2ubuntu7)
Ich hab zwer schon öfter shared objects gebastelt, aber noch nie in dieser speziellen Konfiguration. Muss ich da an den Linkeroptionen drehen, oder hab ich im Code noch was zu biegen?
PS: kurz zum Kontext: ich möchte erreichen, dass alle shobj den gleichen Tracer verwenden. Dieser wird in main() konstruiert ( via getInstance() ), und soll dann automatisch alle Traces aller shobj abfackeln.
-
Also ich habs raus, hier nur der Vollständigkeit halber, wenn ein anderer das Problem auch mal hat:
1. Ein Singleton soll in einem shared object verwendet werden
2. da das Singleton statische Globalvariablen benötigt, z.B.:Singleton* Singleton::instance_
... muss man sich überlegen, wo diese definiert (nicht deklariert!) werden. Ich hab das alles so gemacht:
- Singleton Klasse ganz normal deklariert, mit allen static membern (.hpp file)
- Implementierung dieser Klasse wie üblich in *cpp file
- die static Variablen werden in der *cpp Klassenimplementierung nicht instantiiertDamit kann man nun seine shared objects erstellen. Wichtig sind diese Linkerflags (werden beim g++ direkt an den Compiler übergeben, der reicht sie dann an den Linker weiter):
g++ ..... [b]-shared -fPIC -rdynamic[/b]
mit dem -rdynamic flag wird veranlasst, dass das shared object seine Symbole bekannt gibt.
Nun der Loader, also das "main()" Programm.
Hier kommen nun die static Variablen rein, aber man kann das natürlich (wenn man noch mehr solche Dinger hat) auch in eine eigene statische Biliothek packen und mit dieser binden, z.B. eine libGlobalObjects.a oder so. Natürlch kommen diese Variablen nicht in die main() Funktion
sondern irgendwo oben ins Sourcefile, z.B. so:
#include <iostream> #include <dlfcn.h> ... // global 'Tracer' variables (Singleton-pattern) Tracer* Tracer::g_instance = getInstance(); pid_t Tracer::g_pid(getpid()); std::string Tracer::g_facility; std::list<boost::shared_ptr<TracerImpl> > Tracer::g_myTracers; std::list<boost::shared_ptr<TraceEntry> > Tracer::g_pendingEntries; std::map<pthread_t, int> Tracer::g_threadIndent; TraceLine* Tracer::g_traceLine(0); bool Tracer::g_traceWasOpened(false); char Tracer::g_traceChannelMask[TraceChannelMaskLen]; bool Tracer::g_allEnabled = false; int Tracer::g_indent; .... int main() { ... }
Das wird nun ebenfalls ganz normal kompiliert, dieses Mal mit diesen Linker- bzw. Compilerflags:
g++ ... [b]-l dl -rdynamic[/b]
und schon klappts auch mit dem Singleton in "cross shared Objects"
Anmerkung: die Singleton Klasse heisst im obigen Beispiel "Tracer".
Vielleicht hilfts dem einen oder anderen.