לדלג לתוכן

9.1 - ערוצי תקשורת מקומיים וחיי הקצוות - פתרון

פתרון הבעלות על קצות הערוץ

פתרון ראשון - כל הפניה נחשבת

אחרי יצירת הכותב נוסיף שני שכפולים. לאחר צריכת הנתונים, כל עוד לפחות אחד מהם חי, הקריאה הלא חוסמת צריכה להצביע שאין נתונים זמינים ולא על סוף זרם. הקטע הבא מחליף את חלק השכפול והבדיקות בתוכנית הצינור.

let first_copy = writer.try_clone()?;
let second_copy = writer.try_clone()?;
writer.write_all(b"abc")?;
drop(writer);
let mut bytes = [0_u8; 3];
reader.read_exact(&mut bytes)?;
let mut extra = [0_u8; 1];
assert_eq!(reader.read(&mut extra).unwrap_err().kind(), io::ErrorKind::WouldBlock);
drop(first_copy);
assert_eq!(reader.read(&mut extra).unwrap_err().kind(), io::ErrorKind::WouldBlock);
drop(second_copy);
assert_eq!(reader.read(&mut extra)?, 0);

בטבלה הראשונה יש שתי הפניות חיות לקצה הכתיבה, בשנייה אחת ובשלישית אפס. תוכנית אחרת שמחזיקה עותק הייתה מוסיפה שורה לטבלה גם אם אינה מופיעה במרחב המשתנים של הפונקציה שלנו.

פתרון שני - גבול הודעה אינו גבול באפר

התוכנית הבאה היא תוכנית עצמאית המשתמשת בספרייה התקנית במערכת יוניקס.

use std::io;
use std::os::unix::net::UnixDatagram;
use std::time::Duration;

fn main() -> io::Result<()> {
    let (sender, receiver) = UnixDatagram::pair()?;
    receiver.set_read_timeout(Some(Duration::from_secs(1)))?;
    assert_eq!(sender.send(b"abcd")?, 4);
    assert_eq!(sender.send(b"EF")?, 2);
    let mut buffer = [0_u8; 2];
    assert_eq!(receiver.recv(&mut buffer)?, 2);
    assert_eq!(&buffer, b"ab");
    assert_eq!(receiver.recv(&mut buffer)?, 2);
    assert_eq!(&buffer, b"EF");
    receiver.set_nonblocking(true)?;
    assert_eq!(receiver.recv(&mut buffer).unwrap_err().kind(), io::ErrorKind::WouldBlock);
    Ok(())
}

הקריאה הראשונה צורכת הודעה אחת, והחלק שלא נכנס לבאפר אינו נשמר כקידומת של הקריאה הבאה. הקריאה השנייה מקבלת את ההודעה הבאה. בפרוטוקול שלא יכול לסבול קטיעה משתמשים בגודל מרבי מוסכם ובממשק שמאפשר לזהות דגל קטיעה, כפי שנלמד בקבלת הודעות בקרה.

פתרון שלישי - חיי הילד אינם חיי כל המתארים

המתנת הילד מוכיחה שהילד הסתיים, אבל העותק של ההורה עדיין מחזיק את קצה הכתיבה פתוח. ההורה צריך לסגור את העותק המיותר מיד אחרי מסירת הקצה לילד, ולוודא שגם ילדים אחרים אינם יורשים אותו בטעות. לאחר שכל הכותבים נסגרו והנתונים נצרכו, הקורא יראה סוף זרם.

הפעולה shutdown משנה את מצב הכיוונים של סוקט. היא אינה ממשק כללי עבור כל מתאר ואינה פועלת כפתרון לספירת הפניות של צינור. עבור הצינור התיקון הוא לסגור את ההפניות המיותרות ולתכנן את ירושת המתארים, ולא להוסיף קריאה שאינה מתאימה לסוג המשאב.