לדלג לתוכן

פתרון ביטול וסיום בקשות

בזמן שהתור מחזיק את הבקשה, ה־driver אינו בעל הזכות להוציא אותה מתוך pointer שנשמר בעבר. ביטול בתור הוא מסלול framework, או callback ייעודי אם נרשם. אחרי retrieve מוצלח הבעלות עוברת ל־driver, וה־framework אינו משלים בשבילו עבודה שנשמרה מחוץ לתור ללא פרוטוקול.

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

שתי אסטרטגיות שונות

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

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

ידית ישנה אחרי completion

אם callback הביטול כבר השלים, timer אינו רשאי לקרוא UnmarkCancelable על handle ישן. שמירת reference יכולה לעכב הרס של אובייקט framework במצבים מסוימים, אך אינה משחזרת את מצב הבקשה לפני completion. הפתרון הוא סנכרון שמנקה את ה־handle המשותף לפני הסיום ומונע את הקריאה המאוחרת.

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

בדיקת cleanup

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

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