shmget#
Δημιουργεί ή αναζητά τμήμα κοινόχρηστης μνήμης System V και επιστρέφει το αναγνωριστικό του.
Η shmget είναι το βήμα εκχώρησης για κοινόχρηστη μνήμη SysV. Δοθέντος αριθμητικού KEY (είτε IPC_PRIVATE για φρέσκο ανώνυμο τμήμα είτε ενός γνωστού αριθμού που συμφωνείται με άλλες διεργασίες), του αιτούμενου SIZE σε bytes, και μάσκας bits FLAGS (σημαίες δημιουργίας OR-αρισμένες με 9-bit mode), επιστρέφει ακέραιο αναγνωριστικό που έχει εκχωρηθεί από τον πυρήνα. Αυτό το αναγνωριστικό - το shmid - είναι ό,τι χρησιμοποιεί κάθε επόμενη κλήση (shmctl, shmread, shmwrite) για να αναφερθεί στο τμήμα. Το τμήμα παραμένει στον πυρήνα μέχρι να αφαιρεθεί ρητά με shmctl($shmid, IPC_RMID, 0) ή να επανεκκινήσει το σύστημα· το κλείσιμο της δημιουργούσας διεργασίας δεν το απελευθερώνει.
Σύνοψη#
shmget KEY, SIZE, FLAGS
Τι επιστρέφεται#
Ακέραιο αναγνωριστικό κοινόχρηστης μνήμης (shmid) σε επιτυχία, κατάλληλο για πέρασμα στις shmctl, shmread, και shmwrite. Σε αποτυχία επιστρέφει ψευδή τιμή και θέτει το $! στο υποκείμενο errno.
use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR);
my $shmid = shmget(IPC_PRIVATE, 4096, IPC_CREAT | S_IRUSR | S_IWUSR)
or die "shmget: $!";
Το επιστρεφόμενο αναγνωριστικό είναι αδιαφανής μικρός ακέραιος. Μην κάνετε αριθμητική σε αυτό, μην το συγκρίνετε με 0 για αλήθεια - το αναγνωριστικό 0 είναι νόμιμη τιμή σε ορισμένα συστήματα. Πάντα ελέγχετε την επιστροφή έναντι της τεκμηριωμένης φρουράς αποτυχίας (δείτε Διαφορές από το upstream).
Καθολική κατάσταση που επηρεάζει#
$!- τίθεται σε αποτυχία στο υποκείμενοerrno:EACCES(δικαιώματα),EEXIST(τμήμα για αυτό το κλειδί υπάρχει ήδη και δόθηκαν και τα δύοIPC_CREATκαιIPC_EXCL),EINVAL(SIZEκάτω απόSHMMINή πάνω απόSHMMAX, ή τοSIZEδιαφέρει από το υπάρχον τμήμα κατά την αναζήτησή του),ENFILE/ENOSPC(πίνακας τμημάτων πυρήνα γεμάτος),ENOENT(κανένα τμήμα για αυτό το κλειδί και δεν δόθηκεIPC_CREAT),ENOMEM(ανεπαρκής μνήμη).
Η συνάρτηση είναι κατά τα άλλα καθαρή ως προς την κατάσταση που φαίνεται στην Perl: καμία ειδική μεταβλητή πέραν του $! δεν αγγίζεται, το $_ δεν διαβάζεται.
Παραδείγματα#
Δημιουργία φρέσκου ιδιωτικού τμήματος - το συνηθισμένο μοτίβο όταν γονέας και παιδιά μοιράζονται μνήμη μέσω fork:
use IPC::SysV qw(IPC_PRIVATE IPC_CREAT S_IRUSR S_IWUSR);
my $size = 4096;
my $shmid = shmget(IPC_PRIVATE, $size, IPC_CREAT | S_IRUSR | S_IWUSR)
or die "shmget: $!";
# children inherit $shmid across fork and attach via shmread/shmwrite
Σύνδεση σε προϋπάρχον τμήμα μέσω του γνωστού του κλειδιού. Το SIZE και τα mode bits αγνοούνται σε αυτή τη μορφή· περάστε 0 και για τα δύο:
my $key = 0xDEADBEEF;
my $shmid = shmget($key, 0, 0)
or die "shmget: $!";
Δημιουργία-ή-άνοιγμα με IPC_CREAT. Αν το κλειδί υπάρχει ήδη επιστρέφεται το υπάρχον shmid· διαφορετικά δημιουργείται νέο τμήμα μεγέθους SIZE bytes με το δοθέν mode:
use IPC::SysV qw(IPC_CREAT S_IRUSR S_IWUSR S_IRGRP);
my $shmid = shmget(0x1234, 8192, IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP)
or die "shmget: $!";
Αποτυχία αν υπάρχει ήδη τμήμα, με χρήση IPC_EXCL. Αυτό είναι το ασφαλές μοτίβο για μια διεργασία που θέλει να είναι ο μοναδικός δημιουργός:
use IPC::SysV qw(IPC_CREAT IPC_EXCL S_IRUSR S_IWUSR);
use Errno qw(EEXIST);
my $shmid = shmget(0x1234, 4096, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
if (!$shmid) {
die "shmget: $!" unless $! == EEXIST;
# another process won the race; fall back to plain lookup
$shmid = shmget(0x1234, 0, 0) or die "shmget (lookup): $!";
}
Πλήρης κύκλος δημιουργίας-χρήσης-καταστροφής με εγγυημένο καθαρισμό μέσω END:
use IPC::SysV qw(IPC_PRIVATE IPC_CREAT IPC_RMID S_IRUSR S_IWUSR);
my $shmid = shmget(IPC_PRIVATE, 1024, IPC_CREAT | S_IRUSR | S_IWUSR)
or die "shmget: $!";
END {
shmctl($shmid, IPC_RMID, 0) if defined $shmid;
}
shmwrite($shmid, "hello", 0, 5) or die "shmwrite: $!";
shmread($shmid, my $buf, 0, 5) or die "shmread: $!";
Οριακές περιπτώσεις#
Το
use IPC::SysVείναι ουσιαστικά υποχρεωτικό. Οι σταθερές σημαιών (IPC_PRIVATE,IPC_CREAT,IPC_EXCL,IPC_RMID) και τα mode bits (S_IRUSR,S_IWUSR,S_IRGRP, …) δεν είναι ενσωματωμένα. Χωρίς την εισαγωγή καταλήγετε να περνάτε σκέτες barewords που μετατρέπονται σε0και κάνουν σιωπηρά το λάθος πράγμα.Το κλειδί
0δεν είναιIPC_PRIVATE. ΤοIPC_PRIVATEορίζεται ως0στο Linux, αλλά το πέρασμα κυριολεκτικού0χωρίςIPC_CREATζητά από τον πυρήνα το τμήμα στο κλειδί0, που είναι η φρουράIPC_PRIVATEκαι αποδίδειEINVAL. Εισάγετε τη σταθερά βάσει ονόματος και χρησιμοποιήστε την.Το
SIZEστρογγυλοποιείται προς τα πάνω σε όριο σελίδας από τον πυρήνα· το επιστρεφόμενο τμήμα μπορεί να είναι μεγαλύτερο από αυτό που ζητήθηκε. Ζητήστε από τον πυρήνα το ενεργό μέγεθος μεshmctl($shmid, IPC_STAT, $ds)και αποπακετάρετε τη δομήshmid_dsαν χρειάζεστε τον πραγματικό αριθμό.Το τμήμα παραμένει πέραν της εξόδου της διεργασίας. Ένας δημιουργός που έχει καταρρεύσει ή σκοτωθεί αφήνει το τμήμα στον πυρήνα. Χρησιμοποιήστε
ipcs -mγια να καταγράψετε ορφανά τμήματα καιipcrm -m <shmid>για να τα αφαιρέσετε. Εγκαταστήστε μπλοκENDή χειριστή σήματος για να καλέσετεshmctl IPC_RMIDστον τερματισμό.Το
IPC_RMIDείναι αναβληθέν, όχι άμεσο. Σημαίνει το τμήμα για καταστροφή· η πραγματική αφαίρεση συμβαίνει μόλις πέσει στο μηδέν ο μετρητής συνδέσεων. Ασφαλές να καλεστεί αμέσως μετά τηνshmgetαν γνωρίζετε ότι κανείς άλλος δεν θα συνδεθεί.Όρια πυρήνα. Το
SHMMNIπεριορίζει τον συνολικό αριθμό τμημάτων στο σύστημα (/proc/sys/kernel/shmmni). ΤοSHMMAXπεριορίζει το μέγεθος ενός τμήματος (/proc/sys/kernel/shmmax). Σε κοινόχρηστο υπολογιστή είναι εύκολο να τα φτάσετε· αντιμετωπίστε ταENOSPCκαιEINVAL-από-μεγάλο-μέγεθος ως ζητήματα διαμόρφωσης, όχι ως bugs.Το SysV IPC δεν είναι διαθέσιμο σε κάθε πλατφόρμα. Η upstream Perl χτισμένη σε σύστημα χωρίς
HAS_SHMπεθαίνει με"System V IPC is not implemented on this machine". Η pperl στοχεύει μόνο το Linux, όπου το SysV IPC είναι πάντα παρόν, οπότε η κλήση αποστέλλεται πάντα.
Διαφορές από το upstream#
Επιστρέφει
-1αντί γιαundefσε αποτυχία. Και οι δύο τιμές είναι ψευδείς υπό τους κανόνες αλήθειας της Perl, οπότε το ιδιωματικόshmget(...) or die "$!"λειτουργεί αμετάβλητο, αλλά κώδικας που διακρίνει το «όχι αναγνωριστικό» μέσωdefined $shmidθα διαβάσει το-1ως ορισμένο. Προτιμήστε τον έλεγχο για αλήθεια, ή συγκρίνετε ρητά έναντι του-1όταν θέλετε να διακλαδώσετε βάσει της φρουράς αποτυχίας. Το-1είναι η ωμή τιμή επιστροφής τηςshmget(2), που είναι η τεκμηριωμένη φρουρά σφάλματος για αυτή την κλήση συστήματος.
Δείτε επίσης#
shmctl- λειτουργίες ελέγχου στο τμήμα που επέστρεψε ηshmget· χρησιμοποιήστεIPC_RMIDγια να το διαγράψετε,IPC_STATγια να εξετάσετε το μέγεθος και τα δικαιώματαshmread- διαβάζειSIZEbytes από το τμήμα σε βαθμωτό της Perlshmwrite- γράφει βαθμωτό της Perl στο τμήμα σε ένα offsetmsgget- το ισοδύναμο βήμα εκχώρησης για ουρές μηνυμάτων SysV όταν θέλετε ουρά, όχι επίπεδο ενταμιευτήsemget- το ισοδύναμο για σηματοφόρους SysV όταν ο στόχος είναι συγχρονισμός παρά κοινόχρηστα δεδομέναIPC::SysV- πηγή των σταθερών σημαιώνIPC_*καιS_*που απαιτεί ηshmget· δεν υπάρχει τοπική σελίδα αναφοράς, δείτε το upstream POD