2009-04-12 11 views
4

J'essaie de permettre à deux processus différents de communiquer en utilisant le mappage mémoire du même fichier. Cependant, j'ai quelques problèmes avec cela. J'ai un sentiment que cela a à voir avec la façon dont j'utilise l'appel open() et en passant mon descripteur de fichier à mmap.Utilisation de mmap sur un fichier

Voici mon code, pouvez-vous voir quelque chose de mal à ce sujet?

objet 1 Code de:

16  FILE* temp = fopen(theSharedFileName, "w"); 
17  fseek(temp, fileSize-1, SEEK_SET); 
18  fprintf(temp, "0"); // make the file a certain size 
19  fseek(temp, 0, SEEK_CUR); 
20 
21  int sharedFileName = fileno(temp); 
... 
31  sharedArea = (MyStruct*)mmap(0, fileSize, 
32   PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, sharedFileName, 0); 

J'utilise le mode fichier « w » depuis l'objet 1 ne jamais être fait une fois et je le veux pour réinitialiser toutes les données existantes.

Code objet de 2:

130  FILE* tempFile = fopen(sharedFileName, "a"); 
131  int theFile = fileno(tempFile); 
... 
135  sharedArea = (MyStruct*)mmap(NULL, fileSize, 
136   PROT_READ | PROT_WRITE | PROT_EXEC, MAP_SHARED, theFile, 0); 
+0

À quels problèmes précis faites-vous face? Pouvez-vous garantir que obj2 n'accèdera jamais au fichier avant que obj1 ne le fasse? – dirkgently

+0

Oui, obj1 est plus un serveur et obj2 est comme un client qui sera démarré plus tard. – samoz

Répondre

24

Quelques questions:

  1. Evitez de mélanger de haut niveau I/O (fopen(), fseek()) et une opération de faible niveau mmap(). Bien que vous puissiez obtenir le descripteur de fichier de bas niveau en utilisant fileno(), c'est comme prendre le chemin le plus long pour arriver au même endroit. En outre, l'utilisation de mmap() rompt la compatibilité au-delà de BSD et POSIX, de sorte que vous n'obtenez rien en utilisant les fonctions d'E/S C standard. Utilisez simplement open() et lseek() directement.
  2. Cela n'a aucun sens d'utiliser des E/S formatées en flux (fprintf()) sur le même fichier que vous mappez en mémoire. Lorsque vous mappez un fichier en mémoire, vous indiquez implicitement au système que vous allez l'utiliser en tant que données à accès aléatoire (indexation directe). fprintf() est pour la sortie de flux, vous l'utilisez généralement pour un accès séquentiel. En fait, bien que possible, il est inhabituel de voir fprintf() et fseek() dans le même descripteur (ce n'est même pas portable, mais en raison de l'élément précédent, je ne considère pas la portabilité).
  3. La protection doit correspondre à la protection de fichier ouverte. Puisque vous passez "w" à fopen(), et PROT_READ | PROT_WRITE | PROT_EXEC à mmap(), vous violez cette restriction. Cela souligne également pourquoi vous ne devez pas mélanger les E/S de haut niveau avec le mappage de la mémoire: comment garantissez-vous que fopen(...,"w") ouvrira le fichier avec les bons indicateurs? Ceci est censé être "implémentation-detail" pour la bibliothèque C. Si vous souhaitez mapper un fichier avec des autorisations de lecture et d'écriture, vous devez utiliser le de bas niveau pour ouvrir le fichier.
  4. Ne pas utiliser PROT_WRITE et PROT_EXEC ensemble. Ce n'est pas portable et c'est un risque de sécurité. Lire à propos de W^X et executable space protection.
+0

Réponse très complète. – Anthony

+1

Une partie de cette réponse semble être de la désinformation. Je suis confus pourquoi vous pensez que 'fprintf' et' fseek' ne peuvent pas être utilisés ensemble de façon portative. Et comme pour les modes # 3 et fichiers, POSIX spécifie très explicitement comment les chaînes de mode 'fopen' se traduisent en modes de descripteur de fichier; Ce n'est pas spécifique à la mise en œuvre. –

1

Comme d'autres l'ont dit, n'utilisez pas fopen() et vos amis pour cela. Une partie du problème que vous rencontrez peut être dû au fait que fprintf() peut avoir des tampons de flux, donc il ne peut pas réellement changer le fichier, et donc être visible à l'autre processus lorsque cela est attendu. Vous pouvez ajouter un fflush(), mais read() et write() ne font pas de buffering au niveau de l'application, ce qui explique en partie pourquoi ils sont plus appropriés.

2

Si vous pouvez utiliser C++ et des bibliothèques comme ACE ou Boost qui vous protègent des détails de niveau inférieur et fournissent une abstraction plus facile pour IPC.