web-dev-qa-db-fra.com

Peut-on utiliser plusieurs processus pour écrire dans le même fichier en même temps? [CentOs 6, ext4]

Je construis un système où plusieurs processus esclaves communiquent via des sockets de domaine Unix et ils écrivent dans le même fichier en même temps. Je n'ai jamais étudié les systèmes de fichiers ou ce système de fichiers spécifique (ext4), mais il semble qu'il puisse y avoir un danger ici.

Chaque processus écrit dans un sous-ensemble disjoint du fichier de sortie (c'est-à-dire qu'il n'y a pas de chevauchement dans les blocs en cours d'écriture). Par exemple, P1 n'écrit que dans les premiers 50% du fichier et P2 écrit uniquement sur les 50% restants. Ou peut-être P1 écrit uniquement les blocs impairs tandis que P2 écrit les blocs pairs.

Est-il sûr d'avoir P1 et P2 (s'exécutant simultanément sur des threads séparés) écrivant dans le même fichier sans utiliser de verrouillage? En d'autres termes, le système de fichiers impose-t-il implicitement une sorte de verrouillage?

Note: Je ne suis malheureusement pas libre de sortir plusieurs fichiers et de les rejoindre plus tard.

Remarque: Ma lecture depuis la publication de cette question n'est pas d'accord avec la seule réponse publiée ci-dessous. Tout ce que j'ai lu suggère que ce que je veux faire est bien, alors que le répondant ci-dessous insiste sur le fait que ce que je fais n'est pas sûr, mais je ne peux pas discerner le danger décrit.

45
Fixee

Ce que vous faites semble parfaitement correct, à condition que vous utilisiez les syscalls POSIX "raw" IO tels que read (), write (), lseek () et ainsi de suite.

Si vous utilisez C stdio (fread (), fwrite () et friends) ou une autre bibliothèque d'exécution de langage qui a sa propre mise en mémoire tampon de l'espace utilisateur, la réponse de "Tilo" est pertinente, en ce que, en raison de la mise en mémoire tampon, qui est pour certains dans une mesure hors de votre contrôle, les différents processus peuvent se remplacer mutuellement.

Verrouillage du système d'exploitation Wrt, alors que POSIX indique que les écritures ou les lectures inférieures à la taille PIPE_BUF sont atomiques pour certains fichiers spéciaux (canaux et FIFO), il n'y a pas de telle garantie pour les fichiers normaux. En pratique, je pense qu'il est probable que les E/S dans une page soient atomiques, mais il n'y a pas de telle garantie. Le système d'exploitation ne verrouille en interne que dans la mesure nécessaire pour protéger ses propres structures de données internes. On peut utiliser des verrous de fichiers ou un autre mécanisme de communication interprocessus pour sérialiser l'accès aux fichiers. Mais, tout cela n'est pertinent que si vous avez plusieurs processus faisant IO dans la même région d'un fichier. Dans votre cas, comme vos processus le font IO pour dissocier des sections du fichier, rien de tout cela n'a d'importance, et ça devrait aller.

26
janneb

non, ce n'est généralement pas sûr de le faire!

vous devez obtenir un verrou d'écriture exclusif pour chaque processus - ce qui implique que tous les autres processus devront attendre pendant qu'un processus écrit dans le fichier. plus vous avez de processus gourmands en E/S, plus le temps d'attente est long.

il est préférable d'avoir un fichier de sortie par processus et de formater ces fichiers avec un horodatage et un identificateur de processus au début de la ligne, afin que vous puissiez plus tard fusionner et trier ces fichiers de sortie hors ligne.

Astuce: vérifiez le format de fichier des fichiers journaux du serveur Web - ceux-ci sont effectués avec l'horodatage au début de la ligne, afin qu'ils puissent être combinés et triés ultérieurement.


MODIFIER

Les processus UNIX utilisent une certaine taille de tampon/fixe lorsqu'ils ouvrent des fichiers (par exemple 4096 octets), pour transférer des données vers et depuis le fichier sur le disque. Une fois que le tampon d'écriture est plein, le processus le vide sur le disque - cela signifie: il écrit le tampon complet complet sur le disque! Veuillez noter ici que cela se produit lorsque le tampon est plein! - pas quand il y a une fin de ligne! Cela signifie que même pour un seul processus qui écrit des données texte orientées ligne dans un fichier, ces lignes sont généralement coupées quelque part au milieu au moment où le tampon est vidé. Ce n'est qu'à la fin, lorsque le fichier est fermé après l'écriture, que vous pouvez supposer que le fichier contient des lignes complètes!

Ainsi, selon le moment où votre processus décide de vider leurs tampons, ils écrivent à différents moments dans le fichier - par exemple l'ordre n'est pas déterministe/prévisible Lorsqu'un tampon est vidé dans un fichier, vous ne pouvez pas supposer qu'il n'écrira que des lignes complètes - par ex. il écrit généralement des lignes partielles , gâchant ainsi la sortie si plusieurs processus vident leurs tampons sans synchronisation.

Consultez cet article sur Wikipedia: http://en.wikipedia.org/wiki/File_locking#File_locking_in_UNIX

Citation:

Les systèmes d'exploitation Unix (y compris Linux et Mac OS X d'Apple, parfois appelé Darwin) ne se verrouillent normalement pas automatiquement fichiers ou programmes en cours d'exécution. Plusieurs types de mécanismes de verrouillage de fichiers sont disponibles dans différentes versions d'Unix, et de nombreux systèmes d'exploitation prennent en charge plusieurs types de compatibilité. Les deux mécanismes les plus courants sont fcntl (2) et flock (2). Un troisième mécanisme de ce type est lockf (3), qui peut être séparé ou peut être mis en œuvre en utilisant l'une des deux premières primitives.

Vous devez utiliser soit flock, soit Mutexes pour synchroniser les processus et vous assurer qu'un seul d'entre eux peut écrire dans le fichier à la fois.

Comme je l'ai mentionné précédemment, il est probablement plus rapide, plus facile et plus simple d'avoir un fichier de sortie pour chaque processus, puis de combiner ces fichiers si nécessaire (hors ligne). Cette approche est utilisée par certains serveurs Web par exemple, qui doivent se connecter à plusieurs fichiers à partir de plusieurs threads - et doivent s'assurer que les différents threads sont tous très performants (par exemple, ne pas avoir à attendre sur un verrou de fichier).


Voici un article connexe: (Cochez la réponse de Byer! La réponse acceptée n'est pas correcte/pertinente.)

Est-il sûr de diriger la sortie de plusieurs processus parallèles vers un fichier en utilisant >>?


EDIT 2:

dans le commentaire, vous avez dit que vous vouliez écrire des blocs de données binaires de taille fixe des différents processus dans le même fichier.

Ce n'est que dans le cas où la taille de votre bloc est exactement la taille de la taille du tampon de fichiers du système, que cela peut fonctionner!

Assurez-vous que la longueur de bloc fixe correspond exactement à la taille de la mémoire tampon du système . Sinon, vous vous retrouverez dans la même situation qu'avec les lignes non terminées. par exemple. si vous utilisez des blocs de 16k et que le système utilise des blocs de 4k, alors en général vous verrez 4k blocs dans le fichier dans un ordre apparemment aléatoire - il n'y a aucune garantie que vous verrez toujours 4 blocs d'affilée du même processus

24
Tilo