supprimer - Comment verrouiller un fichier dans Perl?




perl supprimer répertoire (9)

Quelle est la meilleure façon de créer un verrou sur un fichier en Perl?

Est-il préférable de se déplacer sur le fichier ou de créer un fichier de verrouillage pour placer un verrou et rechercher un verrou sur le fichier de verrouillage?


Avez-vous envisagé d'utiliser le module LockFile :: Simple ? Il fait le gros du travail pour vous déjà.

Dans mon expérience passée, je l'ai trouvé très facile à utiliser et robuste.



Je pense qu'il serait préférable de montrer cela avec des variables lexicales comme les gestionnaires de fichiers et la gestion des erreurs. Il est également préférable d'utiliser les constantes du module Fcntl plutôt que le code numérique numéro 2, qui pourrait ne pas être le bon numéro sur tous les systèmes d'exploitation.

    use Fcntl ':flock'; # import LOCK_* constants

    # open the file for appending
    open (my $fh, '>>', 'test.dat') or die $!;

    # try to lock the file exclusively, will wait till you get the lock
    flock($fh, LOCK_EX);

    # do something with the file here (print to it in our case)

    # actually you should not unlock the file
    # close the file will unlock it
    close($fh) or warn "Could not close file $!";

Consultez la documentation complète de flock et le didacticiel sur le verrouillage de fichiers sur PerlMonks, même s'il utilise l'ancien style d'utilisation du descripteur de fichier.

En fait, je passe généralement le traitement des erreurs à close () car il n'y a pas grand chose à faire si cela échoue de toute façon.

En ce qui concerne les éléments à verrouiller, si vous travaillez dans un seul fichier, verrouillez ce fichier. Si vous avez besoin de verrouiller plusieurs fichiers à la fois, afin d'éviter les verrous morts, il est préférable de choisir un fichier que vous verrouillez. Ce n'est pas grave si c'est l'un des nombreux fichiers que vous avez vraiment besoin de verrouiller ou un fichier séparé que vous créez uniquement pour le verrouillage.


Les autres réponses couvrent plutôt bien le verrouillage de floquette Perl, mais sur de nombreux systèmes Unix / Linux, il existe en fait deux systèmes de verrouillage indépendants: les verrous BSD flock () et POSIX fcntl ().

Sauf si vous fournissez des options spéciales à configurer lors de la construction de Perl, son flock utilisera flock () si disponible. C'est généralement bien et probablement ce que vous voulez si vous avez juste besoin de verrouiller votre application (exécutée sur un seul système). Cependant, vous devez parfois interagir avec une autre application utilisant les verrous fcntl (comme Sendmail, sur de nombreux systèmes) ou peut-être devez-vous verrouiller les fichiers sur des systèmes de fichiers montés sur NFS.

Dans ces cas, vous pourriez vouloir regarder File::FcntlLock ou File::lockf . Il est également possible de faire un verrouillage basé sur fcntl () dans Perl pur (avec des bits de pack () poilus et non portables).

Aperçu rapide des différences entre flock / fcntl / lockf:

lockf est presque toujours implémenté au dessus de fcntl, avec un verrouillage de niveau fichier uniquement. Si elles sont implémentées avec fcntl, les limitations ci-dessous s'appliquent également à lockf.

fcntl fournit un verrouillage au niveau de la plage (dans un fichier) et un verrouillage réseau sur NFS, mais les processus enfants n'héritent pas des verrous après un fork (). Sur de nombreux systèmes, vous devez avoir le descripteur de fichier ouvert en lecture seule pour demander un verrou partagé et en lecture-écriture pour demander un verrou exclusif.

flock a uniquement un verrouillage au niveau du fichier, le verrouillage se fait uniquement sur une seule machine (vous pouvez verrouiller un fichier monté sur NFS, mais seuls les processus locaux verront le verrou). Les enfants héritent des verrous (en supposant que le descripteur de fichier n'est pas fermé).

Parfois (systèmes SYSV), le flock est émulé avec lockf ou fcntl; Sur certains systèmes BSD, lockf est émulé avec flock. Généralement, ces émulations fonctionnent mal et il est conseillé de les éviter.


Ryan P a écrit:

Dans ce cas, le fichier est réellement déverrouillé pendant une courte période pendant la réouverture du fichier.

Alors ne fais pas ça. Au lieu de cela, open le fichier pour lire / écrire:

open my $fh, '+<', 'test.dat'
    or die "Couldn’t open test.dat: $!\n";

Lorsque vous êtes prêt à écrire le compteur, seek simplement le début du fichier. Notez que si vous faites cela, vous devriez truncate juste avant la close , de sorte que le fichier ne soit pas laissé avec des erreurs de fin de ligne si son nouveau contenu est plus court que les précédents. (Habituellement, la position actuelle dans le fichier est à sa fin, donc vous pouvez simplement écrire truncate $fh, tell $fh .)

De plus, notez que j'ai utilisé un handle de fichier open et un fichier lexical à trois arguments, et j'ai également vérifié le succès de l'opération. Veuillez éviter les descripteurs de fichiers globaux (les variables globales sont mauvaises, mmkay?) Et les arguments open deux arguments magiques (source de nombreux bogues (exploitables) dans le code Perl), et vérifiez toujours si vos open aboutissent.


Si vous finissez par utiliser flock, voici du code pour le faire:

use Fcntl ':flock'; # Import LOCK_* constants

# We will use this file path in error messages and function calls.
# Don't type it out more than once in your code.  Use a variable.
my $file = '/path/to/some/file';

# Open the file for appending.  Note the file path is quoted
# in the error message.  This helps debug situations where you
# have a stray space at the start or end of the path.
open(my $fh, '>>', $file) or die "Could not open '$file' - $!";

# Get exclusive lock (will block until it does)
flock($fh, LOCK_EX) or die "Could not lock '$file' - $!";

# Do something with the file here...

# Do NOT use flock() to unlock the file if you wrote to the
# file in the "do something" section above.  This could create
# a race condition.  The close() call below will unlock the
# file for you, but only after writing any buffered data.

# In a world of buffered i/o, some or all of your data may not 
# be written until close() completes.  Always, always, ALWAYS 
# check the return value of close() if you wrote to the file!
close($fh) or die "Could not write '$file' - $!";

Quelques liens utiles:

En réponse à la question que vous avez ajoutée, je vous conseille de placer le verrou sur le fichier ou de créer un fichier que vous appelez «verrouiller» chaque fois que le fichier est verrouillé et de le supprimer lorsqu'il n'est plus verrouillé (et de vous assurer que vos programmes respectent ces sémantiques).


Utilisez le troupeau Luke.

Edit: Ceci est une bonne explication.


Voici ma solution pour lire et écrire dans une serrure ...

open (TST,"+< readwrite_test.txt") or die "Cannot open file\n$!";
flock(TST, LOCK_EX);
# Read the file:
@LINES=<TST>;
# Wipe the file:
seek(TST, 0, 0); truncate(TST, 0);
# Do something with the contents here:
push @LINES,"grappig, he!\n";
$LINES[3]="Gekke henkie!\n";
# Write the file:
foreach $l (@LINES)
{
   print TST $l;
}
close(TST) or die "Cannot close file\n$!";

use strict;

use Fcntl ':flock'; # Import LOCK_* constants

# We will use this file path in error messages and function calls.
# Don't type it out more than once in your code.  Use a variable.
my $file = '/path/to/some/file';

# Open the file for appending.  Note the file path is in quoted
# in the error message.  This helps debug situations where you
# have a stray space at the start or end of the path.
open(my $fh, '>>', $file) or die "Could not open '$file' - $!";

# Get exclusive lock (will block until it does)
flock($fh, LOCK_EX);


# Do something with the file here...


# Do NOT use flock() to unlock the file if you wrote to the
# file in the "do something" section above.  This could create
# a race condition.  The close() call below will unlock it
# for you, but only after writing any buffered data.

# In a world of buffered i/o, some or all of your data will not 
# be written until close() completes.  Always, always, ALWAYS 
# check the return value on close()!
close($fh) or die "Could not write '$file' - $!";




locking