lock#
Τοποθετεί προτρεπτικό κλείδωμα σε κοινόχρηστη μεταβλητή, πίνακα, πίνακα κατακερματισμού ή υπορουτίνα μέχρι το κλείδωμα να βγει εκτός εμβέλειας.
Η lock είναι το πρωτογενές συγχρονισμού του μοντέλου διερμηνέα-threads της Perl (use threads; use threads::shared). Όταν το THING είναι μεταβλητή που έχει δηλωθεί ως :shared - ή αναφορά σε κοινόχρηστο σύνθετο - η lock αποκτά προτρεπτικό mutex σε αυτό το δεδομένο για το υπόλοιπο του περικλείοντος μπλοκ. Όταν το μπλοκ εξέλθει, το κλείδωμα απελευθερώνεται. Οποιοδήποτε άλλο thread καλεί lock στο ίδιο δεδομένο μπλοκάρει μέχρι ο κάτοχος να το απελευθερώσει.
Το κλείδωμα είναι προτρεπτικό: σταματάει άλλα threads που επίσης καλούν lock στην ίδια μεταβλητή, τίποτα άλλο. Ένα thread που απλώς διαβάζει ή γράφει την κοινόχρηστη μεταβλητή χωρίς να την κλειδώνει δεν μπλοκάρεται και δεν σειριοποιείται. Η lock είναι σύμβαση, όχι φραγμός.
Σύνοψη#
lock $shared_scalar
lock @shared_array
lock %shared_hash
lock &shared_sub
lock $ref_to_shared_aggregate
Τι επιστρέφεται#
Το ίδιο το όρισμα:
Για βαθμωτό, η βαθμωτή τιμή.
Για πίνακα, πίνακα κατακερματισμού ή υπορουτίνα, αναφορά σε αυτό.
Η τιμή επιστροφής σπάνια χρησιμοποιείται. Η lock καλείται για την παρενέργειά της (απόκτηση του mutex), όχι για την τιμή της.
Το κλείδωμα έχει εμβέλεια μπλοκ, όχι εμβέλεια δήλωσης#
Το κλείδωμα απελευθερώνεται όταν το εσώτατο περικλείον μπλοκ εξέλθει, όχι όταν τελειώσει η δήλωση lock. Δύο συνέπειες:
Η
lockμέσα σε μπλοκ{ ... }σειριοποιεί μόνο τη διάρκεια αυτού του μπλοκ. Η έξοδος από το μπλοκ - με φυσιολογική ολοκλήρωση,return,last,die, οτιδήποτε - απελευθερώνει το κλείδωμα.Δεν μπορείτε να απελευθερώσετε ένα κλείδωμα νωρίτερα. Δεν υπάρχει
unlock. Αν χρειάζεστε στενότερο κρίσιμο τμήμα, εισαγάγετε ένα σφιχτότερο μπλοκ{ ... }:{ lock %shared_hash; $shared_hash{$key} = $value; } # lock released here do_unlocked_work();
Ασθενής δεσμευμένη λέξη#
Η lock είναι ασθενής δεσμευμένη λέξη. Αν υπάρχει υπορουτίνα με όνομα lock εντός εμβέλειας στο σημείο της κλήσης (δηλωμένη ή εισαγμένη πριν το σημείο κλήσης), καλείται αυτή η υπορουτίνα αντί για την ενσωματωμένη. Αυτό κάνει την lock ασφαλή να χρησιμοποιείται ως όνομα μεθόδου ή συνάρτησης σε κώδικα που δεν χρησιμοποιεί threads. Για να επιβάλλετε την ενσωματωμένη όταν μια ομώνυμη sub είναι εντός εμβέλειας, καλέστε την μέσω του πακέτου της: CORE::lock($thing).
Παραδείγματα#
Σειριοποιήστε μια ενημέρωση πίνακα κατακερματισμού μεταξύ threads:
use threads;
use threads::shared;
my %counts :shared;
sub bump {
my $key = shift;
lock %counts;
$counts{$key}++;
}
Κλειδώστε ένα σύνθετο μέσω αναφοράς. Η lock ακολουθεί ένα επίπεδο αναφοράς για να βρει το δεδομένο που θα κλειδώσει:
my @queue :shared;
my $queue_ref = \@queue;
sub enqueue {
my $item = shift;
lock $queue_ref; # locks @queue
push @queue, $item;
}
Στενέψτε το κρίσιμο τμήμα με ένα εσωτερικό μπλοκ ώστε άσχετη εργασία να τρέχει χωρίς κλείδωμα:
my $result;
{
lock %cache;
$result = $cache{$key};
}
expensive_post_processing($result); # runs without the lock
Χωρίς use threads::shared, η lock είναι no-op. Αυτό την καθιστά ακίνδυνη ώστε να αφεθεί σε κώδικα που μπορεί να τρέχει με ένα μόνο thread:
# no `use threads::shared` here
lock $x; # does nothing, does not warn
Οριακές περιπτώσεις#
Μη κοινόχρηστη μεταβλητή: η
lockσε μεταβλητή που δεν έχει δηλωθεί:sharedκαι δεν είναι αναφορά σε κοινόχρηστα δεδομένα δεν κάνει κάτι χρήσιμο. Στο upstream μπορεί σε κάποιες περιπτώσεις να εκπέμψει σφάλμα· σε άλλες είναι σιωπηρά no-op. Μη βασίζεστε στηlockγια να πιάσετε το σφάλμα «ξέχασα να μοιραστώ».Αναφορά έναντι σύνθετου: τόσο η
lock \%hόσο και ηlock %hκλειδώνουν τον%h. Ηlockαποαναφέρει ένα επίπεδο για να βρει το κοινόχρηστο δεδομένο.Αναδρομικό κλείδωμα μέσα σε ένα thread: το ίδιο thread μπορεί να ξανααποκτήσει ένα κλείδωμα που ήδη κρατάει· το mutex είναι αναδρομικό ανά thread. Άλλο thread παρ” όλα αυτά μπλοκάρει.
Καμία
unlock: η απελευθέρωση πριν την έξοδο μπλοκ απαιτεί αναδιάρθρωση σε στενότερη εμβέλεια. Τα μοτίβαundef $lock_guardαπό άλλες γλώσσες δεν ισχύουν - ηlockδεν είναι τιμή που αποθηκεύετε.Αμφισημία ασθενούς δεσμευμένης λέξης: μια
sub lockπου δηλώθηκε ή εισήχθη νωρίτερα υπερισχύει της ενσωματωμένης. ΧρησιμοποιήστεCORE::lockγια αποσαφήνιση.Όχι μεταξύ διεργασιών: η
lockσυντονίζει threads μέσα σε μία διεργασία διερμηνέα. Για κλείδωμα σε επίπεδο αρχείου μεταξύ διεργασιών χρησιμοποιήστε τηνflock· για προτρεπτικά κλειδώματα συστήματος αρχείων αυτοί είναι ξεχωριστοί μηχανισμοί χωρίς αλληλεπίδραση.
Διαφορές από το upstream#
Η pperl δεν υλοποιεί διερμηνέα-threads. Ο opcode
lockαναγνωρίζεται από τον αναλυτή αλλά δεν έχει επίδραση στον χρόνο εκτέλεσης - συμπεριφέρεται ακριβώς όπως η upstreamlockσε build χωρίςthreads::shared: σιωπηρό no-op που επιστρέφει το όρισμά του. Κώδικας που χρησιμοποιεί τηlockαμυντικά (όπως συνιστά η τεκμηρίωση upstream για συμβατότητα με ένα μόνο thread) τρέχει χωρίς αλλαγή. Κώδικας που εξαρτάται από τηlockγια πραγματικό συγχρονισμό δεν θα συγχρονιστεί υπό pperl.Η συνοδευτική διανομή
threads::sharedδεν είναι διαθέσιμη στην pperl· τοuse threads::sharedαποτυγχάνει κατά τη μεταγλώττιση. Ο παραλληλισμός στην pperl εκτίθεται μέσω αυτο-παραλληλοποίησης JIT (Rayon) σε συγκεκριμένα σχήματα βρόχου, όχι μέσω ορατών στον χρήστη ithreads.
Δείτε επίσης#
flock- προτρεπτικό κλείδωμα σε filehandle, που συντονίζει μεταξύ διεργασιών αντί για threadswait- συγκομιδή θυγατρικής διεργασίας· το ισοδύναμο σε επίπεδο διεργασίας της αναμονής για άλλη μονάδα εκτέλεσηςfork- το άλλο πρωτογενές ταυτοχρονικότητας στον πυρήνα της Perl, χωρίς προεπιλεγμένη κοινόχρηστη μνήμηour- δηλώστε μεταβλητή με εμβέλεια πακέτου· συνήθως συνδυάζεται με:sharedσε κώδικα με threadslocal- σύνδεση με δυναμική εμβέλεια, μερικές φορές μπερδεύεται με τηlockεπειδή και οι δύο είναι οριοθετημένες σε εμβέλεια και αμφότερες επαναφέρουν στην έξοδο μπλοκ