I/O

flock#

Τοποθετεί συμβουλευτικό κλείδωμα σε ένα ανοιχτό αρχείο.

Η flock είναι η φορητή πρωτογενής λειτουργία κλειδώματος αρχείων της Perl. Καλεί τη υποκείμενη flock(2), fcntl(2) ή lockf(3) - όποια παρέχει η πλατφόρμα - στο FILEHANDLE και μπλοκάρει εξ ορισμού μέχρι να μπορέσει να χορηγηθεί το ζητούμενο κλείδωμα. Τα κλειδώματα καλύπτουν ολόκληρο το αρχείο, ποτέ ένα εύρος bytes, και είναι συμβουλευτικά: συντονίζουν μόνο μεταξύ διεργασιών που επίσης καλούν flock στο ίδιο αρχείο. Κώδικας που αγνοεί το κλείδωμα μπορεί ακόμα να διαβάσει ή να τροποποιήσει το περιεχόμενο.

Σύνοψη#

flock FILEHANDLE, OPERATION

Τι επιστρέφεται#

Αληθής τιμή σε επιτυχία, ψευδής τιμή σε αποτυχία (με την $! ορισμένη). Ελέγχετε πάντα την τιμή επιστροφής - με LOCK_NB η αποτυχία είναι το κανονικό σήμα «κάποιος άλλος το κρατά», όχι σφάλμα:

flock($fh, LOCK_EX | LOCK_NB)
    or die "already locked: $!";

Σε πλατφόρμα που δεν υλοποιεί κανένα από τα flock(2), κλείδωμα fcntl(2) ή lockf(3), η flock εγείρει μοιραίο σφάλμα αντί να επιστρέψει ψευδή τιμή. Στο Linux (τη μόνη υποστηριζόμενη πλατφόρμα της pperl) αυτό δεν συμβαίνει ποτέ.

Τιμές της OPERATION#

Η OPERATION είναι ένας από τους αμοιβαία αποκλειόμενους τύπους αιτήματος, προαιρετικά συνδυασμένος με δυαδικό OR με τη σημαία μη μπλοκαρίσματος. Οι παραδοσιακές αριθμητικές τιμές είναι 1, 2, 4, 8 αλλά ο φορητός κώδικας εισάγει τα συμβολικά ονόματα από το Fcntl, είτε ξεχωριστά είτε ως ομάδα μέσω της ετικέτας :flock:

use Fcntl qw(:flock);
  • LOCK_SH - κοινόχρηστο κλείδωμα. Πολλαπλές διεργασίες μπορούν να κρατούν κοινόχρηστο κλείδωμα στο ίδιο αρχείο ταυτόχρονα. Χρησιμοποιείται για αναγνώστες.

  • LOCK_EX - αποκλειστικό κλείδωμα. Μόνο μία διεργασία μπορεί να το κρατά· καμία άλλη διεργασία δεν μπορεί να κρατά κανένα κλείδωμα στο αρχείο ταυτόχρονα. Χρησιμοποιείται για εγγραφείς.

  • LOCK_UN - απελευθερώνει όποιο κλείδωμα κρατά αυτή τη στιγμή αυτό το filehandle.

  • LOCK_NB - δυαδικό OR με LOCK_SH ή LOCK_EX για να γίνει η κλήση μη μπλοκαριστική· η flock επιστρέφει ψευδή τιμή αμέσως αν το κλείδωμα δεν μπορεί να χορηγηθεί, αντί να περιμένει.

Μια κλήση flock με νέα κατάσταση αντικαθιστά ατομικά υπάρχον κλείδωμα στο ίδιο filehandle (για παράδειγμα, αναβάθμιση από LOCK_SH σε LOCK_EX).

Καθολική κατάσταση που επηρεάζει#

  • Ορίζει την $! σε αποτυχία.

  • Εκκενώνει τον ενταμιευτή εξόδου του FILEHANDLE πριν το κλείδωμα ή το ξεκλείδωμα, ώστε τα δεδομένα της κλειδωμένης περιοχής να φτάσουν στο OS πριν μια άλλη διεργασία δει την αλλαγή κατάστασης κλειδώματος.

Παραδείγματα#

Αποκλειστικό κλείδωμα για εγγραφέα, με μπλοκάρισμα μέχρι να χορηγηθεί:

use Fcntl qw(:flock);
open my $fh, ">>", "counter.log" or die $!;
flock($fh, LOCK_EX)               or die "lock failed: $!";
print $fh "tick\n";
flock($fh, LOCK_UN)               or die "unlock failed: $!";
close $fh;

Μη μπλοκαριστική προσπάθεια - παράλειψη της εργασίας αν τρέχει ήδη άλλη διεργασία:

use Fcntl qw(:flock);
open my $fh, ">", "/var/run/myjob.lock" or die $!;
flock($fh, LOCK_EX | LOCK_NB)
    or do { warn "another instance running\n"; exit 0 };
# ... work ...
# lock auto-released when $fh is closed / program exits

Κλασικός appender mailbox. Παρατηρήστε την seek στο SEEK_END μετά το κλείδωμα - σε πολύ παλιά συστήματα η κατάσταση προσθήκης >> δεν είναι ατομική, οπότε η θέση εγγραφής πρέπει να επανακαθιερωθεί μόλις κρατηθεί το κλείδωμα:

use Fcntl qw(:flock SEEK_END);

sub lock_mbox   { flock($_[0], LOCK_EX) or die "lock: $!" }
sub unlock_mbox { flock($_[0], LOCK_UN) or die "unlock: $!" }

open my $mbox, ">>", "/var/mail/$ENV{USER}" or die $!;
lock_mbox($mbox);
seek($mbox, 0, SEEK_END) or die "seek: $!";
print $mbox $msg, "\n\n";
unlock_mbox($mbox);
close $mbox;

Κοινόχρηστο κλείδωμα ανάγνωσης κατά τη φόρτωση αρχείου ρυθμίσεων, επιτρέποντας σε άλλους αναγνώστες να προχωρούν ταυτόχρονα:

use Fcntl qw(:flock);
open my $fh, "<", "config.dat" or die $!;
flock($fh, LOCK_SH)             or die "lock: $!";
my @lines = <$fh>;
close $fh;                      # releases the lock

Αναβάθμιση κοινόχρηστου κλειδώματος σε αποκλειστικό - η δεύτερη flock εναλλάσσει ατομικά τις καταστάσεις:

flock($fh, LOCK_SH) or die $!;
# ... inspect contents ...
flock($fh, LOCK_EX) or die $!;  # now we intend to write

Οριακές περιπτώσεις#

  • Τα κλειδώματα είναι ανά filehandle, όχι ανά αρχείο. Δύο ανεξάρτητα ανοίγματα της ίδιας διαδρομής έχουν το καθένα τη δική του θέση κλειδώματος. Γι” αυτό το κλείδωμα του ίδιου του αρχείου σας δύο φορές από την ίδια διεργασία μέσω διαφορετικών handles μπορεί να οδηγήσει σε αδιέξοδο ή να συμπεριφερθεί απρόσμενα σε συστήματα βασισμένα σε fcntl(2).

  • Το κλείσιμο του filehandle απελευθερώνει το κλείδωμα. Δεν απαιτείται ξεχωριστό βήμα «ξεκλειδώματος» κατά την έξοδο του προγράμματος· η LOCK_UN είναι χρήσιμη μόνο όταν θέλετε να κρατήσετε το handle ανοιχτό μετά.

  • Η αποτυχία LOCK_NB δεν είναι croak. Επιστρέφει ψευδή τιμή και θέτει την $! σε EWOULDBLOCK. Αντιμετωπίστε το ως αναμενόμενο αποτέλεσμα, όχι ως σφάλμα.

  • Μόνο συμβουλευτικά. Μια διεργασία που δεν καλεί ποτέ flock δεν βλέπει κανένα κλείδωμα. Χρησιμοποιήστε την flock ως πρωτόκολλο συνεργασίας μεταξύ των δικών σας προγραμμάτων, όχι ως μηχανισμό ασφαλείας.

  • Μόνο ολόκληρα αρχεία. Δεν υπάρχει κλείδωμα εύρους bytes μέσω της flock. Για κλείδωμα σε επίπεδο εγγραφής χρησιμοποιήστε fcntl με F_SETLK / F_SETLKW.

  • NFS και άλλα δικτυακά συστήματα αρχείων. Ορισμένες παλιότερες υλοποιήσεις NFS δεν μπορούν να τιμήσουν την flock ανάμεσα σε υπολογιστές· η κλήση μπορεί σιωπηρά να γίνει no-op ή να επιστρέψει επιτυχία χωρίς να παρέχει αποκλεισμό. Χρησιμοποιήστε κλείδωμα μέσω fcntl αν ο δικτυακός συντονισμός έχει σημασία.

  • Κληρονομικότητα στο fork. Όταν η πλατφόρμα χρησιμοποιεί πραγματική flock(2) (όπως το Linux), τα κλειδώματα κληρονομούνται μέσω του fork· το παιδί τα μοιράζεται με τον γονέα. Σε πλατφόρμες που εξομοιώνουν μέσω fcntl(2) τα κλειδώματα δεν επιβιώνουν του fork, πράγμα που κάνει τη συγγραφή διακομιστών κλειδώματος αρκετά πιο δύσκολη.

  • Εκκένωση ενταμιευτή. Η Perl εκκενώνει τον ενταμιευτή εξόδου του FILEHANDLE σε κάθε κλήση flock. Κώδικας που συνδυάζει ενταμιευμένη print με κλείδωμα δεν χρειάζεται ρητή εκκένωση πριν το όριο του κλειδώματος.

  • Αλληλεπίδραση με ανοίγματα τύπου dup. Ένα άνοιγμα της μορφής open(my $A, ">>&=", $B) μοιράζεται τον υποκείμενο περιγραφέα αρχείου με το $B, οπότε οι flock($A) και flock($B) ενεργούν στην ίδια θέση κλειδώματος. Ένα dup >>& δίνει σε κάθε handle τον δικό του περιγραφέα και τη δική του θέση κλειδώματος.

Διαφορές από το upstream#

Πλήρως συμβατό με το upstream Perl 5.42. Η pperl τρέχει μόνο σε Linux, όπου η flock(2) είναι πάντα διαθέσιμη, οπότε η διαδρομή «η πλατφόρμα δεν διαθέτει πρωτογενή λειτουργία κλειδώματος - μοιραίο σφάλμα» που τεκμηριώνεται upstream δεν ενεργοποιείται ποτέ στην πράξη.

Δείτε επίσης#

  • fcntl - κλείδωμα εύρους bytes και συμβουλευτικό κλείδωμα με λεπτότερο έλεγχο· χρησιμοποιήστε την όταν η κοκκιδοποίηση σε επίπεδο ολόκληρου αρχείου είναι υπερβολικά αδρή ή όταν το απαιτούν δικτυακά συστήματα αρχείων

  • open - παράγει το filehandle στο οποίο λειτουργεί η flock· να θυμάστε ότι η απαιτούμενη κατάσταση ανοίγματος (< έναντι >) έχει σημασία για τις LOCK_SH / LOCK_EX που εξομοιώνονται μέσω fcntl

  • close - απελευθερώνει οποιοδήποτε flock εξακολουθεί να κρατείται στο handle

  • seek - συνδυάστε με flock όταν προσθέτετε σε αρχεία που άλλες διεργασίες ενδέχεται να επέκτειναν ενώ περιμένατε για το κλείδωμα

  • fork - η κληρονομικότητα κλειδωμάτων σε διεργασίες-παιδιά εξαρτάται από την υποκείμενη πρωτογενή λειτουργία κλειδώματος

  • Fcntl - πηγή των σταθερών LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB και της ετικέτας εισαγωγής :flock