supprimer Comment verrouiller un fichier dans Perl?




perl supprimer répertoire (11)

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.

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?


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' - $!";

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$!";

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).


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.


Une alternative à l'approche de fichier de verrouillage consiste à utiliser un socket de verrouillage. Voir Lock::Socket sur CPAN pour une telle implémentation. L'utilisation est aussi simple que les suivantes:

use Lock::Socket qw/lock_socket/;
my $lock = lock_socket(5197); # raises exception if lock already taken

L'utilisation d'un socket présente plusieurs avantages:

  • garantie (via le système d’exploitation) qu’aucune application ne contiendra le même verrou: il n’ya pas de condition de course.
  • Il est garanti (encore une fois via le système d’exploitation) de nettoyer soigneusement lorsque votre processus s’arrête, de sorte qu’il n’ya pas de verrou obsolète à gérer.
  • repose sur des fonctionnalités qui sont bien supportées par tout ce que Perl exécute: pas de problèmes avec le support flock (2) sur Win32 par exemple.

L'inconvénient évident est bien sûr que l'espace de noms de verrou est global. Il est possible pour une sorte de déni de service si un autre processus décide de verrouiller le port dont vous avez besoin.

[divulgation: je suis l'auteur du module susmentionné]


Utilisez le troupeau Luke.

Edit: Ceci est une bonne explication.



Mon objectif dans cette question était de verrouiller un fichier utilisé comme magasin de données pour plusieurs scripts. Au final, j'ai utilisé un code similaire à celui de Chris:

open (FILE, '>>', test.dat') ; # open the file 
flock FILE, 2; # try to lock the file 
# do something with the file here 
close(FILE); # close the file

Dans son exemple, j'ai supprimé le FICHIER flock, 8 car la fermeture (FILE) effectue également cette action. Le vrai problème, c'est que lorsque le script démarre, il doit contenir le compteur actuel et, à la fin, il doit mettre à jour le compteur. C'est là que Perl a un problème, pour lire le fichier:

 open (FILE, '<', test.dat');
 flock FILE, 2;

Maintenant, je veux écrire les résultats et, comme je veux écraser le fichier, je dois le rouvrir et le tronquer, ce qui entraîne ce qui suit:

 open (FILE, '>', test.dat'); #single arrow truncates double appends
 flock FILE, 2;

Dans ce cas, le fichier est réellement déverrouillé pendant une courte période pendant la réouverture du fichier. Cela illustre la casse du fichier de verrouillage externe. Si vous souhaitez modifier les contextes du fichier, utilisez un fichier de verrouillage. Le code modifié:

open (LOCK_FILE, '<', test.dat.lock') or die "Could not obtain lock";
flock LOCK_FILE, 2;
open (FILE, '<', test.dat') or die "Could not open file";
# read file
# ...
open (FILE, '>', test.dat') or die "Could not reopen file";
#write file
close (FILE);
close (LOCK_FILE);

flock crée des verrous de style Unix, et est disponible sur la plupart des systèmes d'exploitation sur lesquels Perl s'exécute. Cependant, les verrous de flock ne sont que des conseils.

edit: a souligné que le troupeau est portable


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.







locking