แอปที่พังเมื่อรีซูมจากสลีป — อีเวนต์พลังงานของ Windows ทำงานอย่างไร และสร้างแอปธุรกิจที่รอดได้อย่างไร
· Go Komura · Windows, การจัดการพลังงาน, การพัฒนา Windows, แอปธุรกิจ, การควบคุมอุปกรณ์, การแก้ปัญหา, Win32 API
“ฉันปิดแล็ปท็อป เปิดเช้าวันรุ่งขึ้น แล้วแอปธุรกิจเต็มไปด้วยข้อผิดพลาด” “แอปเฝ้าอุปกรณ์ทิ้งข้อมูลเฉพาะหลังอาหารกลางวัน” “เครื่องมือประจำเครื่องที่ส่งออกไป Excel บางครั้งหยุดด้วยข้อผิดพลาดการเชื่อมต่อ” — ตั๋วเหล่านี้มีผู้ต้องสงสัยคนเดียว สลีป
แอปธุรกิจจากยุคที่พีซีตั้งโต๊ะเป็นกระแสหลักถูกเขียนบนสมมติฐานที่ไม่พูดออกมาว่า “พีซีเปิดค้างอยู่” สนามหลักวันนี้คือแล็ปท็อป และโดยค่าเริ่มต้นมันสลีปหลังว่างไม่กี่นาที บนเครื่องที่รองรับ Modern Standby ความหมายของสลีปเองก็เปลี่ยนจากโมเดลดั้งเดิม มุ่งไปที่นักพัฒนาที่เขียนแอปธุรกิจและซอฟต์แวร์ควบคุมอุปกรณ์บน Windows บทความนี้จัดระเบียบจากแหล่งปฐมภูมิว่า OS แจ้งแอปอย่างไรก่อนและหลังสลีป อะไรพัง และจะเขียนแอปที่รอดตอนรีซูมได้อย่างไร
1. สรุปก่อนเลย
- สลีปคืออีเวนต์ที่แอป “ไม่มีสิทธิ์ปฏิเสธ” คุณถูกแจ้งก่อนหน้าเล็กน้อยด้วย
WM_POWERBROADCAST(PBT_APMSUSPEND) แต่ระยะผ่อนคือประมาณ 2 วินาที และในการระงับฉุกเฉินการแจ้งก็ไม่มาถึงด้วยซ้ำ12 - เมื่อรีซูมจากการระงับ PBT_APMRESUMEAUTOMATIC จะมาถึง และเมื่อรีซูมที่ผู้ใช้เป็นผู้เริ่ม PBT_APMRESUMESUSPEND จะมาถึงด้วย งานที่จำเป็น เช่น เชื่อมต่อใหม่ อยู่ในฝั่งแรกเป็นกฎ การเข้าและออกจากโหมดว่างพลังงานต่ำของ Modern Standby ไม่ได้เรียงกับแจ้งเหล่านี้เสมอ ดังนั้นให้ถือการแจ้งเป็นเครื่องช่วย34
- ออกแบบบนสมมติฐานว่าการเชื่อมต่อ TCP พอร์ตอนุกรม และแฮนเดิลอุปกรณ์ไม่รอดข้ามรีซูม ตรรกะเชื่อมต่อใหม่ที่สร้างพวกมันใหม่จากการแจ้งรีซูมหรือข้อผิดพลาดการสื่อสารคือเหตุการณ์หลัก
- ระวังตัวตั้งเวลาและการจัดการเวลา งานเป็นระยะหยุดระหว่างสลีป และวิธีที่ยิงทันทีหลังรีซูมต่างกันตาม timer API และรันไทม์ “การกระโดดมหาศาลของเวลาที่ผ่านไป” ก็เกิดเช่นกัน ดังนั้นแนวทางที่ปลอดภัยคือสร้างตารางใหม่ตอนรีซูม
- ยับยั้งสลีปอย่างชัดเจนสำหรับช่วงที่คุณไม่อยากให้สลีปผ่าน ใช้
SetThreadExecutionState(ES_SYSTEM_REQUIRED) หรือ power request (PowerSetRequest) และยกเลิกเสมอเมื่องานเสร็จ45 - บนเครื่อง Modern Standby ระบบยังรันเป็นช่วง ๆ ระหว่างสลีป แต่แอปเดสก์ท็อปถูกพัก คุณถือความคาดหวังว่า “แอปของเราควรรันต่อไประหว่างสลีป” ไม่ได้6
- เครื่องมือสอบสวนมาตรฐานคือ
powercfg(/requests, /lastwake, /sleepstudy) และ Kernel-Power ในล็อกอีเวนต์
2. สิ่งที่เกิดรอบสลีป — ลำดับอีเวนต์พลังงาน
OS กระจายการเปลี่ยนสถานะพลังงานไปยังทุกแอปเป็นข้อความ WM_POWERBROADCAST2 มีอีเวนต์หลักสามอย่างที่เกี่ยวข้องกับสลีปและรีซูม
| อีเวนต์ | ความหมาย |
|---|---|
| PBT_APMSUSPEND | กำลังจะเข้าสลีป (โอกาสสุดท้ายที่จะเตรียม) |
| PBT_APMRESUMEAUTOMATIC | รีซูมแล้ว (มาถึงเสมอตอนรีซูม) |
| PBT_APMRESUMESUSPEND | รีซูมที่เกิดจากการกระทำของผู้ใช้ (อันนี้มีเงื่อนไข) |
PBT_APMSUSPEND คือการแจ้งก่อนสลีปไม่กี่ขณะ และที่นี่คุณเตรียมได้ด้วยการปิดไฟล์และบันทึกสถานะ แต่มีสองเงื่อนไข ประการแรก เวลาที่อนุญาตให้ประมวลผลคือประมาณ 2 วินาทีต่อแอป และหากเกินระบบจะเดินต่อโดยไม่รอ1 ประการที่สอง ในการระงับฉุกเฉิน เช่น แบตเตอรี่ต่ำวิกฤต มันสลีปทันทีโดยไม่มีการแจ้งล่วงหน้า2 การออกแบบที่ “ต้องทำให้เสร็จก่อนสลีป” ไม่ตั้งอยู่ได้ ให้ถือการแจ้งเป็นโอกาสที่จะ “ทำถ้าทัน” และวางงานหลักไว้ฝั่งรีซูม
ฝั่งรีซูมมีสองขั้น PBT_APMRESUMEAUTOMATIC มาถึงเมื่อรีซูมจากการเปลี่ยนไประงับ นอกจากนั้น หากเครื่องรีซูมเพราะการกระทำของผู้ใช้ เช่น ปุ่มเปิดปิดหรือการกดแป้น (หรือตรวจพบว่ามีผู้ใช้อยู่ในภายหลัง) PBT_APMRESUMESUSPEND จะตามมา ในทางกลับกัน การรีซูมแบบไม่มีผู้ดูแลเพื่อปลุกจากระยะไกลผ่านเครือข่ายหรือเพื่อบำรุงรักษาส่งเฉพาะ PBT_APMRESUMEAUTOMATIC3 สองขั้นนี้เองเป็นคำใบ้ว่าจะแยกงานอย่างไร — ทำการกู้คืนเชิงกล เช่น สร้างการเชื่อมต่อใหม่บน PBT_APMRESUMEAUTOMATIC และทำการกระทำที่หันหน้าหาผู้ใช้ เช่น อัปเดตหน้าจอหรือพร้อมต์ล็อกอินใหม่บน PBT_APMRESUMESUSPEND
sequenceDiagram
accTitle: ลำดับการแจ้งสำหรับสลีปและรีซูม
accDescr: PBT_APMSUSPEND มาถึงก่อนสลีปไม่กี่ขณะพร้อมระยะผ่อนประมาณ 2 วินาที เมื่อรีซูม PBT_APMRESUMEAUTOMATIC มาถึงเสมอ และ PBT_APMRESUMESUSPEND ตามมาเฉพาะเมื่อรีซูมที่ผู้ใช้เป็นผู้เริ่ม
participant OS as OS
participant A as แอป
OS->>A: PBT_APMSUSPEND (ระยะผ่อนประมาณ 2 วินาที)
A->>A: บันทึกสถานะและปิดการเชื่อมต่อ
Note over OS: สลีป (โค้ดไม่รัน)
OS->>A: PBT_APMRESUMEAUTOMATIC (มาถึงตอนรีซูม)
A->>A: เชื่อมต่อใหม่และคืนสถานะ
OS->>A: PBT_APMRESUMESUSPEND (เฉพาะรีซูมที่ผู้ใช้เริ่ม)
A->>A: อัปเดตหน้าจอและงานที่หันหน้าหาผู้ใช้
ภาพ 1: การแจ้งเป็นเพียง “คำหนึ่งก่อนหน้าเล็กน้อย และอีกหนึ่งหรือสองคำหลังรีซูม” ดาวของการกู้คืนคืองานฝั่งรีซูม
flowchart TB
accTitle: ความต่างระหว่างสลีปธรรมดากับการระงับฉุกเฉิน
accDescr: สลีปธรรมดาส่ง PBT_APMSUSPEND ก่อนหน้าเล็กน้อยพร้อมเวลาเตรียมประมาณ 2 วินาที แต่การระงับฉุกเฉิน เช่น แบตเตอรี่วิกฤต หยุดโดยไม่มีการแจ้งล่วงหน้า ดังนั้นการออกแบบที่พึ่งการแจ้งล่วงหน้าจึงไม่ตั้งอยู่ได้
n2["สลีปธรรมดา"] --> pre["PBT_APMSUSPEND (ระยะผ่อนประมาณ 2 วินาที)"]
pre --> s1["เตรียม แล้วหยุด"]
e2["ระงับฉุกเฉิน (แบตเตอรี่ต่ำวิกฤต)"] --> s2["หยุดโดยไม่มีการแจ้งล่วงหน้า"]
s2 -.-> l2["การออกแบบที่สมมติว่าการแจ้งจะมาไม่ตั้งอยู่ได้"]
ภาพ 2: การระงับฉุกเฉินมาโดยไม่มีคำเตือน ดังนั้นการเตรียมคือ “โบนัสถ้าทัน” และงานหลักไปอยู่ฝั่งรีซูม
โปรดทราบว่า WM_POWERBROADCAST ไม่แยกชนิดของสถานะพลังงานต่ำ (สลีปกับไฮเบอร์เนต)4 นามธรรมที่ถูกสำหรับแอปคือถือว่าเป็นอีเวนต์ชนิดเดียว: “มันหยุด แล้วมันกลับมา” บริการที่ไม่มีหน้าต่างและแอปคอนโซลรับการแจ้งเดียวกันได้ด้วยการใช้ RegisterSuspendResumeNotification ในรูปคอลแบ็ก (DEVICE_NOTIFY_CALLBACK)7
flowchart TB
accTitle: การแยกงานข้ามสองขั้นของรีซูม
accDescr: วางการกู้คืนเชิงกล เช่น เชื่อมต่อใหม่ บน PBT_APMRESUMEAUTOMATIC ซึ่งมาถึงตอนรีซูม วางงานที่หันหน้าหาผู้ใช้ เช่น อัปเดตหน้าจอหรือพร้อมต์ล็อกอินใหม่ บน PBT_APMRESUMESUSPEND ซึ่งมาถึงเฉพาะเมื่อรีซูมที่ผู้ใช้เป็นผู้เริ่ม
ra["PBT_APMRESUMEAUTOMATIC (ตอนรีซูม)"] --> m["การกู้คืนเชิงกล"]
rs["PBT_APMRESUMESUSPEND (รีซูมที่ผู้ใช้เริ่ม)"] --> u["งานที่หันหน้าหาผู้ใช้"]
m -.-> m1["เชื่อมต่อใหม่และเปิดแฮนเดิลใหม่"]
u -.-> u1["อัปเดตหน้าจอและพร้อมต์ล็อกอินใหม่"]
ภาพ 3: อันหลังไม่มาถึงในการรีซูมแบบไม่มีผู้ดูแล ดังนั้นการวางการกู้คืนที่จำเป็นไว้ที่อันหลังจะพลาด
3. Modern Standby — ความหมายของ “สลีป” ได้เปลี่ยนไป
ข้อเท็จจริงสมัยใหม่อีกอย่างที่ต้องรับไว้คือ Modern Standby สลีป S3 แบบดั้งเดิมเป็นโมเดลเรียบง่ายที่ “หยุดระบบทั้งก้อน” สลีปบนเครื่อง Modern Standby เป็นโมเดลแบบสมาร์ตโฟนที่ระบบยังรันเป็นช่วง ๆ หลังหน้าจอดับ
สิ่งที่สำคัญสำหรับแอปธุรกิจที่นี่คือ แอปเดสก์ท็อปถูกพักโดย Desktop Activity Moderator (DAM) ที่ขั้นแรกของการเข้าสลีป6 ระบบเองยังรันเป็นครั้งคราวเพื่อให้เครือข่ายอยู่และรับการแจ้ง แต่คอมโพเนนต์ที่ได้ประโยชน์จากนั้นคือพวกที่เข้าร่วมกลไกนี้ — โค้ดแอปเดสก์ท็อปธรรมดาไม่รัน ดังนั้นจากมุมนักพัฒนา ข้อสรุปเหมือนกันทั้ง Modern Standby และ S3 — ออกแบบบนสมมติฐานว่า โค้ดของคุณไม่รันระหว่างสลีป
flowchart TB
accTitle: ความต่างระหว่างสลีปดั้งเดิมกับ Modern Standby
accDescr: สลีป S3 ดั้งเดิมหยุดระบบทั้งก้อน ในขณะที่ภายใต้ Modern Standby ระบบยังรันเป็นช่วง ๆ หลังหน้าจอดับ แอปเดสก์ท็อปถูกพักโดย DAM ในทั้งสองกรณี ดังนั้นโค้ดของแอปจึงไม่รัน
s3["สลีป S3 ดั้งเดิม: ระบบทั้งก้อนหยุด"] --> conc["โค้ดของแอปไม่รัน"]
ms["Modern Standby: ระบบรันเป็นช่วง ๆ"] --> dam["แอปเดสก์ท็อปถูกพักโดย DAM"]
dam --> conc
ภาพ 4: โมเดลเปลี่ยนแล้ว แต่สำหรับแอปเดสก์ท็อปข้อสรุปเหมือนกัน: “คุณรันระหว่างสลีปไม่ได้”
ข้อควรระวังอีกอย่างคือคุณพึ่งการแจ้งได้น้อยเพียงใด ภายใต้ Modern Standby การเข้าและออกจากโหมดว่างพลังงานต่ำไม่เรียงกับการเปลี่ยนไประงับแบบดั้งเดิม และการเชื่อมต่ออาจขาดไปแล้วโดยไม่มีการแจ้งมาถึงเลย ให้ถือการแจ้งรีซูมเป็นเครื่องช่วย และวางการเชื่อมต่อใหม่ที่ถูกกระตุ้นโดยการตรวจข้อผิดพลาด (บทที่ 5) ไว้บนเส้นทางกู้คืนหลัก
ความต่างอีกอย่างคือความรู้สึก “ลื่น” ของพฤติกรรม การถึงความลึกของสลีปเป็นขั้น ๆ และจังหวะของการตัดการเชื่อมต่อและการหยุดไม่คมเท่าภายใต้ S3 ความต่างระหว่าง “หน้าจอดับเฉย ๆ” กับ “มันสลีป” ผู้ใช้ก็เห็นยากเช่นกัน ดังนั้นเมื่อรับอาการ คุณต้องยืนยันว่า “เขาปิดฝาหรือไม่” และ “ปล่อยว่างกี่นาที”
4. อะไรพัง — อาการคลาสสิก
การเชื่อมต่อ TCP ตาย ระหว่างสลีป อีกฝั่ง NAT และไฟร์วอลล์ถือความเงียบของคุณเป็นหมดเวลาแล้วทิ้งการเชื่อมต่อ ที่แย่กว่า ซ็อกเก็ตฝั่งนี้ไม่รู้เรื่องข้อผิดพลาด ดังนั้นมันล้มเหลวเฉพาะเมื่อคุณส่งหรือรับหลังรีซูม หรือแย่กว่านั้น การรอรับไม่เคยเกิดข้อผิดพลาดเลย (นั่นคือเหตุที่คุณต้องการ keepalive) การเชื่อมต่อฐานข้อมูลและ WebSocket มีรูปเดียวกัน
แฮนเดิลพอร์ตอนุกรมและอุปกรณ์ USB กลายเป็นโมฆะ อุปกรณ์ที่ต่อ USB ตอนรีซูมอาจดูราวกับว่าถูก “ถอดแล้วเสียบกลับ” ครั้งหนึ่ง และแฮนเดิลที่คุณเปิดไว้เริ่มคืนข้อผิดพลาด นั่นคือรูปแบบทั่วไปของแอปควบคุมอุปกรณ์ที่ “ได้ข้อผิดพลาดการสื่อสารเฉพาะหลังอาหารกลางวัน” การออกแบบเชื่อมต่อใหม่ยังอยู่ในบทความเรื่องการสื่อสารอนุกรม
ความต่อเนื่องของเวลาขาด งานที่ขับด้วยตัวตั้งเวลา เช่น “โพลทุก 10 วินาที” ไม่ยิงระหว่างสลีป วิธีที่ยิงทันทีหลังรีซูม (งานที่หมดอายุยิงทันทีครั้งหนึ่ง ไม่เกิดอะไรจนกว่าคาบถัดไป เป็นต้น) ต่างกันตาม timer API และรันไทม์ที่คุณใช้ ดังนั้นอย่าปล่อยการจัดการติ๊กที่พลาดให้พฤติกรรมโดยนัย — แนวทางที่ปลอดภัยคือสร้างตารางใหม่จากการแจ้งรีซูม นอกจากนี้ การคำนวณเวลาที่ผ่านไป (ผลต่างจากตราประทับเวลาก่อนหน้า) กลายเป็น “มูลค่า 8 ชั่วโมง” ทันที และการคำนวณค่าเฉลี่ยหรือการตัดสินหมดเวลาพัง งานตามตาราง เช่น “รันทุกคืนตีสอง” เพียงแค่ไม่รันหากพีซีสลีปอยู่เวลานั้น (ปลุกด้วยฟีเจอร์ปลุกจากสลีปของ Task Scheduler หากต้องการ)
flowchart TB
accTitle: สามรูปที่ความต่อเนื่องของเวลาขาด
accDescr: งานเป็นระยะหยุดระหว่างสลีป และการยิงหลังรีซูมต่างกันตาม API จึงสร้างตารางใหม่ตอนรีซูม ผลต่างจากตราประทับเวลาก่อนหน้ากลายเป็นมหาศาลหลังรีซูม จึงต้องกันไว้ งานตามตารางไม่รันหากเครื่องสลีป จึงพิจารณาการปลุกจากสลีปของ Task Scheduler
t1["งานเป็นระยะ: หยุด"] -.-> g1["สร้างตารางใหม่"]
t2["เวลาที่ผ่านไป: พอง"] -.-> g2["กันผลต่างผิดปกติ"]
t3["ตามตาราง: ไม่เคยรัน"] -.-> g3["ปลุกจากสลีป"]
g1 ~~~ t2
g2 ~~~ t3
ภาพ 5: เขียนการจัดการตัวตั้งเวลาและเวลาบนสมมติฐานว่า “เวลากระโดด” ทั้งสามรูปมีชนิดของมาตรการ
flowchart TB
accTitle: สามสิ่งที่พังข้ามสลีป
accDescr: ข้ามสลีป การเชื่อมต่อ TCP ถูกทิ้งโดยหมดเวลาฝั่งตรงข้าม แฮนเดิลอุปกรณ์ USB ถูกทำให้โมฆะเป็นการเชื่อมต่อใหม่ และงานตามเวลาที่ผ่านไปสังเกตการกระโดดของเวลาที่มหาศาล กู้แต่ละอย่างด้วยเชื่อมต่อใหม่ เปิดใหม่ และการกันผลต่าง
sleep["ช่วงสลีป"] --> tcp["TCP: คู่สื่อสารทิ้งไป"]
sleep --> more{"USB หรือเวลาที่ผ่านไป?"}
more --> usb["USB: แฮนเดิลโมฆะ"]
more --> time["เวลาที่ผ่านไป: กระโดด"]
tcp -.-> r1["ตรวจจับ + เชื่อมต่อใหม่"]
usb -.-> r2["เปิดอุปกรณ์ใหม่"]
time -.-> r3["กันผลต่างผิดปกติ"]
ภาพ 6: สิ่งที่พังตกเป็นสามตระกูล — “การเชื่อมต่อ” “แฮนเดิล” และ “ความต่อเนื่องของเวลา” — และแต่ละอย่างมีชนิดการกู้คืนที่ลงตัว
การยืนยันตัวตนใหม่ต่อทรัพยากรที่ใช้ร่วม ไดรฟ์เครือข่ายและ VPN มักต้องถูกสร้างใหม่หลังรีซูม และมี “หุบเขาตอนเริ่ม” ไม่กี่วินาทีถึงหลายสิบวินาทีทันทีหลังรีซูมที่การเข้าถึงล้มเหลว จะปลอดภัยกว่าหากไม่ลองทุกอย่างพร้อมกันทันทีหลังรีซูม แต่รอนิดแล้วลองใหม่เป็นขั้น
5. สร้างแอปที่รอดตอนรีซูม
หลักการมีอย่างเดียว สมมติว่า “การเชื่อมต่อและแฮนเดิลไม่รอดข้ามสลีป” และจัดโครงสร้างแอปให้คุณกู้คืนได้เสมอ
ตรวจรีซูมแล้วกู้คืน เมื่อ WM_POWERBROADCAST ของหน้าต่างระดับบนรับ PBT_APMRESUMEAUTOMATIC ให้ทิ้งการเชื่อมต่อที่ถืออยู่แล้วสร้างใหม่ จุดสำคัญคืออย่าพึ่งการแจ้งรีซูมอย่างเดียว การแจ้งที่พลาดและการสื่อสารที่เกิดก่อนการแจ้งเป็นเรื่องจริง ดังนั้นจับคู่เสมอกับเส้นทางที่ “เชื่อมต่อใหม่เมื่อตรวจพบข้อผิดพลาดการสื่อสาร” และถือการแจ้งรีซูมเป็นตัวกระตุ้นที่เพียงเริ่มสิ่งนั้นเร็วขึ้น
// C#: funnel both the resume notification and communication errors into the same reconnect path
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(); // idempotent reconnect request
}
base.WndProc(ref m);
}
ทำให้งานเชื่อมต่อใหม่เองidempotent (ปลอดภัยไม่ว่าจะถูกเรียกกี่ครั้ง) ลองใหม่เมื่อล้มเหลวด้วย exponential backoff และในสถานะคงที่ตรวจการเชื่อมต่อที่ตายแต่เนิ่นด้วย keepalive — รวมสามอย่างนั้นเป็นชุด แล้วคุณจะรอดไม่เฉพาะรีซูมจากสลีป แต่ยังรอดการหลุดเครือข่ายสั้น ๆ หรือการรีบูตอุปกรณ์
flowchart TB
accTitle: การออกแบบเชื่อมต่อใหม่ที่ทนรีซูม
accDescr: การแจ้งรีซูม ข้อผิดพลาดการสื่อสาร และความล้มเหลวของ keepalive ทั้งหมดไหลเข้าสู่งานเชื่อมต่อใหม่ idempotent เดียวกัน ซึ่งลองใหม่ด้วย exponential backoff เมื่อล้มเหลว
e1["การแจ้งรีซูม (PBT_APMRESUMEAUTOMATIC)"] --> r["งานเชื่อมต่อใหม่แบบ idempotent"]
e2["การตรวจข้อผิดพลาดการสื่อสาร"] --> r
e3["ความล้มเหลวของ keepalive"] --> r
r --> ok{"สำเร็จ?"}
ok -->|"ใช่"| run["กลับสู่การทำงานปกติ"]
ok -->|"ไม่"| back["ลองใหม่หลัง exponential backoff"]
back --> r
ภาพ 7: รวมการเชื่อมต่อใหม่เข้าสู่เส้นทาง idempotent เส้นเดียว และเข้าถนนเดียวกันจากการแจ้งรีซูม การตรวจข้อผิดพลาด หรือ keepalive
ทบทวนการจัดการเวลา สำหรับงานที่ใช้ “เวลาที่ผ่านไปตั้งแต่ครั้งก่อน” ให้ใส่การกันที่ทำให้ช่วงเวลาเป็นโมฆะเมื่อตรวจพบผลต่างที่ใหญ่ผิดปกติ (อย่าพับเข้าค่าเฉลี่ย อย่าถือเป็นหมดเวลา) การวัดเวลาที่ผ่านไปข้ามรีซูมต้องคงความต่างระหว่างนาฬิกาที่เดินระหว่างสลีป (เวลาตามกำแพง) กับเวลาที่ใช้ทำงานจริง
ยับยั้งสลีปอย่างชัดเจนสำหรับช่วงที่คุณไม่อยากให้สลีปผ่าน ระหว่างงานที่ห้ามถูกสลีปผ่าน — การย้ายข้อมูล การสื่อสารต่อเนื่องกับอุปกรณ์ เป็นต้น — คุณให้ระบบตื่นอยู่ได้ด้วย SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) (เพิ่ม ES_DISPLAY_REQUIRED หากอยากให้หน้าจอติดด้วย)45 วิธีที่มีมารยาทกว่าคือ power-request API (PowerCreateRequest + PowerSetRequest) ซึ่งแนบสตริงเหตุผลได้ และ powercfg /requests จะแสดง “ใครกำลังบล็อกและทำไม”8 โปรดทราบว่าการยับยั้งผ่าน SetThreadExecutionState เป็นรายเธรด และคุณยกเลิกจากเธรดเดียวกันที่ตั้งไว้ สำหรับงานที่เปลี่ยนเธรด เช่น async/await ให้ใช้ฝั่ง power request ซึ่งจัดการด้วยแฮนเดิล มีข้อควรระวัง ประการแรก สิ่งที่เหล่านี้ยับยั้งคือสลีปอัตโนมัติเมื่อว่าง พวกมันหยุดการกระทำที่ชัดเจนของผู้ใช้ เช่น ปิดฝาหรือเลือก Sleep จากเมนูเริ่มต้นไม่ได้ ดังนั้นคุณข้ามการออกแบบเชื่อมต่อใหม่ของบทนี้ไม่ได้แม้ขณะกำลังยับยั้ง ประการที่สอง บนแบตเตอรี่บนเครื่อง Modern Standby power request เหล่านี้ยังถูกตัดหลังหมดเวลาสลีปผ่านไปสักพัก งานที่ห้ามถูกขัดจังหวะต้องถูกรับประกันด้วยไฟ AC หรือด้วยการปฏิบัติการ8 ประการที่สาม ยกเลิกเสมอเมื่องานเสร็จ การลืมยกเลิกกลายเป็นบั๊กใหม่: “พีซีเครื่องนี้ ไม่รู้ทำไม ไม่ยอมสลีป”
flowchart TB
accTitle: สองวิธียับยั้งสลีป
accDescr: ไม่ว่าคุณจะใช้ SetThreadExecutionState ที่สะดวก หรือ power-request API ที่แนบสตริงเหตุผลได้และผู้ดูแลเห็นผ่าน powercfg ให้ยกเลิกเสมอเมื่องานจบ
need["ช่วงงานที่ห้ามถูกสลีปผ่าน"] --> a["SetThreadExecutionState"]
need --> b["Power request (PowerSetRequest)"]
a -.-> a1["สะดวก — แฟล็กอย่างเดียว"]
b -.-> b1["มีเหตุผล — เห็นใน powercfg"]
a --> off["ยกเลิกเสมอเมื่องานจบ"]
b --> off
ภาพ 8: สำหรับทั้งสองวิธี “ยกเลิกเมื่อเสร็จ” คือเงื่อนไขเด็ดขาด Power request ที่ทำให้เหตุผลมองเห็นได้ใจดีต่อการปฏิบัติการมากกว่า
บริการและแอปที่ไม่มีหน้าต่าง รับการแจ้งแบบคอลแบ็กด้วย RegisterSuspendResumeNotification (DEVICE_NOTIFY_CALLBACK)7 หากการทำงานต่อเนื่องเป็นข้อกำหนดจริง คำตอบรากคือทบทวนการออกแบบที่ให้งานประจำอยู่บนพีซีไคลเอนต์ที่สลีป แล้วย้ายไปฝั่งเซิร์ฟเวอร์หรือเครื่องที่ปฏิบัติการโดยไม่สลีป
6. การสอบสวน — powercfg และล็อกอีเวนต์
การสอบสวนรอบพลังงานใช้เครื่องมือที่มากับ OS ได้ดี
- มันไม่ยอมสลีป:
powercfg /requestsแสดงโปรเซสและไดรเวอร์ที่ออก power request “แอปลืมยกเลิกSetThreadExecutionState” ปรากฏที่นี่ด้วย - มันตื่นเอง:
powercfg /lastwakeแสดงเหตุผลตื่นล่าสุด และpowercfg /waketimersแสดงตัวตั้งเวลาที่จองไว้เพื่อปลุกเครื่อง - คุณภาพ Modern Standby:
powercfg /sleepstudyสร้างรายงานการบริโภคพลังงานและกิจกรรมต่อช่วงสลีป9 - ยืนยันไทม์ไลน์: แหล่ง Kernel-Power ในล็อกอีเวนต์ (System) เก็บบันทึกการเข้าสลีปและการรีซูม การจับคู่กับล็อกของแอปให้คุณยืนยันอย่างเป็นกลางว่า “มีการรีซูมก่อนข้อผิดพลาดไม่กี่ขณะ”
flowchart TB
accTitle: การแมปอาการปัญหาพลังงานกับคำสั่งสอบสวน
accDescr: สำหรับอาการไม่ยอมสลีป หาว่าใครถือ power request ด้วย powercfg /requests สำหรับอาการตื่นเอง หาเหตุผลตื่นด้วย /lastwake และ /waketimers สำหรับไทม์ไลน์ ใช้ Kernel-Power ในล็อกอีเวนต์
s1["มันไม่ยอมสลีป"] --> c1["powercfg /requests"]
s2["มันตื่นเอง"] --> c2["powercfg /lastwake และ /waketimers"]
s3["อยากยืนยันไทม์ไลน์"] --> c3["Kernel-Power ในล็อกอีเวนต์"]
c1 -.-> note["การยับยั้งสลีปที่ลืมก็ปรากฏด้วย"]
ภาพ 9: อาการแมปกับคำสั่งสอบสวนเป็นสามตระกูล ยืนยันก่อนว่า “เพิ่งสลีปหรือไม่” แล้วจึงแยก
ในการจัดการตั๋ว การถามก่อนว่า “พีซีสลีปอยู่ก่อนหน้าเล็กน้อยหรือไม่ (เขาปิดฝาหรือไม่)” เร่งการแยกสาขามาก
7. สรุป
- สลีปปฏิเสธไม่ได้ การแจ้งล่วงหน้า (PBT_APMSUSPEND) เป็น best-effort พร้อมระยะผ่อนประมาณ 2 วินาที และไม่มาในกรณีฉุกเฉิน วางการออกแบบหลักไว้ฝั่งรีซูม
- การแจ้งรีซูมคือ PBT_APMRESUMEAUTOMATIC (ตอนรีซูมจากการระงับ) + PBT_APMRESUMESUSPEND (เมื่อผู้ใช้กระทำ) คงการเชื่อมต่อใหม่ที่ขับด้วยข้อผิดพลาดไว้บนเส้นทางหลักสำหรับกรณีที่การแจ้งไม่มาถึง
- สมมติว่าการเชื่อมต่อและแฮนเดิลไม่รอดข้ามรีซูม และอิมพลีเมนต์ชุดสามชิ้นของการเชื่อมต่อใหม่แบบ idempotent + exponential backoff + keepalive
- ใส่การกัน “ผลต่างผิดปกติ” บนกิจตามเวลาที่ผ่านไป ออกแบบงานตามตารางบนสมมติฐานว่ามันไม่รันระหว่างสลีป
- สำหรับช่วงที่ห้ามถูกสลีปผ่าน ให้ยับยั้งสลีปอย่างชัดเจนด้วย
SetThreadExecutionStateหรือ power request และยกเลิกเสมอเมื่อเสร็จ - การสอบสวนคือ
powercfg(/requests, /lastwake, /sleepstudy) และล็อกอีเวนต์ Kernel-Power ในการจัดการตั๋ว ให้ถามก่อนว่า “เพิ่งสลีปหรือไม่”
จากมุมของแอป สลีปคืออีเวนต์ที่ “เวลากระโดดโดยไม่มีคำเตือน การเชื่อมต่อไปยังสภาพแวดล้อมถูกตัด แล้วมันกลับมา” ว่าคุณได้ถักสิ่งนั้นเข้าไปในการออกแบบเป็นส่วนหนึ่งของชีวิตประจำวัน แทนที่จะเป็นสถานการณ์ผิดปกติ คือสิ่งที่แยกความเสถียรของแอปธุรกิจในยุคแล็ปท็อป
บทความที่เกี่ยวข้อง
- กับดักของแอปสื่อสารอนุกรม - ผ่านการเชื่อมต่อใหม่และการออกแบบล็อก
- Windows Shutdown จากมุมของแอป — รอดจากการแจ้งออก รีสตาร์ต และการตัดไฟอย่างถูกต้อง
- โหมดประสิทธิภาพของ Windows คืออะไร? - ไอคอนใบไม้เขียวและวิธีปิด
- ทำไมบน Windows จึงควรใช้การรออีเวนต์มากกว่า Sleep(1)
- “ไม่ตอบสนอง” คืออะไรจริง ๆ — Windows ตัดสินว่าแอปแฮงอย่างไร และออกแบบอย่างไรให้ไม่แฮง
ด้านให้คำปรึกษาที่เกี่ยวข้อง
KomuraSoft LLC รับการสอบสวนหาสาเหตุของบั๊ก เช่น “การสื่อสารขาดหลังรีซูมจากสลีป” และ “การเชื่อมต่อกับอุปกรณ์หลุดหลังอาหารกลางวัน” การต่อตรรกะเชื่อมต่อใหม่และการจัดการอีเวนต์พลังงานเข้ากับแอปที่มีอยู่ และการตรวจทานการออกแบบของแอปธุรกิจและซอฟต์แวร์ควบคุมอุปกรณ์ที่สมมติการปฏิบัติการบนแล็ปท็อป
- การตรวจสอบบั๊กและวิเคราะห์หาสาเหตุที่แท้จริง
- การพัฒนาแอปพลิเคชัน Windows
- ที่ปรึกษาด้านเทคนิคและการตรวจทานการออกแบบ
- ติดต่อเรา
ลิงก์อ้างอิง
-
Microsoft Learn, PBT_APMSUSPEND event. ว่าด้วยนี่คืออีเวนต์ที่มาถึงก่อนคอมพิวเตอร์เข้าสู่สถานะระงับไม่กี่ขณะ ว่าด้วยแอปถูกคาดหวังให้ทำงานที่จำเป็นเพื่อบันทึกข้อมูลให้เสร็จ และว่าด้วยระบบอนุญาตประมาณ 2 วินาทีเพื่อจัดการการแจ้งนี้ โดยแอปที่ทำต่อเกินนั้นอาจถูกขัดจังหวะ ↩ ↩2
-
Microsoft Learn, System Power Management Events. ว่าด้วยระบบกระจายการเปลี่ยนโหมดการทำงาน เช่น สลีป ล่วงหน้า ว่าด้วย PBT_APMSUSPEND ถูกแจ้งก่อนสลีปเมื่อว่างเพื่อให้คุณเตรียมด้วยการปิดไฟล์และบันทึกข้อมูล ว่าด้วยการระงับฉุกเฉิน (แบตเตอรี่วิกฤต เป็นต้น) ไม่ให้การแจ้งล่วงหน้า ว่าด้วยการจัดการข้อความนี้ได้รับอนุญาตสูงสุด 2 วินาทีต่อแอปและถูกตัดหลังหมดเวลา และว่าด้วยทุกแอปถูกแจ้งตอนรีซูม ↩ ↩2 ↩3
-
Microsoft Learn, PBT_APMRESUMESUSPEND event. ว่าด้วยสิ่งนี้ถูกส่งหลัง PBT_APMRESUMEAUTOMATIC เมื่อรีซูมที่ผู้ใช้เป็นผู้เริ่มหรือเมื่อตรวจพบอินพุตของผู้ใช้ในภายหลัง ว่าด้วยมีเพียง PBT_APMRESUMEAUTOMATIC ถูกส่งสำหรับการรีซูมจากสาเหตุภายนอก เช่น การปลุกจากระยะไกล และว่าด้วยแอปถูกคาดหวังให้เปิดไฟล์ที่ปิดตอนสลีปใหม่และเตรียมสำหรับอินพุตของผู้ใช้ ↩ ↩2
-
Microsoft Learn, WM_POWERBROADCAST message. ว่าด้วย PBT_APMRESUMEAUTOMATIC ถูกส่งเสมอตอนรีซูม โดย PBT_APMRESUMESUSPEND ถูกส่งด้วยเมื่อรีซูมจากอินพุตของผู้ใช้ ว่าด้วยข้อความนี้ไม่แยกชนิดของสถานะพลังงานต่ำ ว่าด้วยรายละเอียดของการเปลี่ยนสถานะพลังงานถูกบันทึกในล็อกอีเวนต์ของระบบ และว่าด้วยการเรียก SetThreadExecutionState เพื่อกันระบบไม่ให้เข้าสู่สถานะพลังงานต่ำ ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, SetThreadExecutionState function (winbase.h). ว่าด้วย ES_SYSTEM_REQUIRED และ ES_DISPLAY_REQUIRED สามารถยับยั้งสลีปเมื่อว่างของระบบและการปิดพลังงานจอได้ และว่าด้วยการประกาศการยับยั้งต่อเนื่องด้วย ES_CONTINUOUS และการยกเลิกด้วยการเรียก ES_CONTINUOUS อย่างเดียวเมื่อเสร็จ ↩ ↩2
-
Microsoft Learn, Prepare software for modern standby. ว่าด้วย Desktop Activity Moderator (DAM) พักแอปเดสก์ท็อปที่ขั้นแรกของการเปลี่ยนเข้าสู่ Modern Standby และว่าด้วยระบบจากนั้นเคลื่อนเป็นขั้นเข้าสู่เฟสพลังงานต่ำและเฟสความยืดหยุ่น โดยมีเพียงคอมโพเนนต์ที่อนุญาตที่รันเป็นช่วง ๆ ↩ ↩2
-
Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). ว่าด้วยนี่คือ API ที่ลงทะเบียนเพื่อรับการแจ้งระงับ/รีซูม และว่าด้วยการระบุ DEVICE_NOTIFY_CALLBACK เพื่อให้แอปหรือบริการที่ไม่มีหน้าต่างรับการแจ้งผ่านคอลแบ็กได้ นอกจากการส่งข้อความไปยังแฮนเดิลหน้าต่าง ↩ ↩2
-
Microsoft Learn, PowerSetRequest function (winbase.h). ว่าด้วยสามารถตั้งชนิดคำขอ เช่น ให้ระบบหรือจอตื่นอยู่ บนออบเจ็กต์ power request ที่สร้างด้วย PowerCreateRequest ว่าด้วยสามารถแนบสตริงเหตุผลสำหรับวินิจฉัยได้ และว่าด้วย power request ที่ค้างสามารถแจกแจงด้วย powercfg /requests ↩ ↩2
-
Microsoft Learn, Modern standby SleepStudy. ว่าด้วยรายงานที่สร้างโดย powercfg /sleepstudy ให้คุณตรวจ ต่อช่วง Modern Standby การบริโภคพลังงาน กิจกรรม และเหตุผลตื่น (ปุ่มเปิดปิด อินพุตของผู้ใช้ ตัวตั้งเวลาปลุก เป็นต้น) ↩
บทความที่เกี่ยวข้อง
บทความล่าสุดที่มีแท็กเดียวกัน เพื่อเจาะลึกหัวข้อใกล้เคียง
DllMain และ Loader Lock — เหตุผลจริงที่ถูกบอกให้ "อย่าทำอะไรในการเริ่มต้น DLL"
ทำไมคุณต้องไม่เรียก LoadLibrary หรือซิงโครไนซ์กับเธรดอื่นจาก DllMain บทความนี้อธิบายจากแหล่งปฐมภูมิว่า loader lock ทำให้การแจ้ง DLL ทุกคร...
"ไม่ตอบสนอง" คืออะไรจริง ๆ — Windows ตัดสินว่าแอปแฮงอย่างไร และออกแบบอย่างไรให้ไม่แฮง
"ไม่ตอบสนอง" ของ Windows คือกลไกที่ OS ตัดสินว่าหน้าต่างไม่ได้ดึงข้อความเป็นเวลา 5 วินาทีแล้วแทนที่ด้วยหน้าต่างโกสต์ บทความนี้ครอบคลุมภาย...
Win32 Thread Pool API — คอนเคอร์เรนซีโดยไม่สร้างเธรดเอง ด้วย CreateThreadpoolWork
โค้ดเนทีฟของคุณกระจายการเรียก CreateThread ไปทั่วหรือไม่ บทความนี้อธิบาย Win32 thread pool API ที่ออกแบบใหม่ใน Vista — ออบเจ็กต์สี่ชนิด w...
Named Pipe ในทางปฏิบัติ — IPC มาตรฐานของ Windows ตั้งแต่การออกแบบถึงความปลอดภัย
คู่มือเชิงปฏิบัติเรื่อง named pipe ซึ่งเป็นการสื่อสารระหว่างโปรเซสมาตรฐานของ Windows บทความนี้จัดระเบียบจากแหล่งปฐมภูมิ ทั้งการเลือกระหว่...
Spurious Wakeup — ทำไม condition variable จึงตื่น "โดยไม่ถูกแจ้ง" และวิธีรออย่างถูกต้องบน Windows
การรอของ condition variable สามารถกลับได้แม้ไม่มีการแจ้งมาถึง (spurious wakeup) บทความนี้อธิบายจากการอิมพลีเมนต์ของ Windows ว่าทำไมข้อกำห...
หัวข้อที่เกี่ยวข้อง
หน้าเหล่านี้วางหัวข้อไว้ในบริบทที่กว้างขึ้นของบริการและการตัดสินใจ
หัวข้อเทคนิคของ Windows
ประตูสู่การพัฒนา Windows การตรวจสอบบั๊ก และการใช้ประโยชน์จากสินทรัพย์เดิม
บริการที่เกี่ยวข้องกับหัวข้อนี้
บทความนี้เกี่ยวข้องโดยตรงกับบริการต่อไปนี้
พัฒนาแอป Windows
แอปธุรกิจ การเชื่อมต่ออุปกรณ์ และเครื่องมือสื่อสาร ตั้งแต่ความต้องการจนถึงการพัฒนา
คำถามที่พบบ่อย
คำถามที่มักพบในการปรึกษาเกี่ยวกับหัวข้อของบทความนี้
- แอปเรียนรู้เรื่องสลีปล่วงหน้าแล้วปฏิเสธได้หรือไม่
- บน Windows ปัจจุบันคุณรับการแจ้งได้ แต่ปฏิเสธไม่ได้ ก่อนสลีปไม่กี่ขณะ ข้อความ WM_POWERBROADCAST ส่งอีเวนต์ PBT_APMSUSPEND และที่นี่คุณเตรียมได้ด้วยการปิดไฟล์และบันทึกสถานะ แต่เวลาที่อนุญาตให้ประมวลผลคือประมาณ 2 วินาทีต่อแอป และหากเกินระบบจะเดินต่อโดยไม่รอ ในการระงับฉุกเฉิน เช่น แบตเตอรี่ต่ำวิกฤต การแจ้งล่วงหน้าเองก็ไม่มา การออกแบบที่ "ต้องทำให้เสร็จก่อนสลีป" จึงไม่ตั้งอยู่ได้ คุณต้องการการออกแบบที่กู้คืนตอนรีซูมได้ไม่ว่าจะถูกตัดเมื่อใด สำหรับช่วงงานที่คุณไม่อยากให้สลีปผ่านจริง ๆ ให้ยับยั้งสลีปอย่างชัดเจนด้วย SetThreadExecutionState หรือ power request (PowerSetRequest)
- จะตรวจได้อย่างไรว่าเครื่องรีซูมแล้ว
- หากแอปมีหน้าต่าง ให้จัดการ WM_POWERBROADCAST เมื่อรีซูมจากการระงับ PBT_APMRESUMEAUTOMATIC จะมาถึง และหากการรีซูมเกิดจากการกระทำของผู้ใช้ (ปุ่มเปิดปิดหรือการกดแป้น) PBT_APMRESUMESUSPEND จะตามมา การรีซูมแบบไม่มีผู้ดูแลที่กลับไปสลีปทันทีส่งเฉพาะ PBT_APMRESUMEAUTOMATIC ดังนั้นการแยกพื้นฐานคือวางงานที่จำเป็น เช่น เชื่อมต่อใหม่ ไว้ฝั่ง PBT_APMRESUMEAUTOMATIC และงานที่หันหน้าหาผู้ใช้ เช่น อัปเดตหน้าจอ ไว้ฝั่ง PBT_APMRESUMESUSPEND บริการที่ไม่มีหน้าต่างและแอปคอนโซลรับการแจ้งเดียวกันผ่านคอลแบ็กได้ด้วย RegisterSuspendResumeNotification คู่กับ DEVICE_NOTIFY_CALLBACK
- ฉันให้แอปรันต่อไประหว่างสลีปได้หรือไม่
- ตามกฎแล้วไม่ได้ ระหว่างสลีป การรันของ CPU เองหยุด (บนเครื่อง Modern Standby แอปเดสก์ท็อปถูกพักโดย Desktop Activity Moderator) และโค้ดของแอปไม่รัน มีสองทางเลือก หนึ่งคือยับยั้งสลีปเฉพาะขณะงานกำลังดำเนิน การระบุ ES_SYSTEM_REQUIRED กับ SetThreadExecutionState หรือออก power request ด้วย PowerCreateRequest/PowerSetRequest จะยับยั้งสลีปอัตโนมัติเมื่อว่างในช่วงนั้น (ยืนยันได้ด้วย powercfg /requests) นั่นยังหยุดการสลีปที่ชัดเจน เช่น ผู้ใช้ปิดฝาไม่ได้ ดังนั้นคุณยังต้องพร้อมสำหรับรีซูมแม้ขณะกำลังยับยั้ง อีกทางคือยอมรับสลีปแล้วออกแบบให้ "ตามให้ทันหลังรีซูม" สำหรับงานตามตาราง เช่น แบตช์กลางคืน คุณยังปลุกพีซีด้วย "ปลุกคอมพิวเตอร์เพื่อรันงานนี้" ของ Task Scheduler ได้ งานที่ต้องรันต่อเนื่องจริง ๆ อยู่ในเซิร์ฟเวอร์หรือบริการที่ตั้งค่าไม่ให้สลีป
- ทำไมการเชื่อมต่อ TCP และพอร์ตอนุกรมจึงหยุดทำงานหลังรีซูม
- เพราะอะแดปเตอร์เครือข่ายและอุปกรณ์ USB ก็ลงสู่สถานะพลังงานต่ำระหว่างสลีปเช่นกัน การเชื่อมต่อ TCP ถูกทิ้งไปแล้วโดยอีกฝั่งหรือโดยหมดเวลาของ NAT หรือไฟร์วอลล์ และการส่ง/รับหลังรีซูมคืนข้อผิดพลาด (คุณมักไม่รู้จนกว่าจะเกิดข้อผิดพลาด) อะแดปเตอร์ USB-to-serial และคล้ายกันบางครั้งถูกจัดการเป็นการถอดและเสียบอุปกรณ์ใหม่ตอนรีซูม และแฮนเดิลที่คุณเปิดไว้กลายเป็นโมฆะ สำหรับทั้งคู่ สมมติฐานที่ถูกต้องคือ "แฮนเดิลและการเชื่อมต่อไม่รอดข้ามรีซูม" และคำตอบที่ถูกคืออิมพลีเมนต์ตรรกะเชื่อมต่อใหม่ที่สร้างการเชื่อมต่อใหม่จากการแจ้งรีซูมหรือข้อผิดพลาดการสื่อสาร การรวม keepalive เป็นระยะกับการลองใหม่ที่ใช้ exponential backoff เมื่อล้มเหลวคือรูปแบบที่ลงตัว
- จะสอบสวนสลีปที่ไม่คาดคิดหรือรีซูมที่ไม่คาดคิดอย่างไร
- คำสั่ง powercfg คือเครื่องมือแรก ในทิศทาง "มันไม่ยอมสลีป" powercfg /requests แสดงโปรเซสและไดรเวอร์ใดออก power request ที่กำลังบล็อกสลีป ในทิศทาง "มันตื่นเอง" powercfg /lastwake แสดงเหตุผลตื่นล่าสุด และ powercfg /waketimers แสดงตัวตั้งเวลาที่จองไว้เพื่อปลุกเครื่อง บนเครื่อง Modern Standby powercfg /sleepstudy สร้างรายงานการบริโภคและกิจกรรมระหว่างสลีป ประวัติสลีปและรีซูมยังถูกบันทึกในล็อกอีเวนต์ (แหล่ง Kernel-Power ในล็อก System) ดังนั้นคุณยืนยันบนไทม์ไลน์ได้ว่า "เมื่อใดมันสลีป และเมื่อใดและทำไมมันจึงตื่น"