אפליקציות שנשברות אחרי Sleep — power events ואיך לבנות אפליקציה עסקית ששורדת resume
· עודכן בתאריך: · Go Komura · 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 שנגרם מפעולת משתמש (זה מותנה) |
sequenceDiagram
accTitle: זרימת ה-notifications של Sleep ו-resume
accDescr: PBT_APMSUSPEND מגיע ממש לפני Sleep עם בערך 2 שניות חסד; ב-resume, PBT_APMRESUMEAUTOMATIC תמיד מגיע, ו-PBT_APMRESUMESUSPEND בא אחריו רק ב-resume ביוזמת משתמש
participant OS as OS
participant A as אפליקציה
OS->>A: PBT_APMSUSPEND (בערך 2 שניות חסד)
A->>A: שמירת state וסגירת חיבורים
Note over OS: Sleep (הקוד לא רץ)
OS->>A: PBT_APMRESUMEAUTOMATIC (מגיע ב-resume)
A->>A: reconnect ובניית state מחדש
OS->>A: PBT_APMRESUMESUSPEND (רק resume ביוזמת משתמש)
A->>A: עדכון מסך ועבודה אחרת שפונה למשתמש
איור 1: ה-notifications מסתכמים ב”מילה ממש לפני, ומילה או שתיים אחרי resume”. הטיפול בצד ה-resume הוא מה שמניע את השחזור.
ה-notification שלפני Sleep הוא הזדמנות “להתכונן אם יש זמן”
PBT_APMSUSPEND הוא ה-notification שמגיע ממש לפני הכניסה ל-Sleep. הוא מאפשר לסגור קבצים ולשמור state, אבל הוא מגיע עם שני האילוצים הבאים.
| אילוץ | השפעה על התכנון |
|---|---|
| חלון החסד הוא בערך 2 שניות לכל אפליקציה | מעבר לזמן הזה המערכת ממשיכה בלי לחכות לאפליקציה1 |
| emergency suspend לא נותן notification מוקדם | כשרמת הסוללה קריטית, למשל, המכונה נעצרת בלי כל הכנה2 |
לכן תכנון ש”תמיד מסיים לשמור אחרי קבלת ה-notification הזה” לא מחזיק. משתמשים ב-notification המוקדם כדי להתכונן במה שיש זמן, ואת עיקר השחזור שמים בצד ה-resume.
flowchart TB
accTitle: ההבדל בין Sleep רגיל ל-emergency suspend
accDescr: Sleep רגיל מעביר PBT_APMSUSPEND ממש לפני עם בערך 2 שניות להתכונן, אבל emergency suspend שנגרם מסוללה קריטית וכדומה נעצר בלי notification מוקדם, כך שתכנון שתלוי ב-notification המוקדם לא מחזיק
n2["Sleep רגיל"] --> pre["PBT_APMSUSPEND (בערך 2 שניות חסד)"]
pre --> s1["להתכונן, ואז לעצור"]
e2["emergency suspend (סוללה כמעט נגמרה)"] --> s2["עצירה בלי notification מוקדם"]
s2 -.-> l2["תכנון שמניח שה-notification יגיע לא מחזיק"]
איור 2: emergency suspend מגיע בלי אזהרה. לכן הכנה היא “בונוס אם היא מספיקה בזמן”, והעיקר הולך לצד ה-resume.
notifications של resume מפרידים שחזור מכני מעבודה שפונה למשתמש
ב-resume מ-suspend, PBT_APMRESUMEAUTOMATIC מגיע קודם. אם המכונה חזרה בגלל כפתור ההפעלה או הקשה, או אם נוכחות משתמש זוהתה אחרי resume, PBT_APMRESUMESUSPEND בא אחריו.67
לעומת זאת, ב-resume בלי משתמש כמו remote wake דרך הרשת או resume לתחזוקה, מגיע רק PBT_APMRESUMEAUTOMATIC. שחזור נדרש כמו בניית חיבורים מחדש שמים בראשון, ופעולות שפונות למשתמש כמו עדכון מסך או בקשת login מחדש בשני.6
flowchart TB
accTitle: פיצול עבודה בין שני שלבי ה-resume
accDescr: שמים שחזור מכני כמו reconnect ב-PBT_APMRESUMEAUTOMATIC, שמגיע ב-resume; שמים עבודה שפונה למשתמש כמו עדכון מסך או בקשת login מחדש ב-PBT_APMRESUMESUSPEND, שמגיע רק ב-resume ביוזמת משתמש
ra["PBT_APMRESUMEAUTOMATIC (ב-resume)"] --> m["שחזור מכני"]
rs["PBT_APMRESUMESUSPEND (resume ביוזמת משתמש)"] --> u["עבודה שפונה למשתמש"]
m -.-> m1["reconnect ופתיחה מחדש של handles"]
u -.-> u1["עדכון מסך ובקשת 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
flowchart TB
accTitle: ההבדל בין Sleep מסורתי ל-Modern Standby
accDescr: S3 Sleep מסורתי עוצר את כל המערכת, בעוד שתחת Modern Standby המערכת ממשיכה לרוץ לסירוגין אחרי שהמסך כבה. אפליקציות desktop מושהות על ידי DAM, עם זאת, כך שקוד האפליקציה לא רץ באף אחד מהמקרים
s3["S3 Sleep מסורתי: כל המערכת נעצרת"] --> conc["קוד האפליקציה לא רץ"]
ms["Modern Standby: המערכת רצה לסירוגין"] --> dam["אפליקציות desktop מושהות על ידי DAM"]
dam --> conc
איור 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.
flowchart TB
accTitle: שלושה צורות שבהן המשכיות הזמן נשברת
accDescr: עבודה מחזורית נעצרת ב-Sleep והירי אחרי resume שונה לפי API, לכן בונים מחדש את לוח הזמנים ב-resume; ההפרש מה-timestamp הקודם הופך ענק אחרי resume, לכן מגנים עליו; עבודה מתוזמנת לא רצה אם המכונה ישנה, לכן שוקלים wake-from-sleep של Task Scheduler
t1["עבודה מחזורית: נעצרת ב-Sleep"] -.-> g1["לבנות מחדש את לוח הזמנים ב-resume"]
t2["הפרש elapsed time: מתנפח"] -.-> g2["להגן מפני הפרשים חריגים"]
t3["עבודה מתוזמנת: ישנה, לא רצה"] -.-> g3["להעיר את המכונה עם הגדרת wake"]
איור 5: כותבים טיפול ב-timers ובשעון בהנחה ש”הזמן קופץ”. לכל אחת משלוש הצורות יש סוג טיפול משלה.
flowchart TB
accTitle: שלושה דברים שנשברים מעבר ל-Sleep
accDescr: מעבר ל-Sleep, חיבור TCP נזרק ב-timeout בצד השני, handle של התקן USB מתבטל כאילו חובר מחדש, ועבודה מבוססת elapsed time רואה קפיצת זמן ענקית. משחזרים כל אחד עם reconnect, פתיחה מחדש, והגנה על הפרש
sleep["מרווח Sleep"] --> tcp["חיבור TCP: נזרק על ידי הצד השני"]
sleep --> usb["התקן USB: handle בוטל"]
sleep --> time["elapsed time: קפיצה ענקית"]
tcp -.-> r1["לזהות את השגיאה ולעשות reconnect"]
usb -.-> r2["לפתוח את ה-device מחדש"]
time -.-> r3["להגן מפני הפרשים חריגים"]
איור 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.
flowchart TB
accTitle: תכנון reconnect ששורד resume
accDescr: notification ה-resume, שגיאת תקשורת וכשל keepalive כולם מתנקזים לאותה לוגיקת reconnect אידמפוטנטית, שמנסה מחדש עם exponential backoff בכשל
e1["notification resume (PBT_APMRESUMEAUTOMATIC)"] --> r["לוגיקת reconnect אידמפוטנטית"]
e2["זוהתה שגיאת תקשורת"] --> r
e3["כשל keepalive"] --> r
r --> ok{"הצליח?"}
ok -->|"כן"| run["חזרה להפעלה רגילה"]
ok -->|"לא"| back["ניסיון מחדש אחרי exponential backoff"]
back --> r
איור 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 |
| ביטול שנשכח הופך את המחשב לבלתי מסוגל לישון | תמיד מבטלים כשהעבודה מסתיימת |
flowchart TB
accTitle: שני אמצעים לדיכוי Sleep
accDescr: בין אם משתמשים ב-SetThreadExecutionState הנוח או ב-API של Power request שיכול לצרף מחרוזת סיבה והוא גלוי למנהל דרך powercfg, תמיד מבטלים כשהעבודה מסתיימת
need["מרווח עבודה שאסור לישון באמצעו"] --> a["SetThreadExecutionState"]
need --> b["Power request (PowerSetRequest)"]
a -.-> a1["נוח, רק flags"]
b -.-> b1["עם סיבה, גלוי ב-powercfg"]
a --> off["תמיד לבטל כשהעבודה מסתיימת"]
b --> off
איור 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; מיישרים את חותמות הזמן ומפרידים את הסיבה.
flowchart TB
accTitle: מיפוי סימפטומי תקלות הפעלה לפקודות חקירה
accDescr: לסימפטום לא-נכנס-ל-Sleep, מוצאים מי מחזיק Power request עם powercfg /requests; לסימפטום מתעורר-מעצמו, מוצאים את סיבת ה-wake עם /lastwake ו-/waketimers; לציר הזמן, משתמשים ב-Kernel-Power ב-event log
s1["לא נכנס ל-Sleep"] --> c1["powercfg /requests"]
s2["מתעורר מעצמו"] --> c2["powercfg /lastwake ו-/waketimers"]
s3["רוצים לבדוק את ציר הזמן"] --> c3["Kernel-Power ב-event log"]
c1 -.-> note["דיכוי 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.
מאמרים קשורים
- Pitfalls באפליקציות serial communication — reconnect ותכנון log
- Shutdown ב-Windows מנקודת המבט של האפליקציה — exit notifications, restart ו-power loss
- מהו Efficiency mode ב-Windows? — סמל העלה הירוק ואיך לכבות אותו
- למה Sleep(1) ב-Windows לא מדויק, ולמה עדיף event wait
- מה Not Responding באמת אומר — איך Windows מחליט שיש hang, ואיך לתכנן אפליקציות שלא נתקעות
תחומי ייעוץ קשורים
KomuraSoft LLC מטפלת בחקירת שורש של בעיות כמו “התקשורת נשברת אחרי resume מ-Sleep” ו”החיבור ל-device נופל אחרי הפסקת הצהריים”, בהתאמת לוגיקת reconnect וטיפול ב-power events לאפליקציות קיימות, ובסקירות תכנון של אפליקציות עסקיות ותוכנות בקרת ציוד שנבנו להפעלת laptop.
קישורים
-
Microsoft Learn, PBT_APMSUSPEND event. על כך שזה ה-event שמגיע ממש לפני שהמחשב נכנס למצב suspend; על כך שהאפליקציה אמורה לסיים את העבודה הנדרשת לשמירת נתונים; ועל כך שהמערכת מאפשרת בערך שתי שניות לטפל ב-notification זה, ואפליקציה שממשיכה מעבר לזה נתונה להפרעה. ↩ ↩2
-
Microsoft Learn, System Power Management Events. על כך שהמערכת משדרת מראש שינויי מצב הפעלה כמו Sleep; על כך ש-PBT_APMSUSPEND מגיע לפני idle Sleep כדי שאפשר יהיה להתכונן בסגירת קבצים ושמירת נתונים; על כך ש-emergency suspend (סוללה קריטית וכדומה) לא נותן notification מוקדם; על כך שטיפול בהודעה זו מותר לכל היותר בערך שתי שניות לאפליקציה ונחתך אחרי timeout; ועל כך שכל אפליקציה מקבלת notification ב-resume. ↩ ↩2 ↩3
-
Microsoft Learn, Prepare software for modern standby. על כך ש-Desktop Activity Moderator (DAM) משהה אפליקציות desktop בשלב הראשון של המעבר ל-Modern Standby; ועל כך שהמערכת אחר כך נעה בשלבים לשלב low power ולשלב resiliency, ורק רכיבים מותרים רצים לסירוגין. ↩ ↩2 ↩3
-
Microsoft Learn, SetThreadExecutionState function (winbase.h). על כך ש-ES_SYSTEM_REQUIRED ו-ES_DISPLAY_REQUIRED יכולים לדכא idle Sleep וכיבוי תצוגה; ועל הכרזת דיכוי רציף עם ES_CONTINUOUS וביטולו בקריאה ל-ES_CONTINUOUS לבדו כשמסיימים. ↩ ↩2
-
Microsoft Learn, PowerSetRequest function (winbase.h). על היכולת להגדיר סוג request כמו השארת מערכת או תצוגה ערות על אובייקט Power request שנוצר עם PowerCreateRequest; על היכולת לצרף מחרוזת סיבה אבחנתית; ועל כך ש-Power requests פתוחים ניתנים למנייה עם powercfg /requests. ↩ ↩2 ↩3
-
Microsoft Learn, PBT_APMRESUMESUSPEND event. על כך שזה נשלח אחרי PBT_APMRESUMEAUTOMATIC ב-resume ביוזמת משתמש או כשקלט משתמש מזוהה אחר כך; על כך שנשלח רק PBT_APMRESUMEAUTOMATIC ב-resume מסיבה חיצונית כמו remote wake; ועל כך שהאפליקציה אמורה לפתוח מחדש קבצים שנסגרו ב-Sleep ולהתכונן לקלט משתמש. ↩ ↩2
-
Microsoft Learn, WM_POWERBROADCAST message. על כך ש-PBT_APMRESUMEAUTOMATIC תמיד נשלח ב-resume, ו-PBT_APMRESUMESUSPEND נשלח גם ב-resume מקלט משתמש; על כך שההודעה לא מבדילה את סוג מצב ה-low power; על כך שפרטי מעברי power state נרשמים ב-Event Viewer של המערכת; ועל קריאה ל-SetThreadExecutionState כדי למנוע כניסה למצב low power. ↩ ↩2 ↩3
-
Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). על כך שזה ה-API שרושם לקבלת notifications של suspend/resume, ועל ציון DEVICE_NOTIFY_CALLBACK כדי שאפליקציה או service בלי window יוכלו לקבל את ה-notification דרך callback בנוסף למסירה ל-window. ↩ ↩2
-
Microsoft Learn, Modern standby SleepStudy. על כך שהדוח שמייצר powercfg /sleepstudy מאפשר לבדוק, לכל מרווח Modern Standby, צריכת חשמל, פעילות וסיבת ה-wake (כפתור הפעלה, קלט משתמש, wake timer וכן הלאה). ↩
מאמרים קשורים
מאמרים עדכניים עם אותן תגיות, להעמקה בנושאים קרובים.
למה arguments נשברים — כללי command-line arguments ב-Windows
Windows מעביר ל-CreateProcess מחרוזת אחת שהמקבל מפצל. מכסה את כללי CommandLineToArgvW, CRT ו-.NET, ArgumentList, ובניה ב-C++.
מה נשאר אחרי שה-parent מת — מחזיקים child processes ב-Job Object
למה SDK helpers שורדים UI שנהרג ומחזיקים את המצלמה או את ה-COM port? מתכננים משך חיים של child process עם Job Objects, KillOnJobClose ו-c...
Win32 Thread Pool API — מקביליות בלי CreateThread, דרך CreateThreadpoolWork
מפזרים קריאות CreateThread בכל הקוד ה-native? המאמר מסביר את ה-Win32 Thread Pool API שעוצב מחדש ב-Vista: ארבעת האובייקטים work, timer, wa...
Named Pipes בפועל — ה-IPC הסטנדרטי של Windows, מתכנון עד אבטחה
מדריך מעשי ל-Named Pipes, ה-IPC הסטנדרטי ב-Windows. המאמר מסדר לפי מקורות ראשוניים את הבחירה בין byte mode ל-message mode, תכנון server ל...
DllMain ו-loader lock — הסיבה האמיתית שאומרים לא לעשות כלום ב-initialization של DLL
למה אסור לקרוא ל-LoadLibrary או להסתנכרן עם threads מתוך DllMain. המאמר מסביר ממקורות ראשוניים איך loader lock מסדר כל DLL notification, ...
נושאים קשורים
העמודים האלה ממקמים את הנושא בהקשר רחב יותר של שירותים והחלטות.
נושאים טכניים ב-Windows
שער לנושאי פיתוח Windows, חקירת תקלות וניצול נכסים קיימים.
שירותים הקשורים לנושא הזה
המאמר קשור ישירות לשירותים הבאים.
פיתוח יישומי Windows
יישומים עסקיים, חיבור התקנים וכלי תקשורת, מהגדרת הדרישות ועד הפיתוח.
שאלות נפוצות
שאלות נפוצות בפניות בנושא המאמר.
- האם אפליקציה יכולה לדעת מראש שנכנסים ל-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, ומתי ולמה התעורר.