Aplikasi yang rusak saat bangun dari tidur — cara kerja event daya Windows dan cara membangun aplikasi bisnis yang bertahan
· Go Komura · Windows, Manajemen daya, Pengembangan Windows, Aplikasi bisnis, Kontrol perangkat, Pemecahan masalah, Win32 API
“Saya menutup laptop, membukanya keesokan paginya, dan aplikasi bisnis penuh kesalahan.” “Aplikasi pemantauan peralatan hanya kehilangan data setelah makan siang.” “Alat residensial yang mengekspor ke Excel kadang berhenti pada kesalahan koneksi.” — Tiket-tiket ini berbagi satu tersangka. Tidur.
Aplikasi bisnis dari era ketika PC desktop menjadi arus utama ditulis dengan asumsi tak terucap bahwa “PC tetap menyala”. Medan utama hari ini adalah laptop, dan secara bawaan ia tidur setelah beberapa menit idle. Pada mesin yang mampu Modern Standby, semantik tidur itu sendiri telah berubah dari model tradisional. Ditujukan kepada pengembang yang menulis aplikasi bisnis dan perangkat lunak kontrol peralatan di Windows, artikel ini menata, dari sumber primer, apa yang OS beritahukan kepada aplikasi sebelum dan sesudah tidur, apa yang rusak, dan cara menulis aplikasi yang bertahan saat bangun.
1. Kesimpulan lebih dulu
- Tidur adalah event yang aplikasi “tidak berhak menolak”. Anda diberi tahu tepat sebelumnya dengan
WM_POWERBROADCAST(PBT_APMSUSPEND), tetapi masa tenggang sekitar 2 detik, dan pada suspend darurat notifikasi bahkan tidak datang.12 - Saat bangun dari suspend, PBT_APMRESUMEAUTOMATIC datang, dan pada bangun yang dipicu pengguna PBT_APMRESUMESUSPEND datang juga. Pekerjaan wajib seperti menyambung ulang termasuk di yang pertama sebagai aturan. Transisi masuk dan keluar idle berdaya rendah Modern Standby tidak selalu selaras dengan notifikasi ini, jadi perlakukan notifikasi sebagai bantuan.34
- Rancang dengan asumsi bahwa koneksi TCP, port serial, dan handle perangkat tidak bertahan melewati bangun. Logika sambung ulang yang membangunnya kembali pada notifikasi bangun atau kesalahan komunikasi adalah acara utamanya.
- Waspadai timer dan penanganan waktu. Pekerjaan berkala berhenti selama tidur, dan cara ia menyala tepat setelah bangun berbeda menurut API timer dan runtime. “Lompatan besar pada waktu yang berlalu” juga terjadi, jadi pendekatan yang aman adalah membangun ulang jadwal saat bangun.
- Tekan tidur secara eksplisit untuk interval yang tidak ingin Anda tiduri. Pakai
SetThreadExecutionState(ES_SYSTEM_REQUIRED) atau power request (PowerSetRequest), dan selalu bersihkan saat pekerjaan selesai.45 - Pada mesin Modern Standby sistem tetap berjalan sebentar-sebentar selama tidur, tetapi aplikasi desktop dijeda. Anda tidak dapat memegang harapan bahwa “aplikasi kita harus tetap berjalan selama tidur”.6
- Alat investigasi standar adalah
powercfg(/requests, /lastwake, /sleepstudy) dan Kernel-Power di event log.
2. Apa yang terjadi di sekitar tidur — alur event daya
OS menyiarkan perubahan keadaan daya ke setiap aplikasi sebagai pesan WM_POWERBROADCAST.2 Ada tiga event utama yang melibatkan tidur dan bangun.
| Event | Arti |
|---|---|
| PBT_APMSUSPEND | Akan masuk tidur (kesempatan terakhir untuk bersiap) |
| PBT_APMRESUMEAUTOMATIC | Bangun (selalu datang saat bangun) |
| PBT_APMRESUMESUSPEND | Bangun yang disebabkan tindakan pengguna (yang ini bersyarat) |
PBT_APMSUSPEND adalah notifikasi tepat sebelum tidur, dan di sini Anda dapat bersiap dengan menutup berkas dan menyimpan state. Ada dua syarat, walaupun. Pertama, waktu yang diizinkan untuk pemrosesan sekitar 2 detik per aplikasi, dan jika Anda melebihinya sistem lanjut tanpa menunggu.1 Kedua, pada suspend darurat seperti baterai kritis, ia tidur segera tanpa notifikasi di muka.2 Desain yang “harus selesai sebelum tidur” tidak bertahan. Perlakukan notifikasi sebagai kesempatan untuk “lakukan jika sempat”, dan taruh pekerjaan utama di sisi bangun.
Sisi bangun ada dua tahap. PBT_APMRESUMEAUTOMATIC datang saat bangun dari transisi suspend. Di atas itu, jika mesin bangun karena tindakan pengguna seperti tombol daya atau tekan tombol (atau kehadiran pengguna terdeteksi setelahnya), PBT_APMRESUMESUSPEND mengikuti. Sebaliknya, bangun tanpa pengawasan untuk remote wake lewat jaringan atau untuk pemeliharaan hanya mengirimkan PBT_APMRESUMEAUTOMATIC.3 Dua tahap ini sendiri adalah petunjuk cara membagi pekerjaan — lakukan pemulihan mekanis seperti membangun ulang koneksi pada PBT_APMRESUMEAUTOMATIC, dan lakukan tindakan yang menghadap pengguna seperti pembaruan layar atau prompt masuk ulang pada PBT_APMRESUMESUSPEND.
sequenceDiagram
accTitle: Alur notifikasi untuk tidur dan bangun
accDescr: PBT_APMSUSPEND datang tepat sebelum tidur dengan masa tenggang sekitar 2 detik; saat bangun, PBT_APMRESUMEAUTOMATIC selalu datang, dan PBT_APMRESUMESUSPEND mengikuti hanya untuk bangun yang dipicu pengguna
participant OS as OS
participant A as Aplikasi
OS->>A: PBT_APMSUSPEND (masa tenggang sekitar 2 detik)
A->>A: Simpan state dan tutup koneksi
Note over OS: Tidur (kode tidak berjalan)
OS->>A: PBT_APMRESUMEAUTOMATIC (datang saat bangun)
A->>A: Sambung ulang dan pulihkan state
OS->>A: PBT_APMRESUMESUSPEND (hanya bangun yang dipicu pengguna)
A->>A: Pembaruan layar dan pekerjaan lain yang menghadap pengguna
Gambar 1: Notifikasi hanyalah “satu kata tepat sebelumnya, dan satu atau dua kata setelah bangun”. Bintang pemulihan adalah pekerjaan di sisi bangun.
flowchart TB
accTitle: Perbedaan antara tidur biasa dan suspend darurat
accDescr: Tidur biasa mengirimkan PBT_APMSUSPEND tepat sebelumnya dengan sekitar 2 detik untuk bersiap, tetapi suspend darurat seperti baterai kritis berhenti tanpa notifikasi di muka, jadi desain yang bergantung pada notifikasi di muka tidak bertahan
n2["Tidur biasa"] --> pre["PBT_APMSUSPEND (masa tenggang sekitar 2 detik)"]
pre --> s1["Bersiap, lalu berhenti"]
e2["Suspend darurat (baterai kritis)"] --> s2["Berhenti tanpa notifikasi di muka"]
s2 -.-> l2["Desain yang mengasumsikan notifikasi akan datang tidak bertahan"]
Gambar 2: Suspend darurat datang tanpa peringatan. Jadi persiapan adalah “bonus jika sempat”, dan pekerjaan utama pergi ke sisi bangun.
Perhatikan bahwa WM_POWERBROADCAST tidak membedakan jenis keadaan berdaya rendah (tidur versus hibernasi).4 Abstraksi yang tepat bagi aplikasi adalah memperlakukannya sebagai satu jenis event: “ia berhenti, dan ia kembali”. Layanan tanpa jendela dan aplikasi konsol dapat menerima notifikasi yang sama dengan memakai RegisterSuspendResumeNotification dalam bentuk callback (DEVICE_NOTIFY_CALLBACK).7
flowchart TB
accTitle: Membagi pekerjaan di dua tahap bangun
accDescr: Taruh pemulihan mekanis seperti menyambung ulang pada PBT_APMRESUMEAUTOMATIC, yang datang saat bangun; taruh pekerjaan yang menghadap pengguna seperti pembaruan layar atau prompt masuk ulang pada PBT_APMRESUMESUSPEND, yang datang hanya pada bangun yang dipicu pengguna
ra["PBT_APMRESUMEAUTOMATIC (saat bangun)"] --> m["Pemulihan mekanis"]
rs["PBT_APMRESUMESUSPEND (bangun yang dipicu pengguna)"] --> u["Pekerjaan yang menghadap pengguna"]
m -.-> m1["Sambung ulang dan buka ulang handle"]
u -.-> u1["Pembaruan layar dan prompt masuk ulang"]
Gambar 3: Yang terakhir tidak datang pada bangun tanpa pengawasan, jadi menaruh pemulihan wajib di yang terakhir akan melewatkannya.
3. Modern Standby — arti “tidur” telah berubah
Fakta modern lain yang harus diserap adalah Modern Standby. Tidur S3 tradisional adalah model sederhana yang “menghentikan sistem secara keseluruhan”; tidur pada mesin Modern Standby adalah model mirip smartphone di mana sistem tetap berjalan sebentar-sebentar setelah layar mati.
Yang penting bagi aplikasi bisnis di sini adalah bahwa aplikasi desktop dijeda oleh Desktop Activity Moderator (DAM) pada tahap pertama masuk tidur.6 Sistem itu sendiri tetap berjalan dari waktu ke waktu untuk menjaga jaringan tetap hidup dan menerima notifikasi, tetapi komponen yang mendapat manfaat dari itu adalah yang berpartisipasi dalam mekanisme ini — kode aplikasi desktop biasa tidak berjalan. Jadi dari sudut pandang pengembang kesimpulannya sama untuk Modern Standby dan untuk S3 — rancang dengan asumsi bahwa kode Anda tidak berjalan selama tidur.
flowchart TB
accTitle: Perbedaan antara tidur tradisional dan Modern Standby
accDescr: Tidur S3 tradisional menghentikan sistem secara keseluruhan, sedangkan di bawah Modern Standby sistem tetap berjalan sebentar-sebentar setelah layar mati. Aplikasi desktop dijeda oleh DAM dalam kedua kasus, jadi kode aplikasi tidak berjalan
s3["Tidur S3 tradisional: seluruh sistem berhenti"] --> conc["Kode aplikasi tidak berjalan"]
ms["Modern Standby: sistem berjalan sebentar-sebentar"] --> dam["Aplikasi desktop dijeda oleh DAM"]
dam --> conc
Gambar 4: Modelnya telah berubah, tetapi bagi aplikasi desktop kesimpulannya sama: “Anda tidak dapat berjalan selama tidur”.
Peringatan lain adalah betapa sedikitnya Anda dapat mengandalkan notifikasi. Di bawah Modern Standby, transisi masuk dan keluar idle berdaya rendah tidak selaras dengan transisi suspend tradisional, dan koneksi sudah dapat putus tanpa notifikasi pernah datang. Perlakukan notifikasi bangun sebagai bantuan, dan taruh penyambungan ulang yang dipicu deteksi kesalahan (Bab 5) pada jalur pemulihan utama.
Perbedaan lain adalah rasa “licin” dari perilakunya. Mencapai kedalaman tidur bertahap, dan waktu putus serta berhenti tidak setajam di bawah S3. Perbedaan antara “layar baru saja mati” dan “ia tidur” juga sulit dilihat pengguna, jadi ketika Anda menerima gejala Anda perlu mengonfirmasi “apakah mereka menutup lid” dan “berapa menit dibiarkan idle”.
4. Apa yang rusak — gejala klasik
Koneksi TCP sudah mati. Selama tidur, sisi lain, NAT, dan firewall memperlakukan keheningan Anda sebagai timeout dan membuang koneksi. Lebih buruk, soket di sisi ini tidak tahu tentang kesalahannya, jadi ia gagal hanya ketika Anda mengirim atau menerima setelah bangun. Atau lebih buruk lagi, tunggu terima tidak pernah error sama sekali (itulah mengapa Anda membutuhkan keepalive). Koneksi basis data dan WebSocket punya bentuk yang sama.
Handle port serial dan perangkat USB menjadi tidak valid. Perangkat yang terhubung USB dapat tampak, saat bangun, seolah “dicabut dan dipasang kembali” sekali, dan handle yang Anda buka mulai mengembalikan kesalahan. Itu pola khas aplikasi kontrol peralatan yang “mendapat kesalahan komunikasi hanya setelah makan siang”. Desain sambung ulang juga dibahas di artikel komunikasi serial.
Kontinuitas waktu putus. Pekerjaan yang didorong timer seperti “poll setiap 10 detik” tidak menyala selama tidur. Cara ia menyala tepat setelah bangun (pekerjaan yang sudah jatuh tempo menyala sekali segera, tidak terjadi apa-apa sampai periode berikutnya, dan sebagainya) berbeda menurut API timer dan runtime yang Anda pakai, jadi jangan menyerahkan penanganan tick yang terlewat kepada perilaku implisit — pendekatan yang aman adalah membangun ulang jadwal pada notifikasi bangun. Juga, perhitungan waktu yang berlalu (selisih dari stempel waktu sebelumnya) tiba-tiba menjadi “setara 8 jam”, dan perhitungan rata-rata atau penilaian timeout rusak. Pekerjaan terjadwal seperti “jalankan setiap malam pukul 02.00” sama sekali tidak berjalan jika PC tidur pada waktu itu (bangunkan dengan fitur bangun-dari-tidur Task Scheduler jika Anda membutuhkannya).
flowchart TB
accTitle: Tiga bentuk di mana kontinuitas waktu putus
accDescr: Pekerjaan berkala berhenti selama tidur dan penyalaan pasca-bangun berbeda menurut API, jadi bangun ulang jadwal saat bangun; selisih dari stempel waktu sebelumnya menjadi besar setelah bangun, jadi jaga itu; pekerjaan terjadwal tidak berjalan jika mesin tidur, jadi pertimbangkan bangun-dari-tidur Task Scheduler
t1["Pekerjaan berkala: berhenti"] -.-> g1["Bangun ulang jadwal"]
t2["Waktu yang berlalu: meledak"] -.-> g2["Jaga selisih abnormal"]
t3["Terjadwal: tidak pernah berjalan"] -.-> g3["Bangun-dari-tidur"]
g1 ~~~ t2
g2 ~~~ t3
Gambar 5: Tulis penanganan timer dan waktu dengan asumsi bahwa “waktu meloncat”. Masing-masing dari tiga bentuk punya jenis penanggulangan.
flowchart TB
accTitle: Tiga hal yang rusak melewati tidur
accDescr: Melewati tidur, koneksi TCP sudah dibuang oleh timeout di sisi lain, handle perangkat USB menjadi tidak valid sebagai sambung ulang, dan pekerjaan berbasis waktu yang berlalu mengamati lompatan waktu besar. Pulihkan masing-masing dengan sambung ulang, buka ulang, dan penjaga selisih
sleep["Interval tidur"] --> tcp["TCP: rekan membuangnya"]
sleep --> more{"USB atau waktu yang berlalu?"}
more --> usb["USB: handle tidak valid"]
more --> time["Waktu yang berlalu: lompatan"]
tcp -.-> r1["Deteksi + sambung ulang"]
usb -.-> r2["Buka ulang perangkat"]
time -.-> r3["Jaga selisih abnormal"]
Gambar 6: Yang rusak jatuh ke tiga keluarga — “koneksi”, “handle”, dan “kontinuitas waktu” — dan masing-masing punya jenis pemulihan yang sudah mapan.
Autentikasi ulang ke sumber daya bersama. Drive jaringan dan VPN sering perlu dibangun ulang setelah bangun, dan ada “lembah start” beberapa hingga puluhan detik tepat setelah bangun di mana akses gagal. Lebih aman untuk tidak mencoba ulang semuanya sekaligus tepat setelah bangun, melainkan menunggu sebentar dan mencoba ulang secara bertahap.
5. Membangun aplikasi yang bertahan saat bangun
Prinsipnya satu hal. Asumsikan bahwa “koneksi dan handle tidak bertahan melewati tidur”, dan struktur aplikasi agar Anda selalu dapat pulih.
Deteksi bangun dan pulihkan. Ketika WM_POWERBROADCAST jendela tingkat atas menerima PBT_APMRESUMEAUTOMATIC, buang koneksi yang Anda pegang dan bangun ulang. Poinnya adalah tidak mengandalkan notifikasi bangun saja. Notifikasi yang terlewat dan komunikasi yang terjadi sebelum notifikasi keduanya nyata, jadi selalu pasangkan dengan jalur yang “menyambung ulang ketika kesalahan komunikasi terdeteksi”, dan perlakukan notifikasi bangun sebagai pemicu yang hanya memulai itu lebih awal.
// 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);
}
Buat pekerjaan sambung ulang itu sendiri idempotent (aman tidak peduli berapa kali dipanggil), coba ulang saat gagal dengan exponential backoff, dan dalam keadaan mantap deteksi koneksi mati lebih awal dengan keepalive — satukan ketiga itu sebagai satu set, dan Anda akan bertahan bukan hanya bangun dari tidur tetapi juga jatuh jaringan singkat atau reboot perangkat.
flowchart TB
accTitle: Desain sambung ulang yang tahan bangun
accDescr: Notifikasi bangun, kesalahan komunikasi, dan kegagalan keepalive semuanya masuk ke pekerjaan sambung ulang idempotent yang sama, yang mencoba ulang dengan exponential backoff saat gagal
e1["Notifikasi bangun (PBT_APMRESUMEAUTOMATIC)"] --> r["Pekerjaan sambung ulang idempotent"]
e2["Deteksi kesalahan komunikasi"] --> r
e3["Kegagalan keepalive"] --> r
r --> ok{"Berhasil?"}
ok -->|"ya"| run["Kembali ke operasi normal"]
ok -->|"tidak"| back["Coba ulang setelah exponential backoff"]
back --> r
Gambar 7: Konsentrasikan sambung ulang ke satu jalur idempotent, dan masuk jalan yang sama dari notifikasi bangun, deteksi kesalahan, atau keepalive.
Tinjau ulang penanganan waktu. Untuk pekerjaan yang memakai “waktu yang berlalu sejak terakhir”, pasang penjaga yang membatalkan interval ketika mendeteksi selisih yang abnormally besar (jangan lipat ke rata-rata, jangan perlakukan sebagai timeout). Mengukur waktu yang berlalu melewati bangun mensyaratkan menjaga perbedaan antara jam yang maju selama tidur (waktu dinding) dan waktu yang benar-benar dihabiskan untuk pekerjaan.
Tekan tidur secara eksplisit untuk interval yang tidak ingin Anda tiduri. Selama pekerjaan yang tidak boleh ditiduri — migrasi data, komunikasi berkelanjutan dengan perangkat, dan sebagainya — Anda dapat menjaga sistem tetap terjaga dengan SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) (tambahkan ES_DISPLAY_REQUIRED jika Anda juga ingin menjaga layar menyala).45 Metode yang lebih tertib adalah API power-request (PowerCreateRequest + PowerSetRequest), yang dapat menempelkan string alasan, dan powercfg /requests kemudian akan menunjukkan “siapa yang memblokirnya dan mengapa”.8 Perhatikan bahwa penekanan lewat SetThreadExecutionState adalah per thread, dan Anda membersihkannya dari thread yang sama yang menetapkannya. Untuk pekerjaan yang berganti thread, seperti async/await, pakai sisi power-request, yang dikelola oleh handle. Ada peringatannya. Pertama, yang ditekan ini adalah tidur idle otomatis. Mereka tidak dapat menghentikan tindakan pengguna eksplisit seperti menutup lid atau memilih Sleep dari menu Start, jadi Anda tidak dapat melewatkan desain sambung ulang bab ini bahkan saat penekanan aktif. Kedua, pada baterai pada mesin Modern Standby, power request ini juga dipotong beberapa waktu setelah timeout tidur berlalu. Pekerjaan yang tidak dapat diinterupsi harus dijamin oleh daya AC atau oleh operasi.8 Ketiga, selalu bersihkan saat pekerjaan selesai. Pembersihan yang terlewat menjadi bug baru: “PC ini, entah mengapa, tidak mau tidur”.
flowchart TB
accTitle: Dua sarana menekan tidur
accDescr: Baik Anda memakai SetThreadExecutionState yang nyaman atau API power-request yang dapat menempelkan string alasan dan terlihat oleh administrator lewat powercfg, selalu bersihkan saat pekerjaan berakhir
need["Interval kerja yang tidak boleh ditiduri"] --> a["SetThreadExecutionState"]
need --> b["Power request (PowerSetRequest)"]
a -.-> a1["Nyaman — hanya flag"]
b -.-> b1["Dengan alasan — terlihat di powercfg"]
a --> off["Selalu bersihkan saat pekerjaan berakhir"]
b --> off
Gambar 8: Untuk kedua sarana, “bersihkan saat selesai” adalah syarat mutlak. Power request yang dapat membuat alasan terlihat lebih ramah bagi operasi.
Layanan dan aplikasi tanpa jendela menerima notifikasi callback dengan RegisterSuspendResumeNotification (DEVICE_NOTIFY_CALLBACK).7 Jika operasi berkelanjutan adalah persyaratan sungguhan, solusi akarnya adalah meninjau ulang desain yang menahan pekerjaan residensial pada PC klien yang tidur, dan memindahkannya ke sisi server atau ke mesin yang dioperasikan tanpa tidur.
6. Investigasi — powercfg dan Event Log
Investigasi seputar daya dilayani dengan baik oleh alat yang ikut dengan OS.
- Tidak mau tidur:
powercfg /requestsmencantumkan proses dan driver yang telah mengeluarkan power request. “Aplikasi lupa membersihkanSetThreadExecutionState” muncul di sini juga. - Bangun sendiri:
powercfg /lastwakemenunjukkan alasan bangun terbaru, danpowercfg /waketimersmenunjukkan timer yang saat ini dicadangkan untuk membangunkan mesin. - Kualitas Modern Standby:
powercfg /sleepstudymenghasilkan laporan konsumsi daya dan aktivitas per interval tidur.9 - Mengonfirmasi linimasa: Sumber Kernel-Power di event log (System) menyimpan catatan masuk tidur dan bangun. Mencocokkannya dengan log aplikasi membiarkan Anda mengonfirmasi secara objektif apakah “ada bangun tepat sebelum kesalahan”.
flowchart TB
accTitle: Memetakan gejala masalah daya ke perintah investigasi
accDescr: Untuk gejala tidak-mau-tidur, temukan siapa yang memegang power request dengan powercfg /requests; untuk gejala bangun-sendiri, temukan alasan bangun dengan /lastwake dan /waketimers; untuk linimasa, pakai Kernel-Power di event log
s1["Tidak mau tidur"] --> c1["powercfg /requests"]
s2["Bangun sendiri"] --> c2["powercfg /lastwake dan /waketimers"]
s3["Ingin mengonfirmasi linimasa"] --> c3["Kernel-Power di event log"]
c1 -.-> note["Penekanan tidur yang terlupa muncul juga"]
Gambar 9: Gejala memetakan ke perintah investigasi dalam tiga keluarga. Pertama konfirmasi “apakah baru saja tidur”, lalu belah.
Dalam penanganan tiket, hanya dengan bertanya lebih dulu “apakah PC tidur tepat sebelumnya (apakah mereka menutup lid)” sangat mempercepat isolasi.
7. Ringkasan
- Tidur tidak dapat ditolak. Notifikasi di muka (PBT_APMSUSPEND) adalah best-effort dengan masa tenggang sekitar 2 detik, dan tidak datang dalam keadaan darurat. Taruh desain utama di sisi bangun.
- Notifikasi bangun adalah PBT_APMRESUMEAUTOMATIC (saat bangun dari suspend) + PBT_APMRESUMESUSPEND (pada tindakan pengguna). Pertahankan sambung ulang yang didorong kesalahan pada jalur utama untuk kasus di mana notifikasi tidak datang.
- Asumsikan bahwa koneksi dan handle tidak bertahan melewati bangun, dan implementasikan set tiga bagian berupa sambung ulang idempotent + exponential backoff + keepalive.
- Pasang penjaga terhadap “selisih abnormal” pada pekerjaan berbasis waktu yang berlalu. Rancang pekerjaan terjadwal dengan asumsi bahwa ia tidak berjalan selama tidur.
- Untuk interval yang tidak boleh ditiduri, tekan tidur secara eksplisit dengan
SetThreadExecutionStateatau power request, dan selalu bersihkan saat selesai. - Investigasi adalah
powercfg(/requests, /lastwake, /sleepstudy) dan event log Kernel-Power. Dalam penanganan tiket, tanya lebih dulu “apakah ia tidur tepat sebelumnya”.
Dari sudut pandang aplikasi, tidur adalah event di mana “waktu meloncat tanpa peringatan, koneksi ke sekitar terputus, lalu ia kembali”. Apakah Anda telah merajut itu ke dalam desain sebagai bagian dari kehidupan sehari-hari, bukan sebagai situasi abnormal, adalah yang memisahkan kestabilan aplikasi bisnis di era laptop.
Artikel terkait
- Jebakan aplikasi komunikasi serial - lewat desain sambung ulang dan log
- Shutdown Windows dilihat dari aplikasi Anda — bertahan dari notifikasi keluar, restart, dan kehilangan daya dengan benar
- Apa itu Windows Efficiency Mode? - Ikon daun hijau dan cara mematikannya
- Mengapa Anda sebaiknya lebih memilih tunggu event daripada Sleep(1) di Windows
- Apa sebenarnya “Tidak Merespons” — cara Windows memutuskan aplikasi hang, dan cara merancang aplikasi yang tidak hang
Area konsultasi terkait
KomuraSoft LLC menangani investigasi akar masalah bug seperti “komunikasi putus setelah bangun dari tidur” dan “koneksi ke perangkat jatuh setelah makan siang”, memasang ulang logika sambung ulang dan penanganan event daya pada aplikasi yang ada, serta tinjauan desain aplikasi bisnis dan perangkat lunak kontrol peralatan yang mengasumsikan operasi laptop.
- Investigasi bug dan akar masalah
- Pengembangan aplikasi Windows
- Konsultasi teknis dan tinjauan desain
- Hubungi kami
Tautan referensi
-
Microsoft Learn, PBT_APMSUSPEND event. Tentang ini adalah event yang datang tepat sebelum komputer masuk keadaan suspend; tentang aplikasi diharapkan menyelesaikan pekerjaan yang dibutuhkan untuk menyimpan data; dan tentang sistem yang mengizinkan sekitar 2 detik untuk menangani notifikasi ini, dengan aplikasi yang lanjut melewati itu dapat diinterupsi. ↩ ↩2
-
Microsoft Learn, System Power Management Events. Tentang sistem yang menyiarkan perubahan mode operasi seperti tidur di muka; tentang PBT_APMSUSPEND yang diberitahukan sebelum tidur idle agar Anda dapat bersiap dengan menutup berkas dan menyimpan data; tentang suspend darurat (baterai kritis dan sejenisnya) yang tidak memberi notifikasi di muka; tentang penanganan pesan ini yang diizinkan maksimum 2 detik per aplikasi dan dipotong setelah timeout; dan tentang setiap aplikasi diberitahu saat bangun. ↩ ↩2 ↩3
-
Microsoft Learn, PBT_APMRESUMESUSPEND event. Tentang ini dikirim setelah PBT_APMRESUMEAUTOMATIC pada bangun yang dipicu pengguna atau ketika input pengguna terdeteksi setelahnya; tentang hanya PBT_APMRESUMEAUTOMATIC yang dikirim untuk bangun dari penyebab eksternal seperti remote wake; dan tentang aplikasi diharapkan membuka ulang berkas yang ditutup pada waktu tidur dan bersiap untuk input pengguna. ↩ ↩2
-
Microsoft Learn, WM_POWERBROADCAST message. Tentang PBT_APMRESUMEAUTOMATIC selalu dikirim saat bangun, dengan PBT_APMRESUMESUSPEND dikirim juga pada bangun dari input pengguna; tentang pesan ini tidak membedakan jenis keadaan berdaya rendah; tentang rincian transisi keadaan daya yang dicatat di event log sistem; dan tentang memanggil SetThreadExecutionState untuk mencegah sistem masuk keadaan berdaya rendah. ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, SetThreadExecutionState function (winbase.h). Tentang ES_SYSTEM_REQUIRED dan ES_DISPLAY_REQUIRED yang dapat menekan tidur idle sistem dan mematikan tampilan; dan tentang menyatakan penekanan berkelanjutan dengan ES_CONTINUOUS dan membersihkannya dengan memanggil ES_CONTINUOUS saja saat Anda selesai. ↩ ↩2
-
Microsoft Learn, Prepare software for modern standby. Tentang Desktop Activity Moderator (DAM) yang menjeda aplikasi desktop pada tahap pertama transisi ke Modern Standby; dan tentang sistem kemudian bergerak bertahap ke fase berdaya rendah dan fase resiliency, dengan hanya komponen yang diizinkan yang berjalan sebentar-sebentar. ↩ ↩2
-
Microsoft Learn, RegisterSuspendResumeNotification function (winuser.h). Tentang ini adalah API yang mendaftar untuk menerima notifikasi suspend/resume, dan tentang menentukan DEVICE_NOTIFY_CALLBACK agar aplikasi atau layanan tanpa jendela dapat menerima notifikasi lewat callback selain pengiriman pesan ke handle jendela. ↩ ↩2
-
Microsoft Learn, PowerSetRequest function (winbase.h). Tentang dapat menetapkan jenis permintaan seperti sistem atau tampilan tetap terjaga pada objek power-request yang dibuat dengan PowerCreateRequest; tentang dapat menempelkan string alasan diagnostik; dan tentang power request yang tertunda dapat dienumerasi dengan powercfg /requests. ↩ ↩2
-
Microsoft Learn, Modern standby SleepStudy. Tentang laporan yang dihasilkan powercfg /sleepstudy membiarkan Anda memeriksa, per interval Modern Standby, konsumsi daya, aktivitas, dan alasan bangun (tombol daya, input pengguna, wake timer, dan sebagainya). ↩
Artikel terkait
Artikel terbaru dengan tag yang sama untuk mendalami topik-topik terdekat.
DllMain dan loader lock — alasan sebenarnya Anda diminta "jangan lakukan apa pun di inisialisasi DLL"
Mengapa Anda tidak boleh memanggil LoadLibrary atau menyinkronkan dengan thread lain dari DllMain. Berdasarkan sumber primer, artikel ini...
Apa sebenarnya "Tidak Merespons" — cara Windows memutuskan aplikasi hang, dan cara merancang aplikasi yang tidak hang
"Tidak Merespons" Windows adalah mekanisme di mana OS menilai bahwa jendela belum mengambil pesan selama 5 detik dan menggantinya dengan ...
Win32 Thread Pool API — konkurensi tanpa membuat thread, lewat CreateThreadpoolWork
Apakah Anda menebar panggilan CreateThread di seluruh kode native? Artikel ini menjelaskan Win32 thread pool API yang didesain ulang di V...
Named pipes dalam praktik — IPC standar Windows dari desain hingga keamanan
Panduan praktis tentang named pipe, komunikasi antarpproses standar di Windows. Artikel ini menata, dari sumber primer, pilihan antara mo...
Spurious wakeup — mengapa condition variable bangun "tanpa diberitahu" dan cara menunggu dengan benar di Windows
Tunggu condition variable dapat kembali bahkan ketika tidak ada notifikasi yang datang (spurious wakeup). Artikel ini menjelaskan, dari i...
Topik terkait
Halaman-halaman ini menempatkan topik dalam konteks layanan dan keputusan yang lebih luas.
Topik teknis Windows
Portal tentang pengembangan Windows, investigasi bug, dan pemanfaatan aset yang ada.
Layanan yang terkait dengan topik ini
Artikel ini berkaitan langsung dengan layanan berikut.
Pengembangan aplikasi Windows
Aplikasi bisnis, integrasi perangkat, dan alat komunikasi, dari kebutuhan hingga pengembangan.
Pertanyaan yang sering diajukan
Pertanyaan yang sering muncul dalam konsultasi tentang topik artikel ini.
- Bisakah aplikasi mengetahui tidur lebih dulu dan menolaknya?
- Di Windows saat ini Anda dapat menerima notifikasi, tetapi tidak dapat menolak. Tepat sebelum tidur, pesan WM_POWERBROADCAST mengirimkan event PBT_APMSUSPEND, dan di sini Anda dapat bersiap dengan menutup berkas dan menyimpan state, tetapi waktu yang diizinkan untuk pemrosesan sekitar 2 detik per aplikasi, dan jika Anda melebihinya sistem lanjut tanpa menunggu. Pada suspend darurat seperti baterai kritis, notifikasi di muka itu sendiri tidak datang. Jadi desain yang "harus selesai sebelum tidur" tidak bertahan; Anda membutuhkan desain yang dapat pulih saat bangun tidak peduli kapan potongannya datang. Untuk rentang kerja yang benar-benar tidak ingin Anda tiduri, tekan tidur secara eksplisit dengan SetThreadExecutionState atau power request (PowerSetRequest).
- Bagaimana cara mendeteksi bahwa mesin sudah bangun?
- Jika aplikasi punya jendela, tangani WM_POWERBROADCAST. Saat bangun dari suspend, PBT_APMRESUMEAUTOMATIC datang, dan jika bangun disebabkan tindakan pengguna (tombol daya atau tekan tombol), PBT_APMRESUMESUSPEND mengikutinya. Bangun tanpa pengawasan yang segera tidur lagi hanya mengirimkan PBT_APMRESUMEAUTOMATIC, jadi pemisahan dasarnya adalah menaruh pekerjaan wajib seperti menyambung ulang di sisi PBT_APMRESUMEAUTOMATIC dan pekerjaan yang menghadap pengguna seperti pembaruan layar di sisi PBT_APMRESUMESUSPEND. Layanan tanpa jendela dan aplikasi konsol dapat menerima notifikasi yang sama lewat callback dengan memakai RegisterSuspendResumeNotification dengan DEVICE_NOTIFY_CALLBACK.
- Bisakah saya menjaga aplikasi tetap berjalan selama tidur?
- Sebagai aturan, tidak. Selama tidur, eksekusi CPU itu sendiri berhenti (pada mesin Modern Standby, aplikasi desktop dijeda oleh Desktop Activity Moderator), dan kode aplikasi tidak berjalan. Ada dua pilihan. Yang satu adalah menekan tidur hanya sementara pekerjaan berlangsung. Menentukan ES_SYSTEM_REQUIRED dengan SetThreadExecutionState, atau mengeluarkan power request dengan PowerCreateRequest/PowerSetRequest, akan menekan tidur idle otomatis untuk interval itu (Anda dapat mengonfirmasinya dengan powercfg /requests). Itu tetap tidak dapat menghentikan tindakan tidur eksplisit seperti pengguna menutup lid, jadi Anda tetap perlu siap untuk bangun bahkan saat penekanan aktif. Yang lain adalah menerima tidur dan merancang untuk "mengejar setelah bangun". Untuk pekerjaan terjadwal seperti batch malam, Anda juga dapat membangunkan PC dengan "Wake the computer to run this task" milik Task Scheduler. Pekerjaan yang benar-benar perlu berjalan terus-menerus termasuk di server atau layanan yang dikonfigurasi agar tidak tidur.
- Mengapa koneksi TCP dan port serial berhenti bekerja setelah bangun?
- Karena adapter jaringan dan perangkat USB juga turun ke keadaan berdaya rendah selama tidur. Koneksi TCP sudah dibuang oleh sisi lain atau oleh timeout NAT atau firewall, dan kirim/terima setelah bangun mengembalikan kesalahan (Anda sering tidak menyadarinya sampai ia error). Adapter USB-ke-serial dan sejenisnya kadang diperlakukan sebagai pencabutan dan pemasangan ulang perangkat saat bangun, dan handle yang Anda buka menjadi tidak valid. Untuk keduanya, asumsi yang benar adalah bahwa "handle dan koneksi tidak bertahan melewati bangun", dan jawabannya adalah mengimplementasikan logika sambung ulang yang membangun kembali koneksi pada notifikasi bangun atau kesalahan komunikasi. Menggabungkan keepalive berkala dengan coba ulang yang memakai exponential backoff saat gagal adalah pola yang sudah mapan.
- Bagaimana cara menyelidiki tidur tak terduga atau bangun tak terduga?
- Perintah powercfg adalah alat pertama. Di arah "tidak mau tidur", powercfg /requests mencantumkan proses dan driver mana yang telah mengeluarkan power request yang memblokir tidur. Di arah "bangun sendiri", powercfg /lastwake menunjukkan alasan bangun terbaru dan powercfg /waketimers menunjukkan timer yang saat ini dicadangkan untuk membangunkan mesin. Pada mesin Modern Standby, powercfg /sleepstudy menghasilkan laporan konsumsi dan aktivitas selama tidur. Riwayat tidur dan bangun juga dicatat di event log (sumber Kernel-Power di log System), jadi Anda dapat mengonfirmasi pada linimasa "kapan ia tidur, dan kapan serta mengapa ia bangun".
Profil penulis
Halaman perkenalan penulis artikel.
Go Komura
Direktur KomuraSoft LLC
Berspesialisasi dalam pengembangan perangkat lunak Windows, konsultasi teknis, dan investigasi bug, terutama pada proyek dengan sistem yang sudah ada dan bug yang sulit direproduksi.