-
Partage d'un singleton
Bonjour à tous
Le contexte de mon problème est le suivant :
- je développe en C++ sous Visual Studio 2008
- ma solution implique plusieurs bibliothèques statiques (.lib) et un nombre limité de bibliothèques dynamiques (.dll) qui se contentent d'exposer des fonction définies dans les (.lib)
- je définis des singletons dans mes .lib qui sont utilisés employés par les fonctions exposées dans mes .dll
- l'application qui sert à l'exploitation est réalisée en C# et appelle les fonctions en [DllImport]
- mon code compile et s'exécute en debug
- mon code compile en release mais à chaque référence au singleton, une erreur de type "Violation de mémoire" se produit.
Can anyone help ?
-
Bonjour,
- Si tes singletons sont dans des .lib, tu en as un exemplaire par DLL utilisant la lib, en es-tu bien conscient?
- Essaie de tester tes DLLs depuis un programme natif, avant de tenter de les tester en .Net.
- Tu peux aussi faire tes DLLs en C++/CLI, pour les lier directement aux assemblys C# au lieu de passer par P/Invoke...
-
Pour un singleton garanti multi-processus / multi-exécutables (ce qui est le cas avec les DLL), tu n'as guère d'autre choix que de l'instancier dans une mémoire partagée...
Pour ceci, tu effectues les opérations suivantes pour le premier processus :- Création de la mémoire partagée et du singleton.
- Copie du singleton vers la mémoire partagée.
- Destruction du singleton (la copie en mémoire partagée reste).
- Assignation de l'adresse du singleton à celle de l'objet en mémoire partagée.
Pour les suivants, il te suffit d'aller chercher l'adresse du singleton en mémoire partagée. Tu sais que le singleton est initialisé par le simple fait que la mémoire partagée existe. Un mutex nommé (=global au système) protègera la demande d'instance du singleton, afin d'être tranquille sur la réentrance à ce niveau.
Bien sûr, il te faut protéger ton singleton contre les accès multi-processus, ce qui requiert souvent de stocker une section critique dans la mémoire partagée elle-même, dans ton cas en attribut de la classe singleton par exemple.
Ta classe ne doit bien sûr avoir aucun attribut de type "pointeur", sinon ça va exploser... Et ceci y compris en pointeur sur la mémoire partagée, car tu ne peux pas garantir qu'elle sera mappée à la même adresse dans tous les processus utilisateurs. Au mieux, tu peux utiliser des offsets dans cette mémoire partagée (par rapport à la classe singleton) et/ou des stockages TLS, si vraiment c'est nécessaire.
Si tu es process-safe, normalement, tu ne devrais plus avoir le moindre souci d'accès à ton singleton même au travers de C#, il suffira d'appeler au moins une fois la demande d'instance depuis C# pour être certain d'avoir une copie valide du singleton pour ton processus managé.