Le partage global/variable statique entre un processus et DLL
J'aimerais partager statique/variable globale qu'entre un processus et un dll qui est invoquée par le processus. Les exe et dll sont dans le même espace d'adressage mémoire. Je ne veux pas la variable à être partagée par les autres processus.
Élaboration du problème:
Dire qu'il y a un statique/variable globale x
dans a.cpp
. L'exe foo.exe
et la dll bar.dll
ont a.cpp
, de sorte que la variable x
est dans les deux images.
Maintenant, foo.exe
charge dynamiquement (ou statique) bar.dll
. Ensuite, le problème est de savoir si la variable x
est partagée par les exe et dll, ou pas.
Dans Windows, ces deux gars jamais partager la x
: les exe et dll disposerez d'une copie de x
. Cependant, dans Linux, le fichier exe et dll de faire partager la variable x
.
Malheureusement, je veux le comportement de Linux. J'ai d'abord considéré l'utilisation de pragma data_seg
sur Windows. Cependant, même si j'ai correctement le programme d'installation le segment de données partagées, foo.exe
et bar.dll
ne partage jamais le x
. Rappelons que bar.dll
est chargé dans l'espace d'adressage de foo.exe
. Cependant, si je lance une autre instance de foo.exe
, puis x
est partagé. Mais, je ne veux pas x
d'être partagé par les différents processus. Ainsi, l'utilisation de data_seg
a échoué.
J'ai peut-il utiliser un fichier mappé en mémoire par un nom unique entre exe et dll, je vais essayer maintenant.
Deux questions:
- Pourquoi le comportement de Linux et de Windows est-elle différente? Quelqu'un peut-il expliquer cela plus en détail?
- Ce qui serait le plus facile à résoudre ce problème sur Windows?
Vous devez vous connecter pour publier un commentaire.
Tout d'abord, j'ai trouvé que cet article était très intéressant et concis lire sur les bibliothèques de liens dynamiques (l'article n'est spécifique à Linux, mais les concepts sûrement s'appliquent à windows et vous pourriez obtenir quelques éclaircissements sur les différents comportements que vous voyez). Surtout la différence fondamentale entre statique et dynamique de chargement.
Je pense que ce que vous voulez ou tentent de mettre en œuvre est une "croix-module singleton" modèle. Si vous lisez les réponses à ce fil, je ne sais pas comment je pourrais peut-être répondre à votre question mieux que Ben Voigt répondu à ce post. J'ai mis en place un cross-module singleton avant (quelques fois en fait) à l'aide de la méthode qu'il décrit, et il fonctionne comme un charme.
Bien sûr, vous ne serez pas en mesure de retenir les cleaniness d'avoir juste la variable globale s'asseoir là, dans le fichier cpp. Vous devrez utiliser un pointeur statique et certaines fonctions d'accesseur et de comptage de référence. Mais ça peut marcher. Je ne suis pas sûr de savoir comment il serait possible d'éviter que foo.exe et foo.exe partager la même instance de l'un bar.dll je n'ai jamais eu à le faire et ne peut pas vraiment penser à un moyen de le faire, désolé.
Pour obtenir le comportement de linux, où à la fois le programme principal et d'une dll partagent le même
x
, vous pouvez exporter cette variable soit à partir de la dll, ou le programme principal. L'autre module d'importation de cette variable.Vous faites cela en utilisant DEF fichiers (consultez la documentation de microsoft), ou en marquant les utilise avec la variable avec
__declspec(dllexport)
où elle est définie, et__declspec(dllimport)
dans n'importe quel autre module qu'il est utilisé (consultez la documentation de microsoft). C'est le même que la manière dont la fonction, un objet ou une variable est partagé entre les modules windows.Dans le cas où vous souhaitez un programme à charger une bibliothèque au moment de l'exécution, mais le programme principal peut-être utiliser la variable avant de la bibliothèque est chargé, le programme devrait exporter la variable, et la dll doit importer. Il y a un peu de la poule et de l'œuf problème ici parce que la dll dépend du programme principal et le principal du programme dépend de la dll. Voir http://www.lurklurk.org/linkers/linkers.html#wincircular
J'ai écrit un exemple de comment vous pouvez le faire en utilisant à la fois Microsoft et d'un compilateur mingw gcc sous windows), y compris toutes les différentes façons dont un programme et d'une bibliothèque pouvez lier les uns aux autres (de manière statique, dll chargée au démarrage du programme, dll chargés de cours de l'exécution)
principal.h
principal.c
dll.h
dll.c
dyn_link.h
dyn_link.c
linkage_importing.h
linkage_exporting.h
construire mingw explicite both.sh
construire mingw explicite dll.sh
construire mingw explicite main.sh
construire mingw implicit.sh
construire mingw static.sh
construire msvc à la fois explicite.chauve-souris
construire msvc explicite dll.chauve-souris
construire msvc explicite principal.chauve-souris
construire msvc implicite.chauve-souris
construire msvc statique.chauve-souris
Si foo.exe charge toujours bar.dll ensuite, vous pouvez mettre en œuvre la variable dans bar.dll et de les exporter. Par exemple, certains fichiers b.cpp compilé seulement dans bar.dll, pas dans foo.exe:
Puis de l'importer dans un fichier source c.cpp compilé dans foo.exe:
Cependant, si parfois foo.exe ne charge pas bar.dll alors cela ne fonctionnera pas. Aussi, je suis en train d'écrire ce à partir de la mémoire et donc il y aura peut être quelques erreurs de syntaxe, mais j'espère que c'est assez pour vous diriger dans la bonne direction.
Je ne peux pas répondre pourquoi il est différent de Linux.
J'ai trouvé ceci pour être une question intéressante à laquelle j'ai pris le temps d'écrire un tutoriel complet sur la façon d'utiliser DLL pour partager des données entre plusieurs Dll (que ce soit implicitement ou explicitement lié) mais aussi s'assurer que les données ne sont pas partagées entre les processus distincts d'un même fichier exécutable.
Vous pouvez trouver l'article complet ici: http://3dgep.com/?p=1759
Une solution à ce problème que j'ai trouvé très bien fonctionner est de créer un "commun" ou "partagé" dll qui définit toutes les données et les méthodes que vous souhaitez partager à travers de multiples DLL (mais pas partagées entre les processus).
Supposons que vous souhaitez définir une classe singleton qui peut être accessible par le code de l'application principale (EXE), mais vous aussi vous voulez accéder à l'instance du singleton en commun (implicitement ou explicitement lié DLL). Tout d'abord, vous devez déclarer la classe singleton dans le "commun" DLL:
Lors de la compilation de la CommonDLL projet, vous devez exporter la classe declaratoin par la décoration de la classe avec
__declspec(dllexport)
et quand vous êtes à l'aide de la DLL (dans l'application, par exemple), la définition de la classe doit être importé par la décoration de la classe avec__declspec(dllimport)
.Lors de l'exportation d'une classe par la décoration de la classe, avec l'
__declspec(dllexport)
prescripteur, toutes les méthodes de la classe et de données (même privés) sont exportées à partir de la DLL et utilisable par n'importe quelle DLL ou EXE qui, implicitement, des liens vers la commune de la DLL.La définition de la MySingleton classe pourrait ressembler à quelque chose comme ceci:
Lors de la compilation de la commune de dll, deux fichiers seront produits:
Si vous lien vous demande à l'encontre de la exporté LIB fichier, le fichier DLL sont implicitement liés à l'exécution (tant que le fichier DLL est trouvé dans la DLL chemins de recherche) et vous aurez accès à l'singleton définis dans le CommonDLL.DLL fichier.
Aussi, toute bibliothèque partagée (plugins, par exemple) qui relie également à l'encontre de la CommonDLL.Fichier LIB auront accès à la même singleton cas lorsque chargé dynamiquement par l'application.
Pour une explication complète de cette solution, y compris un exemple de code source, consultez la suite de l'article que j'ai posté intitulée "Utilisation des Bibliothèques de liens Dynamiques (DLL) pour Créer des Plugins":
http://3dgep.com/?p=1759
La différence entre la GCC et de et de Visual Studio que sur Linux, il autorise implicitement le code pour voir les symboles des autres, liée de façon dynamique (en commun) dans les bibliothèques, sans vous, le programmeur d'avoir à faire quelque chose de spécial. Tous les symboles sont disponibles dans les parties communes (liée de façon dynamique) de la bibliothèque de l'éditeur de liens dynamique pour résoudre lorsque le programme s'exécute. Sur Windows, vous devez expressément exporter le symbole de la DLL, et aussi explicitement l'importer dans le programme ou bibliothèque de l'utiliser. (Généralement, cela se fait via une macro (#define) qui s'étend d'avoir la dllexport la déclaration dans un fichier d'en-tête lors de la construction de la dll elle-même, mais lorsque le fichier d'en-tête est inclus par un autre programme à l'aide de la dll, il s'élargit pour avoir le dllimport déclaration à la place. À mon avis, c'est une douleur dans le cou, et le comportement de GCC est plus facile, puisque vous n'avez pas à faire quelque chose de spécial pour obtenir le comportement que vous voulez généralement.
Sur la nouvelle version de GCC, vous pouvez définir la valeur par défaut pour masquer les symboles lors de la construction d'une dynamique (partagé) de la bibliothèque, si vous voulez.
Merci pour la prestation de divers solution sur ce point. j'ai regardé ces options et a décidé de mettre en œuvre la croix module de singleton à l'aide de la Mémoire Partagée et il a bien fonctionné pour moi aussi.
j'ai utilisé Qt QSharedMemory à la réalisation de mes tâches, mais le prototype que j'ai écrit à l'aide de la Win32 CreateFileMapping & etc.
Si je comprends votre question correctement, vous êtes la liaison statique a.cpp en foo.exe et bar.dll de sorte que vous obtenez de 2 instances de x.
Si vous avez créé un troisième dll (dire a.dll), et vous lier dynamiquement foo.exe et bar.dll pour a.dll, vous obtiendrez le comportement que vous désirez:
a.dll est chargé et ne charge pas il
encore une fois, ils partagent x.
sa propre x.
J'ai vu beaucoup de réponses à cette question et comme il est un peu difficile et incertaine, je tiens à apporter le scénario suivant.
Nous voulons partager une variable globale entre une DLL et un programme principal, et permettent également l'accès à cette variable à partir de différents modules dans la DLL et dans le programme principal.
La variable est une valeur BOOLÉENNE indiquant si le programme devrait continuer à fonctionner ou s'arrêter. Le nom de la variable est ShouldRun;
Dans le programme principal, nous avons besoin de mettre:
Dans le DLL module principal nous avons besoin de mettre:
Dans n'importe quel autre module à l'intérieur de la DLL projet, nous allons utiliser: