「노트북을 닫고 다음 날 아침 열었더니 업무 앱이 오류투성이였다」. 「설비 감시 앱이 점심 뒤에만 데이터를 놓친다」. 「Excel로 내보내는 상주 도구가 가끔 연결 오류로 멈춘다」── 이런 티켓의 용의자는 하나입니다. 절전.
데스크톱 PC가 주류이던 시대의 업무 앱은 「PC는 켜진 채로 있다」는 암묵의 가정 위에 쓰였습니다. 지금의 주전장은 노트북이고, 기본값으로는 유휴 몇 분 뒤에 절전합니다. Modern Standby 대응 기기에서는 절전의 의미 자체도 전통 모델과 달라졌습니다. Windows에서 업무 앱과 설비 제어 소프트웨어를 쓰는 개발자를 대상으로, OS가 절전 전후에 앱에 무엇을 알리는지, 무엇이 깨지는지, 재개를 견디는 앱을 어떻게 쓰는지── 1차 정보로 정리합니다.
1. 먼저 결론
- 절전은 앱이 「거부할 권리가 없는」 이벤트입니다. 직전에
WM_POWERBROADCAST(PBT_APMSUSPEND)로 알림이 오지만, 유예는 약 2초이고, 긴급 절전에서는 알림조차 오지 않습니다.12 - 절전에서 재개하면 PBT_APMRESUMEAUTOMATIC이 오고, 사용자 조작에 의한 재개면 PBT_APMRESUMESUSPEND도 이어집니다. 재연결과 같은 필수 작업은 원칙적으로 전자에 둡니다. 다만 Modern Standby의 저전력 유휴 출입은 이 알림과 항상 맞지 않으므로, 알림은 보조로 다룹니다.34
- TCP 연결, 시리얼 포트, 장치 핸들은 재개를 넘기지 못한다고 가정하고 설계합니다. 재개 알림이나 통신 오류에서 다시 만드는 재연결 로직이 본편입니다.
- 타이머와 시간의 처리를 주의합니다. 주기 작업은 절전 중에 멈추고, 재개 직후 어떻게 발화하는지는 타이머 API와 런타임마다 다릅니다. 「경과 시간의 거대한 점프」도 일어나므로, 재개 때 일정을 다시 짜는 것이 안전합니다.
- 절전되면 안 되는 구간은 절전을 명시적으로 억제합니다.
SetThreadExecutionState(ES_SYSTEM_REQUIRED) 또는 전원 요청(PowerSetRequest)을 쓰고, 작업이 끝나면 반드시 해제합니다.45 - Modern Standby 기기에서는 시스템이 절전 중에도 간헐적으로 돌지만, 데스크톱 앱은 일시 정지됩니다. 「우리 앱은 절전 중에도 돌아야 한다」는 기대를 가질 수 없습니다.6
- 조사의 정석 도구는
powercfg(/requests, /lastwake, /sleepstudy)와 이벤트 로그의 Kernel-Power입니다.
2. 절전 전후에 일어나는 일 ── 전원 이벤트의 흐름
OS는 전원 상태 변화를 모든 앱에 WM_POWERBROADCAST 메시지로 브로드캐스트합니다.2 절전과 재개에 관련된 주요 이벤트는 세 가지입니다.
| 이벤트 | 의미 |
|---|---|
| PBT_APMSUSPEND | 절전에 들어가려 함(준비할 마지막 기회) |
| PBT_APMRESUMEAUTOMATIC | 재개함(재개 때 항상 도착) |
| PBT_APMRESUMESUSPEND | 사용자 조작에 의한 재개(조건부) |
PBT_APMSUSPEND는 절전 직전의 알림이며, 여기서 파일을 닫고 상태를 저장하는 준비를 할 수 있습니다. 다만 조건이 둘 있습니다. 첫째, 처리에 허용되는 시간은 앱당 약 2초이며, 넘기면 시스템은 기다리지 않고 진행합니다.1 둘째, 배터리가 임계 이하인 긴급 절전에서는 사전 알림 없이 바로 잠듭니다.2 「절전 전에 반드시 끝내야 한다」는 설계는 성립하지 않습니다. 알림은 「되면 하는」 기회로 두고, 본편은 재개 쪽에 둡니다.
재개 측은 두 단계입니다. PBT_APMRESUMEAUTOMATIC은 절전 전이에서의 재개 때 도착합니다. 그 위에, 전원 버튼이나 키 입력 같은 사용자 조작으로 재개했거나(또는 이후에 사용자 존재가 감지되면) PBT_APMRESUMESUSPEND가 이어집니다. 반대로 네트워크 너머의 원격 기상이나 유지보수를 위한 무인 재개에서는 PBT_APMRESUMEAUTOMATIC만 옵니다.3 이 두 단계 자체가 작업 분할의 힌트입니다── 연결 재구축 같은 기계적 복구는 PBT_APMRESUMEAUTOMATIC에, 화면 갱신이나 재로그인 프롬프트 같은 사용자 대면 동작은 PBT_APMRESUMESUSPEND에.
sequenceDiagram
accTitle: 절전과 재개의 알림 흐름
accDescr: 절전 직전에 약 2초의 유예와 함께 PBT_APMSUSPEND가 오고, 재개 때는 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: 보통 절전은 직전에 약 2초의 준비 시간과 함께 PBT_APMSUSPEND를 주지만, 배터리 임계 같은 긴급 절전은 사전 알림 없이 멈추므로 사전 알림에 의존하는 설계는 성립하지 않는다
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초마다 폴링」 같은 타이머 구동 작업은 절전 중에 발화하지 않습니다. 재개 직후 어떻게 발화하는지(만료된 할 일이 바로 한 번 발화하는지, 다음 주기까지 아무 일도 없는지 등)는 쓰는 타이머 API와 런타임마다 다르므로, 놓친 틱의 처리를 암묵 동작에 맡기지 말고── 재개 알림에서 일정을 다시 짜는 것이 안전합니다. 또한 경과 시간 계산(이전 타임스탬프와의 차이)이 갑자기 「8시간분」이 되어, 평균 계산이나 타임아웃 판단이 깨집니다. 「매일 밤 2시에 실행」 같은 예약 작업은 그 시각에 PC가 잠들어 있으면 그냥 돌지 않습니다(필요하면 작업 스케줄러의 절전 해제 기능으로 깨웁니다).
flowchart TB
accTitle: 시간의 연속성이 깨지는 세 가지 형태
accDescr: 주기 작업은 절전 중에 멈추고 재개 후 발화는 API마다 다르므로 재개 때 일정을 다시 짠다. 이전 타임스탬프와의 차이는 재개 뒤 거대해지므로 가드한다. 예약 작업은 잠들어 있으면 돌지 않으므로 작업 스케줄러의 절전 해제를 검토한다
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#: 재개 알림과 통신 오류를 같은 재연결 경로로 모은다
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(); // 멱등한 재연결 요청
}
base.WndProc(ref m);
}
재연결 작업 자체를 멱등하게(몇 번 호출해도 안전하게) 만들고, 실패 시 지수 백오프로 재시도하며, 정상 상태에서는 keepalive로 죽은 연결을 일찍 감지한다── 이 셋을 세트로 가져가면, 절전 재개뿐 아니라 짧은 네트워크 끊김이나 장치 재부팅도 견딥니다.
flowchart TB
accTitle: 재개에 강한 재연결 설계
accDescr: 재개 알림, 통신 오류, keepalive 실패가 모두 같은 멱등한 재연결 작업으로 모이고, 실패 시 지수 백오프로 재시도한다
e1["재개 알림(PBT_APMRESUMEAUTOMATIC)"] --> r["멱등한 재연결 작업"]
e2["통신 오류 감지"] --> r
e3["Keepalive 실패"] --> r
r --> ok{"성공?"}
ok -->|"예"| run["정상 운용으로 돌아간다"]
ok -->|"아니오"| back["지수 백오프 후 재시도"]
back --> r
그림 7: 재연결을 멱등한 단일 경로로 모으고, 재개 알림·오류 감지·keepalive에서 같은 길로 들어간다.
시간의 처리를 다시 본다. 「지난번부터의 경과 시간」을 쓰는 작업에는, 비정상적으로 큰 차이를 감지하면 그 구간을 무효로 하는 가드를 넣습니다(평균에 접어 넣지 말고, 타임아웃으로 취급하지 마십시오). 재개를 건너는 경과 시간 측정은 절전 중에도 진행하는 시계(벽시계)와 실제로 작업에 쓴 시간을 구분해야 합니다.
절전되면 안 되는 구간은 절전을 명시적으로 억제합니다. 데이터 마이그레이션, 장치와의 연속 통신처럼 잠들면 안 되는 작업 중에는 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)로 시스템을 깨워 둘 수 있습니다(화면도 켜 두고 싶으면 ES_DISPLAY_REQUIRED를 더합니다).45 더 정중한 방법은 전원 요청 API(PowerCreateRequest + PowerSetRequest)로, 이유 문자열을 붙일 수 있고 powercfg /requests가 「누가 왜 막고 있는지」를 보여 줍니다.8 주의할 점은, SetThreadExecutionState를 통한 억제는 스레드마다이며, 설정한 같은 스레드에서 해제한다는 것입니다. async/await처럼 스레드가 바뀌는 작업에는 핸들로 관리하는 전원 요청 쪽을 씁니다. 주의점이 있습니다. 첫째, 이들이 억제하는 것은 자동 유휴 절전입니다. 뚜껑을 닫거나 시작 메뉴에서 절전을 고르는 명시적 사용자 동작은 막지 못하므로, 억제 중에도 이 장의 재연결 설계를 생략할 수 없습니다. 둘째, Modern Standby 기기의 배터리에서는 절전 타임아웃이 지난 뒤 얼마 후면 이 전원 요청도 잘립니다. 중단할 수 없는 작업은 AC 전원이나 운용으로 보장해야 합니다.8 셋째, 작업이 끝나면 반드시 해제합니다. 해제를 놓치면 「이 PC가 왠지 절전이 안 된다」는 새 버그가 됩니다.
flowchart TB
accTitle: 절전을 억제하는 두 수단
accDescr: 편리한 SetThreadExecutionState를 쓰든, 이유 문자열을 붙일 수 있고 powercfg로 관리자에게 보이는 전원 요청 API를 쓰든, 작업이 끝나면 반드시 해제한다
need["잠들면 안 되는 작업 구간"] --> a["SetThreadExecutionState"]
need --> b["전원 요청(PowerSetRequest)"]
a -.-> a1["편리함 ── 플래그만"]
b -.-> b1["이유가 있음 ── powercfg에 보인다"]
a --> off["작업이 끝나면 반드시 해제한다"]
b --> off
그림 8: 어느 수단이든 「끝나면 해제」가 절대 조건이다. 이유를 보이게 할 수 있는 전원 요청이 운용에는 더 친절하다.
서비스와 창 없는 앱은 RegisterSuspendResumeNotification(DEVICE_NOTIFY_CALLBACK)으로 콜백 알림을 받습니다.7 연속 운용이 진짜 요구라면, 절전하는 클라이언트 PC에 작업을 상주시키는 설계 자체를 다시 보고, 서버 측이나 절전 없이 운용하는 기기로 옮기는 것이 근본 해법입니다.
6. 조사 ── powercfg와 이벤트 로그
전원 주변의 조사에는 OS에 딸린 도구가 잘 맞습니다.
- 절전이 안 된다:
powercfg /requests가 전원 요청을 낸 프로세스와 드라이버를 나열합니다. 「앱이SetThreadExecutionState해제를 잊었다」도 여기에 나옵니다. - 혼자 깨어난다:
powercfg /lastwake가 가장 최근 기상 이유를,powercfg /waketimers가 현재 기상을 예약해 둔 타이머를 보여 줍니다. - Modern Standby 품질:
powercfg /sleepstudy가 절전 구간마다의 소비 전력과 활동 보고서를 만듭니다.9 - 타임라인 확인: 이벤트 로그(System)의 Kernel-Power 원본이 절전 진입과 재개의 기록을 남깁니다. 앱 로그와 맞추면 「오류 직전에 재개가 있었는지」를 객관적으로 확인할 수 있습니다.
flowchart TB
accTitle: 전원 장애 증상을 조사 명령에 대응시키기
accDescr: 절전이 안 되는 증상은 powercfg /requests로 누가 전원 요청을 쥐고 있는지 찾고, 혼자 깨어나는 증상은 /lastwake와 /waketimers로 기상 이유를 찾으며, 타임라인은 이벤트 로그의 Kernel-Power를 쓴다
s1["절전이 안 된다"] --> c1["powercfg /requests"]
s2["혼자 깨어난다"] --> c2["powercfg /lastwake와 /waketimers"]
s3["타임라인을 확인하고 싶다"] --> c3["이벤트 로그의 Kernel-Power"]
c1 -.-> note["잊은 절전 억제도 여기에 나온다"]
그림 9: 증상은 조사 명령 세 계열에 대응한다. 먼저 「방금 잠들었는지」를 확인하고 나눈다.
티켓 대응에서는 먼저 「직전에 PC가 잠들어 있었는지(뚜껑을 닫았는지)」를 묻는 것만으로 분리가 크게 빨라집니다.
7. 정리
- 절전은 거부할 수 없습니다. 사전 알림(PBT_APMSUSPEND)은 약 2초 유예의 베스트 에포트이며, 긴급 시에는 오지 않습니다. 본편 설계는 재개 쪽에 둡니다.
- 재개 알림은 PBT_APMRESUMEAUTOMATIC(절전에서 재개) + PBT_APMRESUMESUSPEND(사용자 조작)입니다. 알림이 오지 않는 경우를 위해 오류 구동 재연결을 본선에 둡니다.
- 연결과 핸들은 재개를 넘기지 못한다고 가정하고, 멱등한 재연결 + 지수 백오프 + keepalive의 3종 세트를 구현합니다.
- 경과 시간 기반 작업에는 「이상 차이」 가드를 둡니다. 예약 작업은 절전 중에 돌지 않는다고 가정하고 설계합니다.
- 잠들면 안 되는 구간은
SetThreadExecutionState또는 전원 요청으로 절전을 명시적으로 억제하고, 끝나면 반드시 해제합니다. - 조사는
powercfg(/requests, /lastwake, /sleepstudy)와 Kernel-Power 이벤트 로그입니다. 티켓 대응에서는 먼저 「직전에 잠들었는지」를 묻습니다.
앱의 관점에서 절전은 「예고 없이 시간이 점프하고, 주변과의 연결이 잘린 뒤, 돌아온다」는 이벤트입니다. 그것을 이상 상황이 아니라 일상의 일부로 설계에 짜넣었는지가, 노트북 시대 업무 앱의 안정성을 가릅니다.
관련 기사
- 시리얼 통신 앱의 함정 - 1 byte 단위, 타임아웃, 플로우 컨트롤, 재접속, USB 변환, UI 프리즈를 먼저 정리
- Windows Shutdown as Seen from Your App — Surviving Exit Notifications, Restarts, and Power Loss Correctly
- Windows의 효율 모드란 무엇인가 - Windows 11의 녹색 잎 아이콘의 의미와 끄는 방법
- Windows에서 타이머 대기보다 이벤트 대기를 우선하는 이유 - 약 15.6ms 입자의 폴링을 피한다
- 「응답 없음」의 정체 ── 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). PowerCreateRequest로 만든 전원 요청 객체에 시스템·디스플레이 대기 유지 같은 요청 유형을 설정할 수 있다는 점, 진단용 이유 문자열을 붙일 수 있다는 점, 미해제 전원 요청을 powercfg /requests로 열거할 수 있다는 점에 대해. ↩ ↩2
-
Microsoft Learn, Modern standby SleepStudy. powercfg /sleepstudy가 만드는 보고서로 Modern Standby 구간마다 소비 전력, 활동, 기상 이유(전원 버튼, 사용자 입력, 기상 타이머 등)를 살펴볼 수 있다는 점에 대해. ↩
관련 기사
같은 태그를 공유하는 최신 기사입니다. 더 가까운 주제로 지식을 넓힐 수 있습니다.
DllMain과 로더 락 ── 「DLL 초기화에서는 아무것도 하지 말라」는 말의 진짜 이유
DllMain에서 LoadLibrary를 호출하거나 다른 스레드와 동기화해서는 안 되는 이유를 설명합니다. 로더 락이 모든 DLL 알림을 직렬화하는 구조, 데드락이 구조적으로 확정되는 고전적 시나리오, 초기화를 미루는 올바른 설계, 행(hang)...
「응답 없음」의 정체 ── Windows가 앱의 행을 판단하는 방식과 멈추지 않는 설계
Windows의 「응답 없음」은 창이 5초 동안 메시지를 꺼내지 않았다고 OS가 판단해 고스트 창으로 바꾸는 메커니즘입니다. 그 판단의 내부, 행의 고전적 원인, 무거운 작업을 UI 스레드에서 떼어 내는 설계, 행 조사 절차를 정리합니다.
멀티스레드 실무 베스트 프랙티스 C 언어 편 ── Win32 API의 방식으로 안전하게 작성하기
C 언어 × Win32의 멀티스레드는 _beginthreadex를 이용한 스레드 생성, SRW 잠금과 조건 변수, Interlocked, 정지 이벤트+WaitForMultipleObjects의 정지 설계가 정석입니다. TerminateThread...
Windows 앱 외주·수탁 개발을 의뢰하기 전에 정리해야 할 것
Windows 앱의 외주·수탁 개발을 의뢰하기 전에, 기존 소프트웨어 개수, 장치 연계, COM/ActiveX, 배포·업데이트, 보수와 관련해 정리해야 할 포인트를 설명합니다.
Win32 스레드 풀 API ── CreateThreadpoolWork로 「스레드를 만들지 않는」병렬 처리
네이티브 코드에서 CreateThread를 여기저기 만들고 있지는 않은가요. Vista에서 개편된 Win32 스레드 풀 API의 work·timer·wait·io 네 객체, 클린업 그룹, 콜백에서 해서는 안 되는 일까지 1차 정보를 바탕으로 해설...
관련 토픽
이 기사와 가까운 토픽 페이지입니다. 기사를 출발점 삼아 관련 서비스와 다른 기사로 이어집니다.
Windows 기술 토픽
Windows 개발, 장애 조사, 기존 자산 활용에 관한 KomuraSoft LLC 기사를 모은 토픽 허브입니다.
이 주제와 연결되는 서비스
이 기사는 다음 서비스 페이지로 이어집니다. 가까운 입구부터 확인해 주세요.
Windows 앱 개발
상주 처리, 장비 연동, 운영 로그, 유지 보수 가능한 구조가 필요한 Windows 데스크톱 애플리케이션을 지원합니다.
자주 묻는 질문
이 기사 주제에 대해 상담 시 자주 나오는 질문을 모았습니다.
- 앱이 절전을 미리 알고 거부할 수 있나요?
- 현재 Windows에서는 알림은 받을 수 있지만 거부할 수는 없습니다. 절전 직전에 WM_POWERBROADCAST 메시지로 PBT_APMSUSPEND 이벤트가 전달되고, 여기서 파일을 닫고 상태를 저장하는 준비를 할 수 있지만, 처리에 허용되는 시간은 앱당 약 2초이며 넘기면 시스템은 기다리지 않고 진행합니다. 배터리가 임계 이하인 긴급 절전에서는 사전 알림 자체가 오지 않습니다. 따라서 「절전 전에 반드시 끝내야 한다」는 설계는 성립하지 않고, 언제 잘리든 재개 때 복구할 수 있는 설계가 필요합니다. 정말로 절전되면 안 되는 작업 구간이라면 SetThreadExecutionState 또는 전원 요청(PowerSetRequest)으로 절전을 명시적으로 억제합니다.
- 재개했음을 어떻게 감지하나요?
- 앱에 창이 있으면 WM_POWERBROADCAST를 처리합니다. 절전에서 재개하면 PBT_APMRESUMEAUTOMATIC이 오고, 재개가 사용자 조작(전원 버튼이나 키 입력)에 의한 것이면 이어서 PBT_APMRESUMESUSPEND가 옵니다. 바로 다시 절전되는 무인 재개에서는 PBT_APMRESUMEAUTOMATIC만 오므로, 재연결과 같은 필수 작업은 PBT_APMRESUMEAUTOMATIC 쪽에, 화면 갱신 같은 사용자 대면 작업은 PBT_APMRESUMESUSPEND 쪽에 두는 것이 기본 분할입니다. 창이 없는 서비스와 콘솔 앱은 RegisterSuspendResumeNotification을 DEVICE_NOTIFY_CALLBACK과 함께 쓰면 같은 알림을 콜백으로 받을 수 있습니다.
- 절전 중에도 앱을 계속 돌릴 수 있나요?
- 원칙적으로는 안 됩니다. 절전 중에는 CPU 실행 자체가 멈추고(Modern Standby 기기에서는 Desktop Activity Moderator가 데스크톱 앱을 일시 정지하며), 앱의 코드는 돌지 않습니다. 선택은 두 가지입니다. 하나는 작업 중인 동안만 절전을 억제하는 것입니다. SetThreadExecutionState에 ES_SYSTEM_REQUIRED를 지정하거나 PowerCreateRequest/PowerSetRequest로 전원 요청을 내면, 그 구간 동안 자동 유휴 절전을 억제합니다(powercfg /requests로 확인할 수 있습니다). 그래도 뚜껑을 닫는 같은 명시적 절전 동작은 막지 못하므로, 억제 중에도 재개에 대비해야 합니다. 다른 하나는 절전을 받아들이고 「재개 뒤에 따라잡는다」고 설계하는 것입니다. 야간 배치 같은 예약 작업은 작업 스케줄러의 「이 작업을 실행하기 위해 컴퓨터를 절전 모드에서 해제」로 PC를 깨울 수도 있습니다. 정말로 계속 돌아야 하는 작업은 서버나 절전하지 않도록 운용하는 서비스에 둡니다.
- 재개 뒤에 TCP 연결과 시리얼 포트가 안 되는 이유는 무엇인가요?
- 네트워크 어댑터와 USB 장치도 절전 중에는 저전력 상태로 내려가기 때문입니다. TCP 연결은 이미 상대 측이나 NAT·방화벽의 타임아웃으로 폐기되어 있고, 재개 후의 송수신은 오류를 반환합니다(오류가 날 때까지 알아차리지 못하는 경우가 많습니다). USB-시리얼 어댑터 등은 재개 때 장치 제거와 재삽입으로 취급되는 경우가 있어, 열어 둔 핸들이 무효가 됩니다. 둘 다 「핸들과 연결은 재개를 넘기지 못한다」는 가정이 올바르고, 재개 알림이나 통신 오류에서 연결을 다시 만드는 재연결 로직이 정답입니다. 주기적 keepalive와 실패 시 지수 백오프 재시도를 조합하는 것이 정석입니다.
- 예상치 못한 절전이나 예상치 못한 재개는 어떻게 조사하나요?
- 첫 도구는 powercfg 명령입니다. 「절전이 안 된다」 방향이면 powercfg /requests가 절전을 막고 있는 전원 요청을 낸 프로세스와 드라이버를 나열합니다. 「혼자 깨어난다」 방향이면 powercfg /lastwake가 가장 최근 기상 이유를, powercfg /waketimers가 현재 기상을 예약해 둔 타이머를 보여 줍니다. Modern Standby 기기에서는 powercfg /sleepstudy가 절전 중의 소비와 활동 보고서를 만듭니다. 절전과 재개 이력은 이벤트 로그(System 로그의 Kernel-Power 원본)에도 기록되므로, 「언제 잠들었고, 언제 왜 깨어났는지」를 타임라인으로 확인할 수 있습니다.