FIFOs#
FIFO - named pipe - הוא pipe בעל שם על מערכת הקבצים. שתי תכניות שאינן חולקות הורה, שהופעלו באופן עצמאי מ־shells שונים, עדיין יכולות לתקשר: האחת פותחת את הנתיב לכתיבה, השנייה פותחת אותו לקריאה, ובתים זורמים ביניהן בדיוק כמו דרך pipe אנונימי. הנתיב הוא נקודת מפגש; שום מידע אינו נשמר אי־פעם בקובץ עצמו.
זהו הערוץ שיש לפנות אליו כאשר התהליכים הם בלתי־קשורים - כאשר pipe רגיל אינו אפשרי משום שמעולם לא היה fork משותף שממנו ניתן לרשת את ה־descriptor.
יצירת ה־FIFO#
FIFO נוצר פעם אחת, כקובץ מיוחד, באמצעות POSIX::mkfifo. לאחר מכן הוא נפתח כמו כל נתיב אחר:
use POSIX qw(mkfifo);
my $path = "/tmp/demo.fifo";
mkfifo($path, 0600) or die "mkfifo $path: $!";
הארגומנט השני הוא מצב ההרשאות, אותו 0600 / 0644 שהייתם מעבירים ל־chmod - הוא קובע מי רשאי לפתוח את ה־FIFO. הקריאה נכשלת אם הנתיב כבר קיים, ולכן התקנה ארוכת־טווח בדרך כלל מבצעת unlink ל־FIFO ישן תחילה.
יצרן וצרכן#
ההתנהגות המגדירה של FIFO היא ש**open חוסם עד ששני הקצוות נוכחים**. קורא שפותח את הנתיב ממתין עד שגם כותב כלשהו פותח אותו, ולהפך. נקודת המפגש הזו היא התכונה: היא מסנכרנת שתי תכניות שמעולם לא הסכימו על תזמון.
תכנית יחידה זו מדגימה את שני הקצוות באמצעות fork, אך שני החצאים היו עובדים באותה מידה כשני סקריפטים נפרדים המורצים משני טרמינלים:
use POSIX qw(mkfifo);
my $path = "/tmp/demo.fifo";
unlink $path; # clear any stale FIFO
mkfifo($path, 0600) or die "mkfifo $path: $!";
my $kid = fork() // die "fork: $!";
if ($kid == 0) {
# Producer: open for writing (blocks until a reader appears).
open my $w, ">", $path or die "producer open: $!";
$w->autoflush(1);
print $w "from-producer\n";
close $w;
exit 0;
}
# Consumer: open for reading (blocks until a writer appears).
open my $r, "<", $path or die "consumer open: $!";
my $line = <$r>;
print "consumer read: $line"; # consumer read: from-producer
close $r;
waitpid($kid, 0);
unlink $path; # remove the FIFO when finished
שתי הקריאות ל־open הן הסנכרון. התהליך שמגיע ראשון ל־open שלו חונה שם עד שהאחר מגיע; ואז שניהם ממשיכים יחד. לאחר הפתיחה, מטפלי הקריאה והכתיבה מתנהגים כמו שני הקצוות של כל pipe - קריאות שורה, readline, print עם buffering, הכל ללא שינוי.
שתי הערות מעשיות:
Autoflush בכותב. כמו בכל pipe וסוקט, כתיבה עם buffering עלולה לעולם לא להגיע לקורא עד שה־buffer מתמלא או שהמטפל נסגר. הגדירו
autoflush(1)אם הקורא מצפה לכל שורה ברגע שהיא מיוצרת.FIFO נשאר על הדיסק.
mkfifoמשאיר אחריו קובץ מיוחד ששורד את שני התהליכים. הסירו אותו עםunlinkכאשר השיחה הסתיימה, באותו אופן שבו הייתם מנקים קובץ נעילה.
קישורים מקושרים להפניה#
הבא#
כאשר שני תהליכים צריכים חיבור במקום נתיב חד־כיווני - בקשה ותגובה, שני הכיוונים בבת אחת - פנו לסוקט. ראו סוקטים בתחום UNIX ו־UDP ו־סוקטי TCP.