pipe#
פותח זוג מטפלי קובץ מחוברים - אחד לקריאה, אחד לכתיבה.
pipe עוטף את קריאת המערכת pipe(2). הוא יוצר ערוץ בתים חד־כיווני חסר שם בקרנל ומוסר לכם שני מטפלי קובץ: READHANDLE, שממנו ניתן לקרוא בתים, ו־WRITEHANDLE, שלתוכו ניתן לכתוב בתים. כל מה שנכתב ל־WRITEHANDLE הופך לזמין ב־READHANDLE באותו סדר. השימוש הקלאסי הוא תקשורת בין תהליך הורה לילד שהופק על ידי fork: צד אחד כותב, השני קורא.
תקציר#
pipe READHANDLE, WRITEHANDLE
מה מקבלים בחזרה#
אמת בהצלחה, שקר בכישלון (כאשר $! מוגדר לסיבה - בדרך כלל EMFILE או ENFILE כאשר טבלת הקבצים של התהליך או המערכת מלאה). שני המטפלים נוצרים כתופעות לוואי על הארגומנטים; אין ערך החזרה של ״עצם pipe״.
בהצלחה אתם מחזיקים כעת שני descriptorים של קובץ פתוחים. כל descriptor שאתם יוצרים הוא descriptor שעליכם close - במיוחד את הקצה שכל תהליך אינו משתמש בו לאחר fork (ראו מקרי קצה).
מצב גלובלי שהוא נוגע בו#
$!- מוגדר בכישלון ל־errnoמקריאתpipe(2)הבסיסית.$|- autoflush על המטפל בצד הכתיבה.printעושה buffering דרך PerlIO, אז ללא autoflush הקורא עשוי לא לראות דבר עד שהכותב יוצא או ה־buffer מתמלא. הגדירו את$|על מטפל הכתיבה (בדרך כלל דרךselect) לפני הכתיבה, או שהפרוטוקול שלכם יקרוס ב־deadlock.$^F- מטפל הקובץ המקסימלי של המערכת. descriptorים חדשים עםfilenoגדול מ־$^F(ברירת מחדל2, כלומר מעלSTDERR) מקבלים את דגל close-on-exec באופן אוטומטי, כך שהם אינם דולפים לתוך תוכניות שהופעלו על ידיexec. הורידו את$^Fכדי לשמור את ה־pipe פתוח לאורךexec; העלו אותו, או בצעו dup על fd עם מספר נמוך, כדי לאלץ ירושה.
דוגמאות#
הורה כותב שורה; ילד מ־fork קורא אותה:
pipe my $reader, my $writer or die "pipe: $!";
my $pid = fork // die "fork: $!";
if ($pid == 0) {
# child: reads only
close $writer;
my $line = <$reader>;
print "child saw: $line";
close $reader;
exit 0;
}
# parent: writes only
close $reader;
$writer->autoflush(1);
print $writer "hello from parent\n";
close $writer;
waitpid $pid, 0;
הילד מדווח בכיוון השני - ילד מפיק נתונים, ההורה צורך אותם:
pipe my $reader, my $writer or die "pipe: $!";
my $pid = fork // die "fork: $!";
if ($pid == 0) {
close $reader;
$writer->autoflush(1);
print $writer "$_\n" for 1 .. 5;
close $writer;
exit 0;
}
close $writer;
while (my $line = <$reader>) {
print "got: $line";
}
close $reader;
waitpid $pid, 0;
Autoflush מצד מטפל־נבחר, עבור קוד שקדם לקריאות מתודה של IO::Handle:
pipe my $reader, my $writer or die "pipe: $!";
my $old = select $writer; $| = 1; select $old;
לרוב השימושים, open עם מצב pipe פשוט יותר - הוא עושה fork, pipe, ו־exec בשבילכם:
open my $fh, '|-', 'gzip', '-c' or die $!; # write to gzip's stdin
print $fh "data\n";
close $fh;
open my $fh, '-|', 'ls', '-l' or die $!; # read from ls's stdout
while (my $line = <$fh>) { print $line }
close $fh;
פנו ל־pipe חשוף כאשר אתם זקוקים לשני הכיוונים, צריכים לשמר את הילד שלא בוצע לו exec, או בונים משהו ששתי צורות ה־pipe של open אינן מכסות - אז IPC::Open2 / IPC::Open3 עוטפים בשבילכם את הריקוד pipe + fork + exec.
מקרי קצה#
סגרו את הקצה שאינכם משתמשים בו. לאחר
fork, שני התהליכים מחזיקים את שני ה־descriptorים. הקורא חייב לסגור את קצה הכתיבה, והכותב חייב לסגור את קצה הקריאה. דלגו על זה ותקבלו את באג ה־pipe הקלאסי: ה־<$reader>של הקורא לעולם אינו מחזיר EOF, מכיוון שהקרנל עדיין רואה כותב פתוח (עותק$writerסרק של הקורא עצמו). התוכנית נתקעת.כתיבה ל־pipe ללא קורא מעלה
SIGPIPE. כשכל עותק של קצה הקריאה נסגר, ה־printהבא בצד הכתיבה מספקSIGPIPE, שפעולת ברירת המחדל שלו היא להרוג את התהליך. התקינו$SIG{PIPE} = 'IGNORE'(או מטפל) כדי להפוך אותו לכישלון כתיבה רגיל כאשר$!מוגדר ל־EPIPE, שאז תוכלו לבדוק.Deadlock בלולאות pipe. שני תהליכים שכל אחד מהם כותב לשני דרך pipeים יחסמו לנצח אם שני buffer הכתיבה מתמלאים לפני שאף תהליך קורא. buffer pipe של הקרנל קטנים (בדרך כלל 64 KiB). נקזו צד אחד, השתמשו בקלט/פלט לא־חוסם, או השתמשו ב־
select/IO::Selectלמיקסור.Buffering מסתיר כתיבות. ללא
$|(או$writer->autoflush(1)) בצד הכתיבה, נתונים יושבים ב־buffer של PerlIO עד שה־buffer מתמלא או שהמטפל נסגר. קורא שחסום על<$reader>יחכה - לעתים קרובות לזמן בלתי מוגבל - לנתונים שכבר ״נכתבו״ מנקודת המבט של הכותב.חד־כיווני בלבד.
pipeמפיק ערוץ חד־כיווני: כתבו ל־WRITEHANDLE, קראו מ־READHANDLE, לא להפך. לתקשורת דו־כיוונית השתמשו ב־socketpairאו בשני pipeים.נתונים בינאריים. המטפלים שמחזיר
pipeמתחילים במחסנית שכבת PerlIO של ברירת המחדל. אם אתם מעבירים בתים גולמיים דרך ה־pipe, החילוbinmodeעל שני הקצוות; אחרת שכבות CRLF או קידוד שנירשו מברירות המחדל של התהליך יכולות לכתוב מחדש את הנתונים שלכם.Close-on-exec ו־
fileno. על מערכות עםFD_CLOEXEC, כל descriptor חדש שה־filenoשלו עולה על$^Fנוצר עם דגל close-on-exec מוגדר. descriptorים של pipe נופלים בדרך כלל הרבה מעל2, אז כברירת מחדל הם אינם שורדיםexec- מה שזה בדרך כלל מה שאתם רוצים. הורידו את$^Fלפני קריאה ל־pipeאם בכוונתכם להעביר את ה־descriptorים לתוכנית שעברהexec.
הבדלים מהמקור#
תאימות מלאה עם Perl 5.42 המקורי.
ראו גם#
fork- המחצית השנייה של ניב ה־pipe;pipeנקרא כמעט תמיד ממש לפניforkopen- המצבים'|-'ו־'-|'עושים fork, pipe, ו־execלילד בקריאה אחת; העדיפו אותם כשאתם זקוקים בדיוק לכיוון אחד לפקודה חיצונית אחתclose- סגירת הקצה שאינו בשימוש בכל תהליך היא חובה, לא אופציונליתread- קריאות מוכוונות־בתים מ־READHANDLEכשצורת<$fh>המוכוונת־שורות היא הצורה הלא נכונהprint- הדרך הרגילה לדחוף נתונים לתוךWRITEHANDLE; זכרו את$|fileno- שחזרו את ה־descriptor הבסיסי של הקובץ, לדוגמה כדי למסור ל־select/IO::Selectאו לקריאת מערכת ברמה נמוכה יותר