Existe-t-il un moyen de créer un fichier verrouillé au point de création, dans Perl?

StackOverflow https://stackoverflow.com/questions/6387334

  •  29-10-2019
  •  | 
  •  

Question

J'ai besoin de créer un fichier verrouillé contre les lectures, au point de création, afin que d'autres processus qui peuvent aller chercher ce fichier ne commencent pas à le lire, avant qu'il ne soit complètement écrit.

Je sais que je peux créer et alors Verrouillez-le, mais je crains que cela me laisse ouvert à une condition de course.

Ou Est-ce que je m'inquiète de rien ici? Si j'ai un fichier ouvert pour l'écriture, puis l'ouvrez pour la lecture avec un autre processus, le processus de lecture ne verra-t-il jamais un EOF jusqu'à ce que le processus d'écriture ferme le fichier?

Était-ce utile?

La solution

Il y a une condition de course avec > et >>, mais il peut être contourné en utilisant +<.

# >
open(my $fh, '+<', $qfn) or die $!;
flock($fh, LOCK_EX) or die $!;
truncate($fh, 0) or die $!;
...

# >>
open(my $fh, '+<', $qfn) or die $!;
flock($fh, LOCK_EX) or die $!;
seek($fh, 0, SEEK_END) or die $!;
...

Il y a aussi une condition de course dans le scénario que vous décrivez.

Writer                       Reader
=========================    =========================
- opens file
                             - opens file
                             - locks file
                             - obtains lock on file
- locks file [blocks]        - reads the file [empty]
                             - closes and unlocks file
- obtains lock on file
- writes to file
- writes to file
- closes and unlocks file

Une stratégie courante pour éviter ce problème est d'avoir l'écrivain

  1. Créez le fichier dans un répertoire temporaire, puis
  2. rename Le fichier dans le répertoire du lecteur surveille lorsque le fichier est terminé.

rename est une action atomique, donc le fichier semblera entièrement formé dans le répertoire que le lecteur surveille. Cela nécessite la coopération de l'écrivain, mais les meilleures solutions le feront.

Autres conseils

Utilisation umask(0777) Avant de créer le fichier.

L'entrée du fichier dans le système de fichiers sera complètement inaccessible [*] (c'est-à-dire les autorisations ----------), même si la poignée du fichier, vous avez toujours des permis.

Alors chmod() le fichier une fois que vous avez terminé:

my $file = 'foo.txt';
my $umask = umask(0777);    # change the umask
open(OUT, '>', $file);      # create the file 
umask($umask);              # reset the umask
print OUT "testing\n";      # put stuff in your file
close(OUT);                 # finished with that...
chmod(0644, $file);         # change the permissions

NB: Ce n'est pas réellement "verrouiller" dans le sens strict, où le système d'exploitation empêche activement l'accès aux fichiers. Il s'agit d'un "piratage" au niveau du système de fichiers - si vous ne pouvez pas ouvrir le fichier, il est en quelque sorte verrouillé.

*] sauf à root processe.

(FWIW, lisant un fichier à moitié écrit sera entraîner une condition EOF.)

Soit cela est pris en charge sur votre système d'exploitation, soit ce n'est pas le cas. Si si ça, c'est facile et simple.

use Fcntl   qw( O_CREAT   O_EXCL   O_WRONLY   O_EXLOCK  );

$creat_flags = (O_CREAT | O_EXCL | O_WRONLY | O_EXLOCK );

sysopen(SOMEHANDLE, $somepath, $creat_flags, 0666)
    || die "$0: couldn't sysopen $somepath with flags $creat_flags: $!";
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top