IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Linux Discussion :

mémoire partagée en C sous systèmes Unix


Sujet :

Linux

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 45
    Par défaut mémoire partagée en C sous systèmes Unix
    Bonjour,

    Voici mon problème (qui n'est pas vraiment un problème mais plutôt un choix de conception).

    J'ai deux processus tournant sur une même machine. Ces deux processus n'ont pas de lien de parenté a priori (l'un n'est pas issue d'un fork de l'autre).
    Je dois ouvrir un segment de mémoire partagée entre ces deux processus.

    La technique habituelle est la suivante :

    Dans le premier processus:
    1) créer une clef k avec la fonction ftok() en lui donnant en paramètre un nom de fichier et un identifiant de projet.
    2) à partir de la clef k, créer un segment de mémoire partagé identifié par l'entier id (shmget)
    3) à partir de l'id, récupérer le pointeur sur cette mémoire (shmat)

    Dans le second processus:
    1) créer la clef k avec la fonction ftok en utilisant les mêmes arguments que dans le premier processus, on récupère ainsi la même clef.
    2) à partir de k, récupérer l'id du segment de donnée (shmget)
    3) à partir de l'id, récupérer le pointeur

    Même si c'est la manière classique et habituelle de procéder, ce genre de génération de clef ne me plait pas, de plus je rencontre des problèmes de permissions d'accès au segment de mémoire lorsque je ne lances pas les processus en root.

    J'ai donc fait la chose suivante :

    Dans le premier processus:
    1) utilise IPC_PRIVATE comme clef lors de la création du segment. Je récupère un id.
    2) créer le segment de mémoire à partir de cet id, comme précédemment.
    3) envoyer l'id au second processus (les deux processus sont des jobs MPI tournant sur la même machine, je peux le faire très simplement en utilisant MPI_Send et MPI_Recv).

    Dans le second processus:
    1) attendre (MPI_Recv) que le premier processus envoie l'id
    2) récupérer (shmget) un pointeur sur le segment à partir de cet id.

    Avec cette solution, pas de problème de permission, ni de génération de clefs utilisant un nom de fichier et un identifiant de projet.
    Cela fonctionne.

    Ma question : ... est-ce propre ? Est-ce que ça fonctionnera toujours ou est-ce que c'est un coup de bol du à certains paramètres cachés ?

    Merci !

  2. #2
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sunmat Voir le message
    Même si c'est la manière classique et habituelle de procéder, ce genre de génération de clef ne me plait pas
    Et pourquoi ?
    Personnellement, si deux programmes doivent taper dans la même ipc, j'utilise l'astuce suivante: ftok(".", getuid())
    Après-tout, "." est aussi un fichier !!! Ainsi, comme généralement l'utilisateur appelle les deux programmes à partir du même répertoire de départ et que les deux programmes sont lancés par le même uid, la clef générée sera forcément commune aux deux ; mais différente d'un autre utilisateur qui appèlerait lui-aussi les deux programmes
    Juste un détail: si le uid est root, ftok() n'apprécie pas du tout son second paramètre à 0. Donc ma vraie syntaxe est
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    ftok(".", (getuid() & 0xff) != 0 ?getuid() :-1)

    Citation Envoyé par sunmat Voir le message
    , de plus je rencontre des problèmes de permissions d'accès au segment de mémoire lorsque je ne lances pas les processus en root.
    Là ça devient bizarre. Faudrait vérifier tes paramètres shmget() et surtout la présence des flags SHM_R et/ou SHM_W

    Citation Envoyé par sunmat Voir le message
    J'ai donc fait la chose suivante :

    Dans le premier processus:
    1) utilise IPC_PRIVATE comme clef lors de la création du segment. Je récupère un id.
    2) créer le segment de mémoire à partir de cet id, comme précédemment.
    3) envoyer l'id au second processus (les deux processus sont des jobs MPI tournant sur la même machine, je peux le faire très simplement en utilisant MPI_Send et MPI_Recv).

    Dans le second processus:
    1) attendre (MPI_Recv) que le premier processus envoie l'id
    2) récupérer (shmget) un pointeur sur le segment à partir de cet id.

    Avec cette solution, pas de problème de permission, ni de génération de clefs utilisant un nom de fichier et un identifiant de projet.
    Cela fonctionne.

    Ma question : ... est-ce propre ? Est-ce que ça fonctionnera toujours ou est-ce que c'est un coup de bol du à certains paramètres cachés ?

    Merci !
    J'avais déjà fait ça aussi. Aller taper dans des IPC en utilisant leur id. Effectivement ça marche. Mais bon, si la norme précise de passer par shmget() en y donnant une clef de base, c'est qu'il y a une raison. Malheureusement je ne peux pas répondre plus précisément à tes questions.

    Cependant, à mon avis, tu devrais quand-même te concentrer sur ftok(). Cette fonction est pas mal foutue et si elle a été créée, ce n'est pas sans une bonne raison...
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 45
    Par défaut
    Merci !

    Le problème de générer des clefs avec ftok() est que je dois utiliser des fichiers ou des identifiants de projets à chaque fois que je veux en créer une nouvelle. Or mon application est fortement multi-processus, et chaque processus va éventuellement ouvrir plusieurs segments avec d'autres processus. Je dois m'assurer de créer de nouvelles clefs à chaque fois, donc je ne peux pas me permettre d'utiliser toujours "." comme nom de fichier. Si je joue sur l'identifiant de projet, je n'ai que 256 clefs possibles, c'est pas énorme...

    Pour les permissions, je n'ai pas les flags SHM_R et SHM_W, j'ai utilisé IPC_CREAT et IPC_EXCL. L'erreur vient peut-être de là...

    Bon, pour le moment ma seconde solution fonctionne. S'il s'avère qu'il y a des problèmes dépendants de la plateforme, ce ne sera que quelques lignes à changer...

  4. #4
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sunmat Voir le message
    Merci !

    Le problème de générer des clefs avec ftok() est que je dois utiliser des fichiers ou des identifiants de projets à chaque fois que je veux en créer une nouvelle. Or mon application est fortement multi-processus, et chaque processus va éventuellement ouvrir plusieurs segments avec d'autres processus. Je dois m'assurer de créer de nouvelles clefs à chaque fois, donc je ne peux pas me permettre d'utiliser toujours "." comme nom de fichier. Si je joue sur l'identifiant de projet, je n'ai que 256 clefs possibles, c'est pas énorme...
    Pourquoi "plusieurs segments" ? Qu'est-ce qui t'empêche de n'en ouvrir qu'un seul bien gros et le mapper comme il faut pour que tes processus ne tapent que dans la partie qui leur est allouée ???

    Citation Envoyé par sunmat Voir le message
    Pour les permissions, je n'ai pas les flags SHM_R et SHM_W, j'ai utilisé IPC_CREAT et IPC_EXCL. L'erreur vient peut-être de là...
    Les flags SHM_R et SHM_W sont issus d'Unix. Il est possible qu'ils n'existent plus sous Linux. Mais si tu fais un man de shmget(), tu verras que le second paramètre "shmflg" est un entier composé d'un mixage entre:
    - IPC_CREAT et IPC_EXCL (commun à toutes les fonctions xxxget())
    - mode d'accès => valeur numérique octale identique à celle du chmod (sauf que le droit "x" n'est pas pris en compte). Tu peux la mettre en octal comme 0666 ou bien lui mettre des constantes standard comme S_IRUSR | S_IWUSR | S_IRGRP | ...

    Donc si tu fais un truc ressemblant à
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    shm=shmget(key, IPC_CREAT|IPC_EXCL|0660)
    tu ne devrais plus avoir de problème de droits d'accès...

    Tu peux télécharger mon cours sur les IPC ici http://fr.lang.free.fr/cours/IPC_Csyst_v1.0.pdf
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    45
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 45
    Par défaut
    J'avais utilisé 0666 et non 0660, donc ça aurais du fonctionner aussi...

    Pourquoi "plusieurs segments" ? Qu'est-ce qui t'empêche de n'en ouvrir qu'un seul bien gros et le mapper comme il faut pour que tes processus ne tapent que dans la partie qui leur est allouée ???
    C'est une idée, en effet, à "petites" échelles, car le second argument de shmget est un entier 32bits pour la taille, or mon code devrait tourner avec une RAM de 128Go, sur laquelle je devrais ouvrir plusieurs Go de mémoire partagée. Pris individuellement, la taille des segments peut être décrite sur un entier 32bits. Mis bouts à bout, c'est impossible.

    Les flags SHM_R et SHM_W sont issus d'Unix. Il est possible qu'ils n'existent plus sous Linux.
    Mon code n'est même pas censé tourner sur un Linux simple, mais sur un supercalculateur d'IBM , je ne sais même pas quel système d'exploitation sera lancé dessus, donc je dois faire le plus général possible (au vu des autres bibliothèques utilisées ça doit quand même être issue d'Unix).

    En tout cas merci pour ton aide !

    EDIT: à non en fait shmget prend un argument de type size_t, donc je peux supposer que sur les systèmes d'exploitation orientés HPC ils auront mis size_t = uint64_t ou équivalent. Mais ça ne règle pas un autre problème : pour les sémaphores aussi il faut générer une clef, or je ne sais pas à l'avance combien de processus seront lancés ni combien de segments ils voudront ouvrir. Je ne sais donc pas a priori combien de sémaphores créer, je dois les créer à la demande des processus, ce qui ne fait que déplacer le problème de la mémoire partagée aux sémaphores.

  6. #6
    Membre prolifique
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 835
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 835
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par sunmat Voir le message
    J'avais utilisé 0666 et non 0660, donc ça aurais du fonctionner aussi...
    Exact. Donc c'est un problème à creuser réellement et non prendre la solution de facilité de faire tourner le processus en tant que root.
    Peut-être que tu pourrais faire partager ton code sauf si c'est confidentiel.

    Citation Envoyé par sunmat Voir le message
    C'est une idée, en effet, à "petites" échelles, car le second argument de shmget est un entier 32bits pour la taille, or mon code devrait tourner avec une RAM de 128Go, sur laquelle je devrais ouvrir plusieurs Go de mémoire partagée. Pris individuellement, la taille des segments peut être décrite sur un entier 32bits. Mis bouts à bout, c'est impossible.
    Arf. Peut-etre que tu devrais nous donner les conditions initiales de ton truc afin qu'on ait le plus de billes pour te conseiller au mieux. En l'état, j'imagine mal un projet devant utiliser plusieurs Go de mémoire parce qu'il y a de grandes chances que tu fasses exploser ta RAM. Parce que, que ce soit en une fois ou en plein de petits bouts, la RAM utilisée, elle, reste la même => c'est la somme cumulée de touts les petits bouts !!!
    Donc si ton projet nécessite une grande quantité de datas à gérer, vaudrait mieux t'orienter vers des outils appropriés pour ça => les fichiers ou mieux, les bdd

    Citation Envoyé par sunmat Voir le message
    EDIT: à non en fait shmget prend un argument de type size_t, donc je peux supposer que sur les systèmes d'exploitation orientés HPC ils auront mis size_t = uint64_t ou équivalent. Mais ça ne règle pas un autre problème : pour les sémaphores aussi il faut générer une clef, or je ne sais pas à l'avance combien de processus seront lancés ni combien de segments ils voudront ouvrir. Je ne sais donc pas a priori combien de sémaphores créer, je dois les créer à la demande des processus, ce qui ne fait que déplacer le problème de la mémoire partagée aux sémaphores.
    Attention, un sémaphore n'est jamais associé à un processus mais à une ressource. Il protège la ressource unique face à un accès concurrent de 2, 3 ou 300 processus.
    Donc en fait, t'auras autant de sémaphores que de zones de ta mémoire attaquées.

    Citation Envoyé par sunmat Voir le message
    Mon code n'est même pas censé tourner sur un Linux simple, mais sur un supercalculateur d'IBM , je ne sais même pas quel système d'exploitation sera lancé dessus, donc je dois faire le plus général possible (au vu des autres bibliothèques utilisées ça doit quand même être issue d'Unix).
    Heureusement que c'est de la famille Unix parce que les IPC ne sont pas connues du coté obscur de la force...

    Citation Envoyé par sunmat Voir le message
    En tout cas merci pour ton aide !
    Pas de pb.
    Mon Tutoriel sur la programmation «Python»
    Mon Tutoriel sur la programmation «Shell»
    Sinon il y en a pleins d'autres. N'oubliez pas non plus les différentes faq disponibles sur ce site
    Et on poste ses codes entre balises [code] et [/code]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 0
    Dernier message: 18/02/2010, 08h45
  2. Utilisation simple d'une mémoire partagée sous linux
    Par dreamteam dans le forum Linux
    Réponses: 1
    Dernier message: 09/02/2007, 17h39
  3. Réponses: 17
    Dernier message: 02/02/2006, 12h03
  4. Partage de fichier sous Win9x : 87-Paramètre incorrect
    Par Benjamin GAGNEUX dans le forum Web & réseau
    Réponses: 6
    Dernier message: 14/08/2004, 14h10
  5. [CR][paradox] mémoire partagée disponible insuffisante !
    Par AGT dans le forum SAP Crystal Reports
    Réponses: 2
    Dernier message: 24/03/2004, 14h27

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo