Previous Up Next

מיפוי קבצים לזיכרון

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

מיפוי קובץ לזיכרון: מיפוי קובץ לזיכרון מתבצע בחלונות בשני שלבים. בראשון יוצרים עצם מיפוי, שמאפשר למפות חלקים שונים בקובץ לזיכרון, ובשני ממפים איזור מסויים בקובץ (או את כל הקובץ) לזיכרון.

HANDLE CreateFileMapping(
           HANDLE  file,
           LPSECURITY_ATTRIBUTES sa,
           DWORD   protection,
           DWORD   max_size_high,
           DWORD   max_size_low
           LPCTSTR mapping_name);
הארגומנט הראשון הוא מזהה של קובץ שהתוכנית פתחה קודם לכן, או הערך INVALID_HANDLE_VALUE אם מבקשים למפות לזיכרון חלק מאיזור הדפדוף בדיסק ולא קובץ מסויים. הארגומנט השני מייצג הרשאות שאנו מעוניינים לתת לעצם המיפוי עצמו, או NULL אם אין מעוניינים לציין הרשאות. הארגומנט השלישי מציין האם נרצה לקרוא מתוך הקובץ הממופה לזיכרון, לכתוב לתוכו, או גם לקרוא וגם לכתוב. האפשרויות הללו מיוצגות על ידי הערכים סימבוליים PAGE_READONLY, PAGE_WRITEONLY, ו--PAGE_READWRITE. ניתן גם להעביר את הערך הסימבולי PAGE_WRITECOPY, שמורה למערכת ההפעלה ליצור עותק פרטי באיזור הדפדוף של דפים בקובץ שהתוכנית משנה דרך עצם המיפוי. שני הארגומנטים הבאים מציינים את הגודל המקסימלי של המיפוי. הגודל המקסימלי מיוצג ב--64 סיביות, שמועברות בשני ארגומנטים של 32 סיביות כל אחד. העברת הגודל 0 מציינת שהגודל המקסימלי הוא פשוט גודל הקובץ (אסור להעביר את הגודל 0 אם ממפים את איזור הדפדוף). הארגומנט האחרון הוא שם שאנו מעניקים לעצם המיפוי, אם אנו מעוניינים להשתמש בו מכמה תוכניות.

אם עצם מיפוי בשם הנתון קיים כבר, הקריאה מחזירה מזהה אליו (זו אינה נחשבת שגיאה), אבל במקרה כזה קריאה לפונקציה GetLastError() מחזירה את הערך ERROR_ALREADY_EXISTS.

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

את המיפוי עצמו יוצרים על ידי קריאה לפונקציה הבאה.

void* MapViewOfFile(
           HANDLE  file_mapping,
           DWORD   access,
           DWORD   file_offset_high,
           DWORD   file_offset_low
           SIZE_T  view_size);
BOOL UnmapViewOfFile(void* address);
הקריאה מקבלת מזהה שהוחזר על ידי CreateFileMapping או OpenFileMappin, ומחזירה מצביע לאיזור בזכרון שאליו מערכת ההפעלה מִיפְּתָה את הקובץ. הארגומנט השני מתאר את סוגי הגישה שאנו מעוניינים בהם לקובץ הממופה (הארגומט דומה לארגונמט protection ביצירת עצם המיפוי, אבל משתמש בערכים סימבוליים אחרים): FILE_MAP_READ, FILE_MAP_WRITE, FILE_MAP_ALL_ACCESS, ו--FILE_MAP_COPY. שני הארגומנטים הבאים מציינים את ההיסט, הבית הראשון בקובץ שימופה לזכרון, והארגומנט האחרון את גודל השטח שימופה, או 0 אם מעוניינים למפות את כל הקובץ.

ההיסט מתחילת הקובץ חייב להיות כפולה של גודל הדף של מערכת ההפעלה. על מנת לברר את גודל הדף, יש לקרוא תחילה לשגרה GetSystemInfo שמקבלת ארגומנט בודד, כתובת של מבנה מטיפוס SYSTEM_INFO, שהשדה dwPageSize שלו מתאר את גודל הדף בבתים.

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

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

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

את הפלט יש להדפיס בעזרת printf ואת הקלט יש לקלוט בעזרת scanf. מותר להניח שאורך שורת קלט מוגבל ל-08 תוים (כלומר מחרוזת של עד 18 תוים כולל ה--0 שמסמן את סוף המחרוזת).

שם העצם המיפוי חייב להתחיל בשם המשתמש שלכם. בעזרת התוכנית WinObj שניתן להוריד מהאתר www.sysinternals.com אפשר לראות את עצם המיפוי תחת BaseNamedObject.
  1. כתוב/כיתבי את התכנית. נסו אותה. האם היא עובדת גם כאשר מתחילים קודם את תהליך הפלט וגם כאשר מתחילים קודם את תהליך הפלט (היא צריכה לעבוד בשני המקרים)?
  2. האם יתכן שתוכנית הפלט תדפיס פעמיים מחרוזת שהועברה רק פעם אחת על ידי תוכנית הקלט? האם יתכן שתוכנית הפלט תדלג עם מחרוזת? יש לנמק.
  3. כעת יש להרחיב את התוכנית כך שאם היא מקבלת יותר מארגומנט אחד, הארגומנט השני הוא שם קובץ שישמש למיפוי, במקום איזור הדפדוף. האם יתכן כעת שתוכנית הפלט תדפיס מחרוזת שלא הוקלדה כלל על ידי המשתמש? האם זה יתכן כאשר משתמשים באיזור הדפדוף? יש לנמק.
יש להגיש את התוכנית לאחר ההרחבה של סעיף 3. יש לודא שהתוכנית משתמשת באיזור הדפדוף אם מעבירים לה רק ארגומנט אחד.

Copyright Sivan Toledo 2004
Previous Up Next