אפליקציות שנשברות אחרי Sleep — power events ואיך לבנות אפליקציה עסקית ששורדת resume

· עודכן בתאריך: · · Windows, Power management, פיתוח Windows, אפליקציות עסקיות, Device control, Troubleshooting, Win32 API

היסטוריית עדכונים (גרסה ראשונה, פורסמה בתאריך 22 Aug 2026)
פרסום ראשון
לצטט את המאמר הזה(DOI (ארכיון רשום): 10.5281/zenodo.22176737)

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

Go Komura (2026). אפליקציות שנשברות אחרי Sleep — power events ואיך לבנות אפליקציה עסקית ששורדת resume. KomuraSoft LLC. https://comcomponent.com/he/blog/windows-sleep-resume-power-events/

DOI (ארכיון רשום)
10.5281/zenodo.22176737
DOI (הגרסה האחרונה שנרשמה)
10.5281/zenodo.22176738

סגרתם את ה-laptop, פתחתם אותו בבוקר, והאפליקציה העסקית הייתה מלאה שגיאות. אפליקציית ניטור ציוד מפספסת נתונים רק אחרי הפסקת הצהריים. כלי resident שמייצא ל-Excel נעצר לפעמים בשגיאת חיבור. בסימפטומים כאלה, הדבר הראשון לחשוד בו הוא התנהגות שחוצה Sleep.

חלק מהאפליקציות העסקיות המסורתיות נכתבו בהנחה ש”המחשב נשאר דולק”. עכשיו ש-laptops הפכו למרכז העבודה היומיומית, אי אפשר להתעלם מסביבה שנכנסת ל-Sleep תוך דקות אם משאירים אותה. מעל זה, מחשבים שתומכים ב-Modern Standby ישנים במנגנון אחר מהמסורתי.

המאמר הזה מיועד למפתחים שבונים אפליקציות עסקיות ותוכנות בקרת ציוד ב-Windows. הוא מסדר, לפי מקורות ראשוניים, את ה-notifications שה-OS מעביר, מה נשבר אחרי resume, איך לתכנן שחזור, ואיך לחקור בשטח, בסדר הזה.

1. קודם המסקנה

מרכז התכנון הוא לא “תמיד לסדר לפני Sleep” אלא “להיות מסוגלים לשחזר אחרי resume לא משנה מתי המכונה נעצרת”. יש שלוש נקודות להחזיק.

  • ה-notification המוקדם אינו ערובה שאפשר לסיים. אי אפשר לסרב ל-Sleep, וחלון החסד של PBT_APMSUSPEND הוא בערך 2 שניות. ב-emergency suspend ה-notification לא מגיע בכלל. גם תחת Modern Standby אי אפשר להניח שאפליקציית desktop ממשיכה לרוץ ב-Sleep.123
  • מתכננים בהנחה שחיבורים, handles והמשכיות הזמן לא נשמרים מעבר ל-resume. מנתבים שגיאות תקשורת, לא רק את notification ה-resume, לאותה לוגיקת reconnect, וגם בוחנים מחדש לוחות זמנים של timers והפרשי elapsed time.
  • דיכוי Sleep וההכנה ל-resume הם אמצעים נפרדים. משתמשים ב-SetThreadExecutionState או ב-Power request למרווחי העבודה שצריכים את זה, ותמיד מבטלים אחר כך. זה לא יכול למנוע פעולת Sleep מפורשת של המשתמש, ולכן זה אינו סיבה לדלג על לוגיקת השחזור.45

אפשר גם להתחיל מהפרק שמתאים למטרה.

מה רוצים לדעת פרק לקרוא
אילו notifications מגיעות לפני Sleep ואחריו פרק 2: זרימת ה-power events
מה שונה תחת Modern Standby פרק 3: התנהגות המערכת והשהיית האפליקציה
למה קורות שגיאות חיבור והטיית זמן פרק 4: סימפטומים קלאסיים
איך מממשים reconnect, טיפול בזמן ודיכוי Sleep פרק 5: תכנון ששורד resume
איך ממיינים קריאת תמיכה פרק 6: powercfg ו-event log

2. מה קורה סביב Sleep — זרימת ה-power events

ה-OS מודיע לאפליקציות על שינויי מצב הפעלה דרך הודעת WM_POWERBROADCAST.2 קודם, שלושת ה-events שמשמשים סביב מעבר ה-suspend. איך ה-low-power idle של Modern Standby שונה מכוסה בפרק 3.

Event משמעות
PBT_APMSUSPEND עומדים להיכנס ל-Sleep (ההזדמנות האחרונה להתכונן)
PBT_APMRESUMEAUTOMATIC חזרו (תמיד מגיע ב-resume)
PBT_APMRESUMESUSPEND resume שנגרם מפעולת משתמש (זה מותנה)
זרימת ה-notifications של Sleep ו-resumePBT_APMSUSPEND מגיע ממש לפני Sleep עם בערך 2 שניות חסד; ב-resume, PBT_APMRESUMEAUTOMATIC תמיד מגיע, ו-PBT_APMRESUMESUSPEND בא אחריו רק ב-resume ביוזמת משתמשאפליקציהOSאפליקציהOSSleep (הקוד לא רץ)PBT_APMSUSPEND (בערך 2 שניות חסד)שמירת state וסגירת חיבוריםPBT_APMRESUMEAUTOMATIC (מגיע ב-resume)reconnect ובניית state מחדשPBT_APMRESUMESUSPEND (רק resume ביוזמת משתמש)עדכון מסך ועבודה אחרת שפונה למשתמש

איור 1: ה-notifications מסתכמים ב”מילה ממש לפני, ומילה או שתיים אחרי resume”. הטיפול בצד ה-resume הוא מה שמניע את השחזור.

ה-notification שלפני Sleep הוא הזדמנות “להתכונן אם יש זמן”

PBT_APMSUSPEND הוא ה-notification שמגיע ממש לפני הכניסה ל-Sleep. הוא מאפשר לסגור קבצים ולשמור state, אבל הוא מגיע עם שני האילוצים הבאים.

אילוץ השפעה על התכנון
חלון החסד הוא בערך 2 שניות לכל אפליקציה מעבר לזמן הזה המערכת ממשיכה בלי לחכות לאפליקציה1
emergency suspend לא נותן notification מוקדם כשרמת הסוללה קריטית, למשל, המכונה נעצרת בלי כל הכנה2

לכן תכנון ש”תמיד מסיים לשמור אחרי קבלת ה-notification הזה” לא מחזיק. משתמשים ב-notification המוקדם כדי להתכונן במה שיש זמן, ואת עיקר השחזור שמים בצד ה-resume.

ההבדל בין Sleep רגיל ל-emergency suspendSleep רגיל מעביר PBT_APMSUSPEND ממש לפני עם בערך 2 שניות להתכונן, אבל emergency suspend שנגרם מסוללה קריטית וכדומה נעצר בלי notification מוקדם, כך שתכנון שתלוי ב-notification המוקדם לא מחזיקSleep רגילPBT_APMSUSPEND (בערך 2 שניות חסד)להתכונן, ואז לעצורemergency suspend (סוללה כמעט נגמרה)עצירה בלי notification מוקדםתכנון שמניח שה-notification יגיע לא מחזיק

איור 2: emergency suspend מגיע בלי אזהרה. לכן הכנה היא “בונוס אם היא מספיקה בזמן”, והעיקר הולך לצד ה-resume.

notifications של resume מפרידים שחזור מכני מעבודה שפונה למשתמש

ב-resume מ-suspend, PBT_APMRESUMEAUTOMATIC מגיע קודם. אם המכונה חזרה בגלל כפתור ההפעלה או הקשה, או אם נוכחות משתמש זוהתה אחרי resume, PBT_APMRESUMESUSPEND בא אחריו.67

לעומת זאת, ב-resume בלי משתמש כמו remote wake דרך הרשת או resume לתחזוקה, מגיע רק PBT_APMRESUMEAUTOMATIC. שחזור נדרש כמו בניית חיבורים מחדש שמים בראשון, ופעולות שפונות למשתמש כמו עדכון מסך או בקשת login מחדש בשני.6

פיצול עבודה בין שני שלבי ה-resumeשמים שחזור מכני כמו reconnect ב-PBT_APMRESUMEAUTOMATIC, שמגיע ב-resume; שמים עבודה שפונה למשתמש כמו עדכון מסך או בקשת login מחדש ב-PBT_APMRESUMESUSPEND, שמגיע רק ב-resume ביוזמת משתמשPBT_APMRESUMEAUTOMATIC (ב-resume)שחזור מכניPBT_APMRESUMESUSPEND (resume ביוזמת משתמש)עבודה שפונה למשתמשreconnect ופתיחה מחדש של handlesעדכון מסך ובקשת login מחדש

איור 3: השני לא מגיע ב-resume בלי משתמש, כך ששמים שחזור נדרש בשני יחמיצו אותו.

גם אפליקציות בלי window יכולות לקבל את ה-notifications

services בלי window ואפליקציות console יכולים להשתמש ב-RegisterSuspendResumeNotification עם DEVICE_NOTIFY_CALLBACK ולקבל את אותם notifications דרך callback.8

גם, WM_POWERBROADCAST לא יכול להגיד אם מצב ה-low power היה Sleep או hibernation.7 האפליקציה צריכה לתכנן את השחזור סביב האירוע המשותף “זה נעצר, וזה חזר”.

3. Modern Standby — משמעות ה-“Sleep” השתנתה

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

S3 Sleep המסורתי הוא מודל שעוצר את כל המערכת. Modern Standby, לעומת זאת, הוא מודל דמוי smartphone שבו המערכת ממשיכה לרוץ לסירוגין אחרי שהמסך כבה.

עם זאת, זה לא אומר שאפליקציות desktop רגילות ממשיכות לרוץ. בשלב הראשון של הכניסה ל-Sleep הן מושהות על ידי Desktop Activity Moderator (DAM).3

מצב התנהגות המערכת הנחה לאפליקציות desktop
S3 Sleep מסורתי כל המערכת נעצרת הקוד לא רץ ב-Sleep
Modern Standby רצה לסירוגין כדי לשמור על הרשת, לקבל notifications וכדומה מושהה על ידי DAM; קוד רגיל לא רץ

הרכיבים שמרוויחים מהפעילות הלא-רציפה הם אלה שנבנו למנגנון הזה. לתכנון אפליקציה עסקית, המסקנה זהה בשני המקרים: “הקוד שלכם לא רץ ב-Sleep”.3

ההבדל בין Sleep מסורתי ל-Modern StandbyS3 Sleep מסורתי עוצר את כל המערכת, בעוד שתחת Modern Standby המערכת ממשיכה לרוץ לסירוגין אחרי שהמסך כבה. אפליקציות desktop מושהות על ידי DAM, עם זאת, כך שקוד האפליקציה לא רץ באף אחד מהמקריםS3 Sleep מסורתי: כל המערכת נעצרתקוד האפליקציה לא רץModern Standby: המערכת רצה לסירוגיןאפליקציות desktop מושהות על ידי DAM

איור 4: המודל השתנה, אבל לאפליקציית desktop המסקנה זהה: “אי אפשר לרוץ ב-Sleep”.

לא להפוך את notification ה-resume לטריגר היחיד לשחזור

כניסה ויציאה מ-low-power idle של Modern Standby לא תמיד חופפות למעבר ה-suspend המסורתי. חיבור יכול כבר להיות שבור בלי ששום notification הגיע. מתייחסים ל-notification של resume כעזר שמאיץ שחזור, ושמים במרכז נתיב שעושה reconnect בזיהוי שגיאת תקשורת. המבנה הקונקרטי מוסבר בפרק 5.

גם, כי המעבר למצב low power הוא הדרגתי, תזמון הניתוקים והעצירות אינו חד כמו תחת S3. גם למשתמשים קשה להבדיל בין “המסך פשוט כבה” לבין “זה נכנס ל-Sleep”, ולכן כשמקבלים דיווח סימפטום מאשרים אם המכסה נסגר וכמה דקות המכונה הושארה ללא פעילות.

4. מה נשבר — סימפטומים קלאסיים

שגיאות אחרי resume אפשר לארגן לחיבורים, handles של devices, והמשכיות הזמן. למשאבים משותפים, בודקים גם כמה זמן לוקחים re-authentication והקמת הרשת מחדש.

חיבור TCP לא שם לב לניתוק עד ששולחים או מקבלים

ב-Sleep, הצד השני, התקני NAT ו-firewalls מתייחסים לשתיקה שלכם כ-timeout וזורקים את החיבור. ה-socket שלכם לא יודע על זה, עם זאת, כך שזה נכשל רק כששולחים או מקבלים אחרי resume.

לפעמים receive שממתין לא נכשל בכלל. זו הסיבה שצריך keepalive כדי לבדוק אם החיבור חי. חיבורי database ו-WebSockets הולכים לפי אותו דפוס.

serial ports והתקני USB צריכים ש-handles שלהם ייפתחו מחדש

התקן USB יכול להיראות, ב-resume, כאילו נשלף והוכנס בחזרה, וה-handle שהיה פתוח מתחיל להחזיר שגיאות. זה הדפוס הטיפוסי מאחורי אפליקציית בקרת ציוד ש”מקבלת שגיאת תקשורת רק אחרי הפסקת הצהריים”.

במקום להניח שה-handle נשאר שמיש, מבנים את האפליקציה כך שתוכל לפתוח את ה-device מחדש. תכנון reconnect מכוסה גם ב-מאמר על serial communication.

לבחון מחדש עבודה מחזורית, elapsed time ועבודה מתוזמנת בנפרד

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

עבודה מה קורה מעבר ל-Sleep טיפול
עבודה מחזורית כמו “poll כל 10 שניות” נעצרת ב-Sleep. איך היא יורה אחרי resume תלוי ב-API וב-runtime לבנות מחדש את לוח הזמנים ב-resume
חישובים שמשתמשים בהפרש מה-timestamp הקודם ההפרש הופך פתאום ל”שווה ערך ל-8 שעות”, וממוצעים או שיפוטי timeout נשברים להגן מפני הפרשים גדולים באופן חריג
עבודה מתוזמנת כמו “לרוץ כל לילה ב-2 בלילה” לא רצה אם המחשב ישן באותו זמן להשתמש ביכולת wake-from-sleep של Task Scheduler אם צריך

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

שלושה צורות שבהן המשכיות הזמן נשברתעבודה מחזורית נעצרת ב-Sleep והירי אחרי resume שונה לפי API, לכן בונים מחדש את לוח הזמנים ב-resume; ההפרש מה-timestamp הקודם הופך ענק אחרי resume, לכן מגנים עליו; עבודה מתוזמנת לא רצה אם המכונה ישנה, לכן שוקלים wake-from-sleep של Task Schedulerעבודה מחזורית: נעצרת ב-Sleepלבנות מחדש את לוח הזמנים ב-resumeהפרש elapsed time: מתנפחלהגן מפני הפרשים חריגיםעבודה מתוזמנת: ישנה, לא רצהלהעיר את המכונה עם הגדרת wake

איור 5: כותבים טיפול ב-timers ובשעון בהנחה ש”הזמן קופץ”. לכל אחת משלוש הצורות יש סוג טיפול משלה.

שלושה דברים שנשברים מעבר ל-Sleepמעבר ל-Sleep, חיבור TCP נזרק ב-timeout בצד השני, handle של התקן USB מתבטל כאילו חובר מחדש, ועבודה מבוססת elapsed time רואה קפיצת זמן ענקית. משחזרים כל אחד עם reconnect, פתיחה מחדש, והגנה על הפרשמרווח Sleepחיבור TCP: נזרק על ידי הצד השניהתקן USB: handle בוטלelapsed time: קפיצה ענקיתלזהות את השגיאה ולעשות reconnectלפתוח את ה-device מחדשלהגן מפני הפרשים חריגים

איור 6: מה שנשבר נופל לשלוש משפחות, “חיבורים”, “handles”, ו”המשכיות הזמן”, ולכל אחת יש סוג שחזור מיושב.

כונני רשת ו-VPN יש להם מרווח המתנה ממש אחרי resume

כונני רשת ו-VPN לפעמים צריכים re-authentication והקמה מחדש אחרי resume. כתוצאה מזה יש חלון של כמה שניות עד כמה עשרות שניות ממש אחרי resume שבו גישה נכשלת.

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

5. בניית אפליקציות ששורדות resume

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

לנתב את notification ה-resume ושגיאות תקשורת לאותה לוגיקת reconnect

כש-WM_POWERBROADCAST של ה-window ברמה העליונה מקבל PBT_APMRESUMEAUTOMATIC, זורקים את החיבורים שמוחזקים ובונים אותם מחדש. עם זאת, אל תסמכו על notification ה-resume לבדו. notifications יכולים להתפספס, ותקשורת יכולה לקרות לפני שה-notification מגיע.

תמיד מספקים נתיב ש”עושה reconnect כשמזהים שגיאת תקשורת”, ומתייחסים ל-notification של resume כטריגר שמתחיל את העבודה הזו מוקדם יותר. דוגמת ה-C# הבאה היא החלק שמבקש reconnect מ-notification ה-resume. צד שגיאת התקשורת מתנקז לאותה לוגיקת reconnect.

// C#: מנקזים גם את הודעת ה-resume וגם שגיאות תקשורת לאותה לוגיקת reconnect
protected override void WndProc(ref Message m)
{
    const int WM_POWERBROADCAST = 0x0218;
    const int PBT_APMRESUMEAUTOMATIC = 0x0012;
    if (m.Msg == WM_POWERBROADCAST && (int)m.WParam == PBT_APMRESUMEAUTOMATIC)
    {
        _connectionManager.RequestReconnect();   // בקשת reconnect אידמפוטנטית
    }
    base.WndProc(ref m);
}

reconnect משלב “idempotence, backoff ו-keepalive”

לוגיקת reconnect צריכה את שלושת האלמנטים הבאים יחד.

אלמנט תפקיד
reconnect אידמפוטנטי לשחזר בבטחה לא משנה כמה פעמים מבקשים
retries עם exponential backoff להאריך את המרווח לפני הניסיון הבא אחרי כשל
keepalive במצב יציב לאשר שהחיבור חי ולזהות ניתוק מוקדם

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

תכנון reconnect ששורד resumenotification ה-resume, שגיאת תקשורת וכשל keepalive כולם מתנקזים לאותה לוגיקת reconnect אידמפוטנטית, שמנסה מחדש עם exponential backoff בכשלכןלאnotification resume (PBT_APMRESUMEAUTOMATIC)לוגיקת reconnect אידמפוטנטיתזוהתה שגיאת תקשורתכשל keepaliveהצליח?חזרה להפעלה רגילהניסיון מחדש אחרי exponential backoff

איור 7: מרכזים reconnect לנתיב אידמפוטנטי אחד, ונכנסים לאותו כביש מ-notification ה-resume, מזיהוי שגיאה, או מה-keepalive.

לא לערבב מרווח שבו הזמן קפץ לתוך החישובים

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

כשמודדים זמן מעבר ל-resume, מבחינים בין השעון שממשיך להתקדם ב-Sleep (זמן שעון קיר) לבין הזמן שבאמת הושקע בעבודה. בניית לוח הזמנים מחדש של עבודה מחזורית וטיפול בעבודה מתוזמנת שלא רצה צריכים גם הם להיבחן מחדש לפי הקטגוריות בפרק 4.

לדכא Sleep במפורש לעבודה שאסור להיקטע

בזמן שעבודה שאסור שתישן באמצעה בתהליך, כמו העברת נתונים או תקשורת רציפה עם device, משתמשים ב-SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED). אם רוצים גם להשאיר את המסך דולק, מוסיפים ES_DISPLAY_REQUIRED.74

האמצעי האחר הוא Power request דרך PowerCreateRequest ו-PowerSetRequest. כי אפשר לצרף מחרוזת סיבה, powercfg /requests מראה “מי חוסם Sleep, ולמה”. זה יותר ידידותי בכך שאנשי תפעול יכולים לקרוא את הסיבה.5

אמצעי יחידת ניהול ואזהרות
SetThreadExecutionState לפי thread. מבטלים מאותו thread שהגדיר
Power request (PowerCreateRequest + PowerSetRequest) מנוהל ב-handle. משתמשים בזה לעבודה שמחליפה threads, כמו async/await

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

אילוץ תגובה נדרשת
מה שמדוכא הוא idle Sleep אוטומטי משאירים את לוגיקת ה-reconnect כדי לטפל בפעולות מפורשות כמו סגירת המכסה או בחירת Sleep מתפריט Start
במחשב Modern Standby שרץ על סוללה, גם Power requests נחתכים זמן מה אחרי timeout ה-Sleep מבטיחים עבודה שאי אפשר לקטוע עם חשמל AC או בצד התפעול5
ביטול שנשכח הופך את המחשב לבלתי מסוגל לישון תמיד מבטלים כשהעבודה מסתיימת
שני אמצעים לדיכוי Sleepבין אם משתמשים ב-SetThreadExecutionState הנוח או ב-API של Power request שיכול לצרף מחרוזת סיבה והוא גלוי למנהל דרך powercfg, תמיד מבטלים כשהעבודה מסתיימתמרווח עבודה שאסור לישון באמצעוSetThreadExecutionStatePower request (PowerSetRequest)נוח, רק flagsעם סיבה, גלוי ב-powercfgתמיד לבטל כשהעבודה מסתיימת

איור 8: בכל אחד מהאמצעים, “לבטל כשמסיימים” הוא תנאי מוחלט. Power request, שיכול להפוך את הסיבה לגלויה, ידידותי יותר לתפעול.

אם הפעלה רציפה היא דרישה, לבחון מחדש את המיקום ואת התפעול

services ואפליקציות בלי window יכולים גם הם לקבל את ה-notifications דרך DEVICE_NOTIFY_CALLBACK עם RegisterSuspendResumeNotification.8

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

6. חקירה — powercfg ו-event log

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

מה לברר כלי מה לבדוק
למה זה לא נכנס ל-Sleep powercfg /requests ה-processes וה-drivers שמוציאים Power requests. גם בודקים SetThreadExecutionState שמעולם לא בוטל
למה זה מתעורר מעצמו powercfg /lastwake, powercfg /waketimers סיבת ה-wake האחרונה, וה-timers ששמורים להעיר את המכונה
איכות Modern Standby powercfg /sleepstudy צריכת חשמל ופעילות לכל מרווח Sleep9
ציר הזמן של Sleep ו-resume Kernel-Power ביומן System רשומות של כניסה ל-Sleep ושל resume

התאמת ה-event log מול הלוג של האפליקציה מאפשרת לאשר באופן אובייקטיבי אם היה resume ממש לפני השגיאה. לא עוצרים בחשד ל-Sleep; מיישרים את חותמות הזמן ומפרידים את הסיבה.

מיפוי סימפטומי תקלות הפעלה לפקודות חקירהלסימפטום לא-נכנס-ל-Sleep, מוצאים מי מחזיק Power request עם powercfg /requests; לסימפטום מתעורר-מעצמו, מוצאים את סיבת ה-wake עם /lastwake ו-/waketimers; לציר הזמן, משתמשים ב-Kernel-Power ב-event logלא נכנס ל-Sleeppowercfg /requestsמתעורר מעצמוpowercfg /lastwake ו-/waketimersרוצים לבדוק את ציר הזמןKernel-Power ב-event logדיכוי Sleep שמעולם לא בוטל עולה גם הוא

איור 9: סימפטומים ממופים לפקודות חקירה בשלוש משפחות. קודם מאשרים “האם זה ישן ממש לפני”, ואז בוחרים את הכלי.

7. סיכום

טיפול ב-Sleep אינו מסתיים רק בקבלת ה-notifications. מתחשבים בכך שההכנה לא תספיק בזמן ובכך ש-notification ה-resume לא יגיע, ומחלקים את התפקידים כך.

יעד תכנון או חקירה נקודות להחזיק
לפני Sleep אי אפשר לסרב. מתכוננים בתוך חלון החסד של בערך 2 שניות של PBT_APMSUSPEND, אבל בחירום לא מגיע notification
notifications של resume שחזור נדרש ב-PBT_APMRESUMEAUTOMATIC, עבודה שפונה למשתמש ב-PBT_APMRESUMESUSPEND. לא סומכים על ה-notifications לבדם
חיבורים ו-handles ממקדים reconnect משגיאות תקשורת, ומשלבים idempotence, exponential backoff ו-keepalive
זמן מגנים מפני הפרשי elapsed time חריגים ובונים מחדש עבודה מחזורית. עבודה מתוזמנת לא רצה בזמן שהמכונה ישנה
דיכוי Sleep מגדירים רק למרווחים שצריכים אותו ומבטלים אחר כך. משאירים את השחזור לפעולות Sleep מפורשות וכדומה
חקירת שורש שואלים אם המכונה ישנה ממש לפני, ומתאימים את רשומות powercfg ו-Kernel-Power מול הלוג של האפליקציה

מנקודת המבט של האפליקציה, Sleep הוא אירוע שבו “הזמן קופץ בלי אזהרה, החיבורים לסביבה נחתכים, ואז הכול חוזר”. האם התכנון מתייחס לזה כחלק מהפעלה יומיומית ולא כמצב חריג הוא מה שמפריד אפליקציות עסקיות יציבות מבלתי יציבות בעידן ה-laptop.

מאמרים קשורים

תחומי ייעוץ קשורים

KomuraSoft LLC מטפלת בחקירת שורש של בעיות כמו “התקשורת נשברת אחרי resume מ-Sleep” ו”החיבור ל-device נופל אחרי הפסקת הצהריים”, בהתאמת לוגיקת reconnect וטיפול ב-power events לאפליקציות קיימות, ובסקירות תכנון של אפליקציות עסקיות ותוכנות בקרת ציוד שנבנו להפעלת laptop.

קישורים

  1. Microsoft Learn, PBT_APMSUSPEND event. על כך שזה ה-event שמגיע ממש לפני שהמחשב נכנס למצב suspend; על כך שהאפליקציה אמורה לסיים את העבודה הנדרשת לשמירת נתונים; ועל כך שהמערכת מאפשרת בערך שתי שניות לטפל ב-notification זה, ואפליקציה שממשיכה מעבר לזה נתונה להפרעה. ↩ ↩2

  2. Microsoft Learn, System Power Management Events. על כך שהמערכת משדרת מראש שינויי מצב הפעלה כמו Sleep; על כך ש-PBT_APMSUSPEND מגיע לפני idle Sleep כדי שאפשר יהיה להתכונן בסגירת קבצים ושמירת נתונים; על כך ש-emergency suspend (סוללה קריטית וכדומה) לא נותן notification מוקדם; על כך שטיפול בהודעה זו מותר לכל היותר בערך שתי שניות לאפליקציה ונחתך אחרי timeout; ועל כך שכל אפליקציה מקבלת notification ב-resume. ↩ ↩2 ↩3

  3. Microsoft Learn, Prepare software for modern standby. על כך ש-Desktop Activity Moderator (DAM) משהה אפליקציות desktop בשלב הראשון של המעבר ל-Modern Standby; ועל כך שהמערכת אחר כך נעה בשלבים לשלב low power ולשלב resiliency, ורק רכיבים מותרים רצים לסירוגין. ↩ ↩2 ↩3

  4. Microsoft Learn, SetThreadExecutionState function (winbase.h). על כך ש-ES_SYSTEM_REQUIRED ו-ES_DISPLAY_REQUIRED יכולים לדכא idle Sleep וכיבוי תצוגה; ועל הכרזת דיכוי רציף עם ES_CONTINUOUS וביטולו בקריאה ל-ES_CONTINUOUS לבדו כשמסיימים. ↩ ↩2

  5. Microsoft Learn, PowerSetRequest function (winbase.h). על היכולת להגדיר סוג request כמו השארת מערכת או תצוגה ערות על אובייקט Power request שנוצר עם PowerCreateRequest; על היכולת לצרף מחרוזת סיבה אבחנתית; ועל כך ש-Power requests פתוחים ניתנים למנייה עם powercfg /requests. ↩ ↩2 ↩3

  6. Microsoft Learn, PBT_APMRESUMESUSPEND event. על כך שזה נשלח אחרי PBT_APMRESUMEAUTOMATIC ב-resume ביוזמת משתמש או כשקלט משתמש מזוהה אחר כך; על כך שנשלח רק PBT_APMRESUMEAUTOMATIC ב-resume מסיבה חיצונית כמו remote wake; ועל כך שהאפליקציה אמורה לפתוח מחדש קבצים שנסגרו ב-Sleep ולהתכונן לקלט משתמש. ↩ ↩2

  7. Microsoft Learn, WM_POWERBROADCAST message. על כך ש-PBT_APMRESUMEAUTOMATIC תמיד נשלח ב-resume, ו-PBT_APMRESUMESUSPEND נשלח גם ב-resume מקלט משתמש; על כך שההודעה לא מבדילה את סוג מצב ה-low power; על כך שפרטי מעברי power state נרשמים ב-Event Viewer של המערכת; ועל קריאה ל-SetThreadExecutionState כדי למנוע כניסה למצב low power. ↩ ↩2 ↩3

  8. Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). על כך שזה ה-API שרושם לקבלת notifications של suspend/resume, ועל ציון DEVICE_NOTIFY_CALLBACK כדי שאפליקציה או service בלי window יוכלו לקבל את ה-notification דרך callback בנוסף למסירה ל-window. ↩ ↩2

  9. Microsoft Learn, Modern standby SleepStudy. על כך שהדוח שמייצר powercfg /sleepstudy מאפשר לבדוק, לכל מרווח Modern Standby, צריכת חשמל, פעילות וסיבת ה-wake (כפתור הפעלה, קלט משתמש, wake timer וכן הלאה). ↩

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

העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.

המאמר קשור ישירות לשירותים הבאים.

שאלות נפוצות

שאלות נפוצות בפניות בנושא המאמר.

האם אפליקציה יכולה לדעת מראש שנכנסים ל-Sleep ולסרב?
ב-Windows הנוכחי אפשר לקבל את ה-notification, אבל אי אפשר לסרב. ממש לפני Sleep מגיע WM_POWERBROADCAST עם PBT_APMSUSPEND, ואפשר להתכונן שם (לסגור קבצים ולשמור state), אבל הזמן המותר הוא בערך שתי שניות לכל אפליקציה, ואם חורגים המערכת ממשיכה בלי לחכות. ב-emergency suspend, למשל כשהסוללה על סף סיום, ה-notification המוקדם עצמו לא מגיע. לכן תכנון שחייב להסתיים לפני Sleep לא מחזיק; צריך תכנון שיודע לשחזר ב-resume, לא משנה מתי חתכו. לקטע עבודה שבאמת לא רוצים שיישן באמצעו, מדכאים Sleep במפורש עם SetThreadExecutionState או עם Power request (PowerSetRequest).
איך מזהים שהמחשב חזר מ-Sleep?
אם לאפליקציה יש window, מטפלים ב-WM_POWERBROADCAST. ב-resume מ-suspend מגיע PBT_APMRESUMEAUTOMATIC, ואם ה-resume נגרם מפעולת משתמש (כפתור ההפעלה או הקשה), אחריו מגיע גם PBT_APMRESUMESUSPEND. resume בלי משתמש שחוזר מיד ל-Sleep מעביר רק PBT_APMRESUMEAUTOMATIC, לכן הפיצול הבסיסי הוא לשים עבודה הכרחית כמו reconnect בצד PBT_APMRESUMEAUTOMATIC, ועבודה שפונה למשתמש כמו עדכון UI בצד PBT_APMRESUMESUSPEND. services בלי window ואפליקציות console יכולים לקבל את אותם notifications דרך callback עם RegisterSuspendResumeNotification ו-DEVICE_NOTIFY_CALLBACK.
אפשר להשאיר את האפליקציה רצה במהלך Sleep?
ככלל, לא. ב-Sleep עצירת הביצוע של ה-CPU עצמה (במחשב Modern Standby אפליקציות desktop מושהות על ידי Desktop Activity Moderator), וקוד האפליקציה לא רץ. יש שתי בחירות. אחת היא לדכא Sleep רק בזמן שיש עבודה בתהליך. ציון ES_SYSTEM_REQUIRED ב-SetThreadExecutionState, או Power request עם PowerCreateRequest/PowerSetRequest, ידכא idle Sleep אוטומטי באותו מרווח (אפשר לאשר ב-powercfg /requests). זה עדיין לא יכול לעצור פעולת Sleep מפורשת כמו סגירת המכסה, ולכן גם בזמן דיכוי צריך להיות מוכנים ל-resume. השנייה היא לקבל Sleep ולתכנן להדביק אחרי resume. לעבודה מתוזמנת כמו batch לילי אפשר גם להעיר את המחשב עם Wake the computer to run this task של Task Scheduler. עבודה שבאמת צריכה לרוץ ברציפות שייכת לשרת או ל-service שמוגדר לא להיכנס ל-Sleep.
למה חיבורי TCP ו-serial ports מפסיקים לעבוד אחרי resume?
כי גם network adapters והתקני USB יורדים למצב low power ב-Sleep. חיבור ה-TCP כבר נזרק על ידי הצד השני או על ידי timeout של NAT או firewall, ושליחה/קבלה אחרי resume מחזירה שגיאה (לעיתים שמים לב רק כשיש שגיאה). מתאמי USB-to-serial וכדומה מטופלים לפעמים כהסרה והכנסה מחדש של device ב-resume, וה-handle שהיה פתוח הופך ללא-תקף. בשני המקרים ההנחה הנכונה היא ש-handles וחיבורים לא שורדים מעבר ל-resume, והתשובה הנכונה היא לממש לוגיקת reconnect שבונה את החיבור מחדש ב-notification של resume או בשגיאת תקשורת. שילוב keepalive תקופתי עם retries ב-exponential backoff בכשל הוא הדפוס המקובל.
איך חוקרים Sleep לא צפוי או resume לא צפוי?
פקודת powercfg היא הכלי הראשון. בכיוון לא נכנס ל-Sleep, powercfg /requests מציג אילו processes ו-drivers הוציאו Power request שחוסם Sleep. בכיוון מתעורר מעצמו, powercfg /lastwake מציג את סיבת ה-wake האחרונה ו-powercfg /waketimers מציג timers ששמורים כרגע להעיר את המחשב. במחשב Modern Standby, powercfg /sleepstudy מייצר דוח צריכה ופעילות ב-Sleep. היסטוריית Sleep ו-resume נרשמת גם ב-Event Viewer (מקור Kernel-Power ביומן System), כך שאפשר לאשר בציר זמן מתי נכנס ל-Sleep, ומתי ולמה התעורר.

פרופיל הכותב

עמוד היכרות עם כותב המאמר.

Go Komura

מנהל KomuraSoft LLC

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

קישורים ציבוריים

חזרה לבלוג