2011-08-24 4 views
4

J'ai un programme de niveau utilisateur qui ouvre un fichier en utilisant les indicateurs O_WRONLY|O_SYNC. Le programme crée 256 threads qui tentent d'écrire 256 octets ou plus de données chacun dans le fichier. Je veux avoir un total de 1280000 demandes, soit un total d'environ 300 Mo de données. Le programme se termine une fois que 1280000 demandes ont été complétées.Ecriture simultanée dans un fichier utilisant plusieurs threads

J'utilise pthread_spin_trylock() pour incrémenter une variable qui garde une trace du nombre de demandes terminées. Pour m'assurer que chaque thread écrit dans un offset unique, j'utilise pwrite() et calcule le décalage en fonction du nombre de requêtes qui ont déjà été écrites. Par conséquent, je n'utilise pas de mutex lors de l'écriture dans le fichier (cette approche assure-t-elle l'intégrité des données?)

Lorsque je vérifie la durée moyenne pendant laquelle l'appel pwrite() a été bloqué et les chiffres correspondants (c.-à-d. Q2C fois - qui est la mesure des temps pour le cycle de vie complet de BIO) comme trouvé en utilisant blktrace, je trouve qu'il y a une différence significative. En fait, le temps d'achèvement moyen pour un BIO donné est beaucoup plus élevé que la latence moyenne d'un appel pwrite(). Quelle est la raison de cette divergence? Ces chiffres ne devraient-ils pas être similaires puisque O_SYNC garantit que les données sont effectivement écrites sur le support physique avant de revenir?

Répondre

3

pwrite() est supposé être atomique, donc vous devriez être en sécurité ...

En ce qui concerne la différence de temps de latence entre votre syscall et la BIO réelle, selon ces informations sur le man-pages at kernel.org pour open (2):

POSIX prévoit trois variantes différentes de I synchronisé/O, correspondant aux drapeaux O_SYNC, O_DSYNC et O_RSYNC. Actuellement (2.6.31), Linux seulement implémente O_SYNC, mais glibc mappe O_DSYNC et O_RSYNC au même valeur numérique que O_SYNC. La plupart des systèmes de fichiers Linux ne fait pas mettre en œuvre les POSIX sémantique O_SYNC, qui nécessitent toutes les mises à jour de métadonnées d'une écriture être sur le disque sur le retour à l'espace utilisateur, mais seulement la sémantique O_DSYNC, qui ne nécessitent que données de fichiers réels et les métadonnées nécessaires pour le récupérer sur le disque par l'heure l'appel système revient.

Donc cela implique essentiellement que le drapeau O_SYNC l'ensemble des données que vous essayez d'écrire n'a pas besoin d'être vidées sur le disque avant un rendement syscall, mais l'information plutôt juste assez pour être capable de récupérer partir du disque ... en fonction de ce que vous écrivez, cela pourrait être un peu moins que le tampon entier de données que vous aviez l'intention d'écrire sur le disque, et donc l'écriture de toutes les données aura lieu à un après le syscall a été complété et le processus est passé à autre chose.

+0

J'ai répété la même expérience avec le système de fichiers ext2, qui, contrairement au système de fichiers ext3, n'est pas un système de fichiers de journalisation. La latence moyenne du Q2C s'est avérée être de 8,5 millisecondes. Dans le programme userlevel, la durée moyenne de blocage de l'appel 'pwrite()' est de 1,5 millisecondes. Ces chiffres sont relativement plus proches par rapport à mon expérience précédente; Cependant, ce n'est pas ce que je veux. Comment puis-je rendre l'appel 'pwrite()' _completely_ synchrone, c'est-à-dire que l'appel ne retourne que lorsque le tampon entier des données a été écrit sur le disque? Outils d'analyse comparative de disque doivent avoir une solution de contournement? – user745878

+0

Vous allez probablement devoir utiliser une primitive d'écriture au niveau du noyau inférieure ... par l'implémentation Linux, 'pwrite()' n'est pas complètement synchrone. – Jason

Questions connexes