SysV IPC

semop#

Εκτελεί ατομικά μία ή περισσότερες λειτουργίες σηματοφόρου System V.

Η semop είναι το άλογο εργασίας στη χρήση σηματοφόρων SysV: παίρνει ένα αναγνωριστικό συνόλου σηματοφόρων (από την semget) και μια πακεταρισμένη λίστα λειτουργιών, και κατόπιν ζητά από τον πυρήνα να τις εφαρμόσει όλες ή καμία. Κάθε λειτουργία ονομάζει έναν μεμονωμένο σηματοφόρο μέσα στο σύνολο, ένα ποσό προς πρόσθεση σε αυτόν (συνήθως -1 για αναμονή, +1 για σήμα) και μια λέξη σημαιών. Ο πυρήνας μπλοκάρει τον καλούντα μέχρι κάθε ζητούμενη λειτουργία να μπορεί να προχωρήσει, και κατόπιν τις δεσμεύει ως μία μονάδα. Αυτό κάνει την semop αξιοποιήσιμη ως πρωτογενή λειτουργία αμοιβαίου αποκλεισμού ή μέτρησης πόρων μεταξύ άσχετων διεργασιών.

Σύνοψη#

semop $semid, $opstring

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

Αληθής τιμή σε επιτυχία, ψευδής τιμή σε σφάλμα με την $! ορισμένη. Η τιμή αλήθειας είναι το μόνο αποτέλεσμα - η semop επικοινωνεί το αποτέλεσμα μέσω της παρενέργειας στο σύνολο σηματοφόρων, όχι μέσω της επιστροφής της. Ελέγξτε την σε κάθε κλήση:

semop($semid, $ops)
    or die "semop failed: $!";

Η ψευδής επιστροφή σημαίνει ότι καμία λειτουργία στην OPSTRING δεν εφαρμόστηκε· η σημασιολογία SysV εγγυάται όλα-ή-τίποτα.

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

Ορίζει την $! σε αποτυχία, με τις συνήθεις τιμές errno από την semop(2): EAGAIN όταν είχε οριστεί το IPC_NOWAIT και η λειτουργία θα μπλοκάριζε, EIDRM όταν το σύνολο σηματοφόρων αφαιρέθηκε ενώ περίμενε, EINTR όταν σήμα διέκοψε την αναμονή, EINVAL για κακό αριθμό ή αναγνωριστικό σηματοφόρου, EACCES για αναντιστοιχία δικαιωμάτων έναντι του mode του συνόλου.

Η δομή της λειτουργίας#

Η OPSTRING είναι συνένωση εγγραφών σταθερού πλάτους. Κάθε εγγραφή είναι τρεις ακέραιοι short σε εγγενές πλάτος και παράγεται με pack:

pack("s!3", $semnum, $semop, $semflag)
  • $semnum - ο δείκτης του σηματοφόρου-στόχου μέσα στο σύνολο (0 έως nsems-1, όπου το nsems είναι το μέγεθος που πέρασε στην semget).

  • $semop - το ποσό που προστίθεται στην τιμή του σηματοφόρου. Οι αρνητικές τιμές περιμένουν μέχρι ο σηματοφόρος να είναι τουλάχιστον |$semop| πριν αφαιρέσουν· οι θετικές τιμές προσθέτουν χωρίς συνθήκη και ξυπνούν όσους περιμένουν· το μηδέν περιμένει μέχρι ο σηματοφόρος να φτάσει το μηδέν.

  • $semflag - δυαδικό OR του IPC_NOWAIT (αποτυγχάνει με EAGAIN αντί να μπλοκάρει) και του SEM_UNDO (ζητά από τον πυρήνα να αναιρέσει τη λειτουργία αν η διεργασία τερματίσει χωρίς να την αναιρέσει - απαραίτητο για χρήσεις τύπου κλειδώματος όπου ένα crash δεν πρέπει να αφήσει τον σηματοφόρο κρατημένο).

Το μήκος της OPSTRING υπονοεί τον αριθμό των λειτουργιών: ο πυρήνας επεξεργάζεται length($opstring) / sizeof(struct sembuf) εγγραφές. Το πέρασμα δύο εγγραφών πακεταρισμένων αλληλένδετα ζητά δύο λειτουργίες που εφαρμόζονται ατομικά.

Το s! στο πρότυπο είναι ο εγγενής short, που ταιριάζει στη διάταξη του sembuf στο Linux. Το σκέτο s είναι 16-bit προσημασμένο σε network-order και θα κάνει σιωπηρά λανθασμένο πακετάρισμα σε οποιαδήποτε πλατφόρμα όπου sizeof(short) != 2 ή όπου η endianness διαφέρει από το network order.

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

Αναμονή στον (μείωση κατά 1) σηματοφόρο 0 του συνόλου στο $semid:

my $op = pack("s!3", 0, -1, 0);
semop($semid, $op)
    or die "wait on semaphore failed: $!";

Σήμα (αύξηση κατά 1) στον ίδιο σηματοφόρο:

my $op = pack("s!3", 0, 1, 0);
semop($semid, $op)
    or die "signal failed: $!";

Προσπάθεια απόκτησης χωρίς μπλοκάρισμα - αποτυχία γρήγορα αν τον κρατά κάποιος άλλος:

use POSIX qw(EAGAIN);
my $op = pack("s!3", 0, -1, IPC_NOWAIT);
unless (semop($semid, $op)) {
    die "semop: $!" unless $! == EAGAIN;
    # contended; caller decides what to do
}

Απόκτηση του σηματοφόρου 0 με αυτόματη απελευθέρωση στην έξοδο της διεργασίας - το μοτίβο για αμοιβαίο αποκλεισμό ασφαλή σε crash:

my $op = pack("s!3", 0, -1, SEM_UNDO);
semop($semid, $op) or die "lock: $!";
# critical section
my $release = pack("s!3", 0, 1, SEM_UNDO);
semop($semid, $release) or die "unlock: $!";

Δύο λειτουργίες που εφαρμόζονται ατομικά - αναμονή στους σηματοφόρους 0 και 1 μαζί, χωρίς να απελευθερωθεί κανείς αν κάποιος από τους δύο θα μπλόκαρε:

my $ops = pack("s!3", 0, -1, 0)
        . pack("s!3", 1, -1, 0);
semop($semid, $ops) or die "paired wait: $!";

Αναμονή να φτάσει στο μηδέν ο σηματοφόρος 0 - η μορφή «φράγμα», όπου το $semop είναι μηδέν αντί για αρνητικό:

my $op = pack("s!3", 0, 0, 0);
semop($semid, $op) or die "barrier: $!";

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

  • Σύντομη OPSTRING: το μήκος πρέπει να είναι ακριβές πολλαπλάσιο του μεγέθους εγγραφής sembuf. Συμβολοσειρά αποκομμένη ή με padding δίνει EINVAL. Χτίζετε πάντα τη συμβολοσειρά από κλήσεις pack, ποτέ στο χέρι.

  • Το εγγενές πλάτος έχει σημασία: s!3 και όχι s3. Ένα σενάριο γραμμένο με σκέτο s λειτουργεί σε υπολογιστή με 16-bit short κατά τύχη και σπάει αλλού.

  • Μηδενικού μήκους OPSTRING: ζητά μηδέν λειτουργίες. Ο πυρήνας το αποδέχεται και επιστρέφει επιτυχία χωρίς παρενέργειες - σπάνια αυτό που θέλετε. Προστατέψτε την κλήση με return unless length $ops.

  • Διακοπή από σήμα: μια μπλοκαρισμένη semop που επιστρέφει με την $! ορισμένη σε EINTR δεν είναι σφάλμα - επαναλάβετε εκτός αν εγκαταστήσατε χειριστή που θέλει να ματαιώσει. Ο προεπιλεγμένος χειρισμός $SIG{*} της Perl δεν επανεκκινεί αυτόματα την κλήση συστήματος.

  • Το SEM_UNDO με ζευγαρωμένα ταιριαστά ζεύγη: ο πυρήνας παρακολουθεί τη σωρευτική προσαρμογή ανά σηματοφόρο ανά διεργασία. Η απόκτηση δύο φορές με SEM_UNDO και κατόπιν μία απελευθέρωση αφήνει ένα εκκρεμές -1 να αναιρεθεί κατά την έξοδο. Ζευγαρώστε κάθε -1 με ένα ταιριαστό +1 στην κανονική ροή· το SEM_UNDO είναι ασφάλεια έναντι crashes, όχι υποκατάστατο της απελευθέρωσης.

  • Αφαιρεμένο σύνολο κατά την αναμονή: αν άλλη διεργασία καλέσει semctl με IPC_RMID, κάθε μπλοκαρισμένη semop επιστρέφει ψευδή τιμή με την $! ορισμένη σε EIDRM. Το αναγνωριστικό σηματοφόρου είναι άκυρο από εκείνο το σημείο και μετά.

  • Δικαιώματα: η semop ελέγχει το δικαίωμα αλλαγής στο σύνολο. Μια διεργασία που μπορεί να κάνει semget ένα read-only handle δεν μπορεί παρ” όλα αυτά να εκτελέσει semop σε αυτό.

  • Μεγάλο πλήθος λειτουργιών: ο πυρήνας περιορίζει τον αριθμό λειτουργιών ανά κλήση στο SEMOPM (συνήθως 32). Το χτίσιμο μιας OPSTRING με περισσότερες εγγραφές αποτυγχάνει με E2BIG.

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

Πλήρως συμβατό με το upstream Perl 5.42.

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

  • semget - αποκτήστε το αναγνωριστικό που περνάτε ως πρώτο όρισμα· οι δύο χρησιμοποιούνται πάντα μαζί

  • semctl - ορίζει ή ερωτά τις τιμές σηματοφόρων, και αφαιρεί το σύνολο όταν τελειώσετε με αυτό

  • pack - χτίζει κάθε εγγραφή sembuf· s!3 είναι το πρότυπο που θέλετε

  • msgsnd - το αντίστοιχο για ουρές μηνυμάτων όταν χρειάζεστε να περάσετε δεδομένα αντί να σηματοδοτήσετε διαθεσιμότητα

  • shmget - το αντίστοιχο για κοινόχρηστη μνήμη· οι σηματοφόροι χρησιμοποιούνται συνήθως για να προστατέψουν την πρόσβαση σε ένα τμήμα κοινόχρηστης μνήμης SysV

  • IPC::SysV - εξάγει τις σταθερές IPC_NOWAIT, SEM_UNDO και IPC_RMID που χρησιμοποιούνται στο $semflag και στις εντολές semctl

  • IPC::Semaphore - αντικειμενοστραφές περιτύλιγμα πάνω από τις semget / semop / semctl όταν η διαδικαστική διεπαφή φαντάζει υπερβολικά γυμνή