Que se passe-t-il si un appel système d’écriture est appelé sur le même fichier par 2 processus différents simultanément

Le système d’exploitation le gère-t-il correctement?

Ou devrais-je appeler flock ()?

Bien que le système d’exploitation ne se bloque pas et que le système de fichiers ne soit pas corrompu, les appels à write() NE SONT PAS garantis comme étant atomiques, à moins que le descripteur de fichier en question ne soit un canal et que la quantité de données à écrire ne soit pas PIPE_MAX ou moins. La partie pertinente de la norme :

Une tentative d’écriture sur un tube ou une FIFO présente plusieurs caractéristiques principales:

  • Atomique / non atomique: Une écriture est atomique si la totalité de la quantité écrite en une opération n’est pas entrelacée avec les données d’un autre processus. Ceci est utile lorsque plusieurs rédacteurs envoient des données à un seul lecteur. Les applications ont besoin de savoir quelle taille une demande d’écriture peut être effectuée de manière atomique. Ce maximum s’appelle {PIPE_BUF}. Ce volume de la norme IEEE 1003.1-2001 n’indique pas si les demandes d’écriture de plus de {PIPE_BUF} octets sont atomiques, mais nécessite que les écritures de {PIPE_BUF} ou moins soient atomiques.

[…]

En tant que tel, vous devez en principe vous verrouiller avec des rédacteurs simultanés, sinon vos données écrites risquent d’être mélangées et hors d’ordre (même au sein de la même écriture) ou plusieurs écritures se écrasant. Cependant, il existe une exception – si vous passez O_APPEND , vos écritures seront effectivement atomiques:

Si l’indicateur O_APPEND des indicateurs d’état du fichier est défini, l’offset de fichier doit être défini à la fin du fichier avant chaque écriture et aucune opération de modification de fichier ne doit intervenir entre la modification de l’offset de fichier et l’opération d’écriture.

Bien que cela ne soit pas nécessairement atomique en ce qui concerne les O_APPEND non O_APPEND ou les lectures simultanées, si tous les rédacteurs utilisent O_APPEND et que vous synchronisez d’une manière ou d’une autre avant de faire une read , tout devrait bien se passer.

write (et write aussi) garantit l’atomicité.

Ce qui signifie que si deux threads ou processus écrivent simultanément, vous n’avez pas de garantie que l’on écrit en premier. Mais vous avez la garantie que tout ce qui est dans un appel système ne sera pas mêlé aux données de l’autre.

Dans la mesure où cela fonctionnera toujours correctement , mais pas nécessairement comme vous le souhaitez (si vous supposez que le processus A vient avant le processus B).

Bien sûr, le kernel le gérera correctement, conformément à sa conception de l’exactitude – qui est par définition correcte.

Si vous avez un ensemble de flockers coordonnés, vous pouvez utiliser le kernel pour mettre tout le monde en queue. Mais rappelez-vous que le troupeau n’a rien à voir avec les E / S: cela n’empêchera pas quelqu’un d’autre d’écrire le fichier. Au mieux, cela n’interférera qu’avec les autres flockers.

Oui bien sûr cela fonctionnera correctement. Cela ne plantera pas le système d’exploitation ou le processus.

Que cela ait un sens ou non dépend de la manière dont les applications sont écrites et du but du fichier.

Si le fichier est ouvert par tous les processus en tant qu’add-only, chaque processus effectue (théoriquement) une recherche atomique à la fin avant chaque écriture; ils sont garantis de ne pas écraser les données des autres (mais l’ordre est non déterministe bien sûr).

Dans tous les cas, si vous utilisez une bibliothèque qui divise potentiellement une seule écriture logique en plusieurs appels système d’écriture, attendez-vous à des problèmes.

write() , writev() , read() , readv() peuvent générer des écritures / lectures partielles lorsque la quantité de données transférées est inférieure à celle demandée.

Citation de la page de manuel Linux pour writev() :

Notez que ce n’est pas une erreur pour un appel réussi à transférer moins d’octets que demandé

Citation de la page de manuel POSIX:

Si write () est interrompu par un signal après avoir réussi à écrire des données, il retournera le nombre d’octets écrits.

AFAIU, O_APPEND n’aide pas à cet égard, car il n’empêche pas les écritures partielles: il garantit uniquement que les données écrites sont ajoutées à la fin du fichier.

Voir ce rapport de bogue du kernel Linux :

Un processus écrit des messages dans le fichier. […] les écritures […] peuvent être scindées en deux. […] Donc, si le signal arrive […], l’écriture est interrompue. […] c’est un comportement parfaitement valide en ce qui concerne spec (POSIX, SUS, …)

Les écritures FIFO et PIPE inférieures à PIPE_MAX sont toutefois garanties comme étant atomiques.