shmget#
יוצר או מחפש מקטע זיכרון משותף של System V ומחזיר את המזהה שלו.
shmget הוא צעד ההקצאה לזיכרון משותף SysV. בהינתן KEY מספרי (או IPC_PRIVATE למקטע אנונימי רענן או מספר ידוע־מראש שהוסכם עם תהליכים אחרים), SIZE מבוקש בבתים, ומסיכת ביטים של FLAGS (דגלי יצירה OR’ed עם מצב 9־ביטי), הוא מחזיר מזהה מספר שלם שהוקצה על־ידי הקרנל. המזהה הזה - ה־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 הוא ערך לגיטימי בחלק מהמערכות. תמיד בדוק את ההחזרה מול sentinel הכישלון המתועד (ראה הבדלים מהמקור).
מצב גלובלי שהוא נוגע בו#
$!- מוגדר בכישלון ל־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 וביטי המצב מתעלמים מהם בצורה זו; העבר 0 עבור שניהם:
my $key = 0xDEADBEEF;
my $shmid = shmget($key, 0, 0)
or die "shmget: $!";
יצירה־או־פתיחה עם IPC_CREAT. אם המפתח כבר קיים ה־shmid הקיים מוחזר; אחרת מקטע חדש של SIZE בתים נוצר עם המצב הנתון:
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) וביטי המצב (S_IRUSR,S_IWUSR,S_IRGRP, …) אינם מובנים. ללא הייבוא אתה מסיים בהעברת barewords חשופים שמומרים למחרוזת כ־0ועושים בשקט את הדבר הלא־נכון.מפתח
0אינוIPC_PRIVATE.IPC_PRIVATEמוגדר כ־0ב־Linux, אך העברת0ליטרלי ללאIPC_CREATמבקשת מהקרנל את המקטע במפתח0, שהוא ה־sentinel של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־מ־גודל־גדול כסוגיות תצורה, לא באגים.SysV IPC אינו זמין בכל פלטפורמה. Perl המקורי שנבנה על מערכת ללא
HAS_SHMמת עם"System V IPC is not implemented on this machine". pperl מכוון רק ל־Linux, שבו SysV IPC נוכח תמיד, כך שהקריאה תמיד מופנית.
הבדלים מהמקור#
מחזיר
-1במקוםundefבכישלון. שני הערכים שקריים תחת כללי האמת של Perl, כך שה־shmget(...) or die "$!"האידיומטי עובד ללא שינוי, אך קוד שמבחין בין ״לא מזהה״ דרךdefined $shmidיקרא את-1כמוגדר. העדף בדיקת אמת, או השווה מול-1במפורש כשאתה רוצה להסתעף על sentinel הכישלון. ה־-1הוא ערך ההחזרה הגולמי שלshmget(2), שהוא sentinel השגיאה המתועד לקריאת המערכת הזו.
ראו גם#
shmctl- פעולות בקרה על המקטע ש־shmgetהחזיר; השתמש ב־IPC_RMIDכדי למחוק אותו, ב־IPC_STATכדי לבדוק גודל והרשאותshmread- קוראSIZEבתים מהמקטע לסקלר Perlshmwrite- כותב סקלר Perl לתוך המקטע ב־offsetmsgget- צעד ההקצאה המקביל לתורי הודעות SysV כשאתה רוצה תור, לא buffer שטוחsemget- המקבילה לסמפורי SysV כשהמטרה היא סנכרון במקום נתונים משותפיםIPC::SysV- מקור הקבועיםIPC_*ו־S_*של דגלים ש־shmgetדורש; אין דף עיון מקומי, ראה POD מקורי