לדלג לתוכן

פתרון חלון תור ולולאת הודעות

פתרון התרגיל הראשון

הודעות היצירה נמסרות במהלך CreateWindowExW. לכן הstate צריך להיות נגיש לפני החזרה מהקריאה. אפשר להדפיס לפני הקריאה, בתוך שני handlers ואחריה, ולהשוות את הסדר בפועל. אין צורך להניח שכל הודעות המערכת יופיעו באותו סדר מלא בכל גרסת Windows; הבדיקה מתמקדת בגבול הסינכרוני של היצירה.

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

פתרון התרגיל השני

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

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

הstateים חייבים להישאר חיים עד הריסת שני החלונות. אם נשמור אותם בvector שמבצע reallocation אחרי שכתובותיהם כבר נמסרו לחלונות, נשבור את החוזה. נשתמש בכתובות יציבות, למשל אובייקטים מקומיים קבועים או הקצאות בבעלות unique_ptr.

פתרון התרגיל השלישי

נגדיר constexpr UINT set_count = WM_APP + 1 ונוסיף לWndProc ענף שמעתיק wParam לstate->clicks, מסמן invalidation וחוזר. לפני ההמרה נבדוק שהערך מתאים לDWORD אם החוזה מאפשר לשולח להשתמש ברוחב גדול יותר.

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

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