スリープ・休止・Modern Standbyと長時間稼働アプリ ── 「夜中に止まっていた」を設計で防ぐ
· 小村 豪 · スリープ, Modern Standby, 電源管理, SetThreadExecutionState, 長期稼働, タイマー, 常駐アプリ, C#, .NET, 不具合調査, Windows開発, 技術相談
「監視アプリを夜通し動かしていたはずが、朝見たらグラフが深夜1時で止まっていた」「デスクトップPCでは何か月も安定していた収集ツールが、ノートPCに置き換えた途端に記録が歯抜けになった」── 長時間動き続ける業務アプリの相談で、この症状は定番中の定番です。ログを見ると例外もクラッシュもなく、ただ数時間分の記録がすっぽり抜けている。犯人はアプリのバグではなく、Windowsの電源管理であることが非常に多いのです。
厄介なのは、「スリープ」と一口に言っても中身が1種類ではないことです。従来のS3スリープ、休止状態(S4)、そして近年のノートPCで主流のModern Standby(S0 low power idle)では、アプリから見える止まり方も、対策の効き方も違います。特にModern Standbyは「スリープ中もシステムは動いている」という触れ込みから誤解されがちですが、デスクトップアプリはむしろ積極的に止められます。
この記事では、スリープの種類とスリープ中のアプリの挙動を最低限だけ押さえたうえで、「スリープをさせない」「スリープを前提にする」「決まった時刻に起こす」という3つの設計をどう使い分けるかを、実装例と判断表つきで整理します。
1. まず結論
- Windowsのスリープには従来のS3スリープ・休止状態(S4)・Modern Standby(S0 low power idle)があり、Modern Standby対応機はS1〜S3をサポートしません。自分のPCがどれかは
powercfg /aで確認できます。123 - Modern Standby中もデスクトップアプリは動き続けません。DAM(Desktop Activity Moderator)がデスクトッププロセスのスレッドをサスペンドします(セッション0のサービスはスロットリング)。「S0だから動くはず」という前提で設計しないでください。4
- スリープ中はスレッドが実行されず、タイマーの期限の数え方もAPIの世代で異なります。Windows 8以降、相対指定のタイマーや待機(
SetWaitableTimerの相対指定、SleepEx等)はスリープ中カウントが進まず、残り時間を復帰後に持ち越します。56 .NETのタイマーは .NET 10 まではスリープ時間を数える実装(スリープ中に期限が来ていれば復帰直後に発火)で、.NET 11 から数えない方式に変わります。6 経過時間APIも、スリープ時間を含むもの(GetTickCount、QueryPerformanceCounter=Stopwatch)と含まないもの(QueryUnbiasedInterruptTime)が混在します。78 - スリープ中にアイドルになったTCP接続は、NAT・ファイアウォール・ロードバランサーなどの中間機器のアイドルタイムアウトで黙って破棄されていることがあります(例: Azure Load Balancerの既定は4分で通知なしドロップ)。復帰後は再接続前提で設計します。94
- スリープを抑止する正攻法は
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)です。ただし効くのは無操作タイムアウト起因の自動スリープだけで、ユーザーが電源ボタンやふた閉じで指示したスリープは防げません。必要な区間だけ設定し、終わったら必ずクリアします。1011 - 抑止が効いているかは
powercfg /requestsで確認できます。PowerCreateRequest系APIなら要求に理由文字列を付けられ、この一覧に表示されるため運用調査に強くなります。121314 - スリープを前提にするなら、.NETでは
SystemEvents.PowerModeChanged、Win32ではWM_POWERBROADCAST(PBT_APMSUSPEND / PBT_APMRESUMEAUTOMATIC)で検知します。サスペンド通知の猶予は1アプリあたり約2秒しかなく、バッテリー切迫時は通知なしでスリープすることもあります。15161718 - 決まった時刻に確実に動かすなら、タスクスケジューラの「タスクの実行時にスリープを解除する」(WakeToRun)が第一候補です。タスク完了までシステムを起きたままにしてくれます。ただし電源オプションのウェイクタイマー許可に依存するため、実機での起床確認が必須です。1920
2. Windowsのスリープは1種類ではない
最初に、対策を考える前提となる3つの状態だけ押さえます。
| 状態 | 通称 | 中身 | アプリから見ると |
|---|---|---|---|
| S3 | 従来のスリープ | CPU停止、RAMだけ通電して状態保持 | 計算処理は一切走らない1 |
| S4 | 休止状態 | メモリ内容を休止ファイルに書いて電源断 | 同上。復帰はファイルからの復元1 |
| S0 low power idle | Modern Standby | システムは低電力で部分的に稼働し続け、瞬時に復帰 | デスクトップアプリはDAMに止められる24 |
S3とS4は「システムが計算タスクを何も実行していない、見かけ上オフの状態」です。1 一方Modern Standbyは、スマートフォンの電源モデルに近い方式で、画面オフ中もネットワーク接続を維持したまま低電力で待機し、電源ボタンから1秒未満で復帰します。Modern Standbyをサポートする機種はS1〜S3を使いません。221
ここで重要なのが、Modern Standby対応機に載っているDAM(Desktop Activity Moderator)です。DAMはスタンバイ突入時にデスクトップアプリの実行をS3スリープと同等になるよう抑え込む仕組みで、対話セッションのプロセスは全スレッドがサスペンドされ、セッション0のサービスはスロットリング(大半の時間サスペンドされ、断続的にだけ実行)されます。4 つまり「Modern Standbyならスリープ中もアプリが動くのでは」という期待は逆で、アプリ視点ではS3と同じく止まる、しかもS3と違って「システム自体は動いているのにアプリだけ止まる」ため、時刻のずれやタイマー挙動の不整合として現れる、と理解しておくのが安全です。4
自分のPC(顧客の現場のPC)がどちらの方式かは、管理者不要で次のコマンドで確認できます。3
> powercfg /a
以下のスリープ状態がこのシステムで利用可能です:
スタンバイ (S0 低電力アイドル) ネットワークに接続されています
休止状態
...
スタンバイ (S3) と出ればS3機、S0 低電力アイドル と出ればModern Standby機です。「ノートPCに変えたら記録が抜けるようになった」という相談では、まずこれを確認します。
3. スリープ中・復帰後にアプリはどうなるか
3.1. スレッドとタイマー
スリープ中(S3/S4、およびDAMサスペンド中)はスレッドが実行されません。14 見落とされがちなのは、タイマーや待機の「期限」がスリープ時間をどう数えるかで、これはAPIの層によって扱いが分かれます。
- Win32の相対タイマー(
SetWaitableTimer/SetWaitableTimerExの相対指定)は、Windows 7以前は低電力状態の時間もカウントに含めていました(スリープ中もカウントダウンが進む)が、Windows 8以降は含めません。スリープをまたいだ相対タイマーは、復帰後に残り時間ぶん待ってから発火します。5 - 一方、タイムアウトを指定する待機API(
SleepEx/WaitForMultipleObjectsExなど)は、Windows 8以降、スリープ等の非稼働時間をカウントしません。残り時間はスリープをまたいで持ち越されます。6 - .NETのマネージドタイマー(
System.Threading.Timer等)の発火タイミングは、ランタイムのバージョンで変わります。Environment.TickCount64が .NET 10まではスリープ時間を含み(GetTickCount64ベース)、.NET 11からは含まない(QueryUnbiasedInterruptTimeベース)に変更されるためで、変更ドキュメント自身が「復帰直後にタイマーが発火しなくなるコードがあり得る」と注意しています。6
つまり「10秒間隔の System.Threading.Timer で計測していたアプリが8時間スリープした」場合、8時間分がまとめて発火することはどのみちありませんが、復帰直後に1回すぐ発火するのか、残り時間を待ってから発火するのかは、APIの層とランタイムのバージョン次第です。どちらにせよスリープ中のサンプルは欠測になります。「復帰直後の発火」に依存して立て直し処理を組むのではなく、第5章の復帰イベントで明示的に再スケジュールするのが安全です。
3.2. 経過時間の計測がずれる
経過時間APIには、スリープ時間を含むものと含まないものが混在しています。
| API | スリープ時間 |
|---|---|
| GetTickCount / GetTickCount64 | 含む7 |
| QueryPerformanceCounter(= .NET の Stopwatch の基盤) | 含む(standby・hibernate・connected standby)8 |
| QueryUnbiasedInterruptTime | 含まない(working stateの時間のみ)227 |
| Environment.TickCount / TickCount64 | .NET 10 まで含む(GetTickCount64ベース)、.NET 11 から含まない(QueryUnbiasedInterruptTimeベース)に変更6 |
「Stopwatchで10秒たったら次のサンプル」というコードは、スリープをまたぐと「8時間と10秒たった」ことになりますし、逆にTickCountベースの経過判定は .NET 11 移行で挙動が変わります。「処理にかかった時間」はStopwatch、「次に動くべき壁時計時刻」は DateTime/DateTimeOffset で管理し、復帰イベント(第5章)で基準を取り直す、という役割分担にしておくと、スリープにもランタイム更新にも振り回されません。短周期タイマーの設計自体の話は「WindowsでSleep(1)よりイベント待機を優先すべき理由」で扱っています。
3.3. TCP接続は「黙って」死んでいる
スリープ中、アプリは通信できないので接続はアイドルになります。問題は経路上の機器です。NATやファイアウォール、ロードバランサーといった中間機器はアイドルなフローをタイムアウトで破棄しますが、多くの構成では破棄を両端に通知せず黙って落とします。たとえばAzure Load Balancerの既定動作は「アイドルタイムアウト(既定4分)に達したフローをサイレントにドロップ」です。9 社内のルーターや装置側の組み込みTCPスタックにも同種のタイムアウトはあります。
その結果、復帰後のアプリのソケットは一見正常なまま、次の送信でエラーになるか、応答待ちでタイムアウトまで固まります。DAMのドキュメントも、プロセスサスペンドが接続の寿命やハンドシェイクに与える影響を考慮するよう明記しています。4 さらにModern Standby機では、バッテリー駆動時は既定でスリープ中のネットワーク活動そのものが静止されます(Adaptive Connected Standby)。23 復帰イベントを受けたら接続は疑って破棄・再接続するのが定石です。接続が「生きているように見えて死んでいる」問題の切り分けは「TCP再送で産業用カメラ通信が止まる原因と切り分け」も参考にしてください。
4. スリープを「させない」 ── SetThreadExecutionStateと電源要求
計測中の数時間だけはスリープされては困る、という場合の正攻法が SetThreadExecutionState です。C#からはP/Invokeで呼びます。
using System.Runtime.InteropServices;
internal static class PowerGuard
{
[Flags]
private enum EXECUTION_STATE : uint
{
ES_CONTINUOUS = 0x80000000,
ES_SYSTEM_REQUIRED = 0x00000001,
ES_DISPLAY_REQUIRED = 0x00000002,
}
[DllImport("kernel32.dll", SetLastError = true)]
private static extern EXECUTION_STATE SetThreadExecutionState(EXECUTION_STATE esFlags);
/// <summary>計測開始時に呼ぶ: 自動スリープを抑止する(Endと同じスレッドから呼ぶこと)</summary>
public static void Begin() =>
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS |
EXECUTION_STATE.ES_SYSTEM_REQUIRED);
/// <summary>計測終了時に必ず呼ぶ: 抑止を解除する(Beginと同じスレッドから呼ぶこと)</summary>
public static void End() =>
SetThreadExecutionState(EXECUTION_STATE.ES_CONTINUOUS);
}
押さえるべき仕様は次のとおりです。
ES_CONTINUOUSを付けると、次にES_CONTINUOUS付きで呼び直すまで効果が持続します。付けない場合はアイドルタイマーを1回リセットするだけなので、持続させたければ定期的に呼び続ける必要があります。10ES_SYSTEM_REQUIREDはシステムのスリープを、ES_DISPLAY_REQUIREDはディスプレイオフを抑止します。バックグラウンド計測なら前者だけで十分です。画面は消えてよいのにES_DISPLAY_REQUIREDまで立てるのは電力の無駄です。10- ユーザーが電源ボタンを押した・ふたを閉じたことによるスリープは防げません。この関数が効くのは無操作タイムアウト起因の自動スリープだけです。ユーザーの明示操作は尊重すべきである、と公式ドキュメントにも明記されています。10
- システムは
SetThreadExecutionStateを呼んだスレッドを数えており、カウントがゼロになりユーザー入力もなければスリープに入ります。11 プロセスが異常終了すれば抑止も消えるので、「抑止したまま解除し忘れて永遠にスリープしないPC」になる心配は再起動すれば解消しますが、逆に言えばクラッシュ耐性の担保にはなりません。 - 名前のとおり、この関数が設定するのは呼び出したスレッドの実行状態です。10 設定と解除は同じスレッドで行ってください。
async/awaitの継続は別のスレッドプールスレッドで実行されることがあるため、awaitを挟んでBegin()とEnd()を呼ぶ実装では、解除がスリープ抑止を立てたのとは別のスレッドで空振りし、元のスレッドが生きている間ずっと抑止が残り続けます。UIスレッドのように同一性が保証されるスレッドに固定して呼ぶのが安全で、スレッドをまたぐ設計が必要ならこの後で触れるハンドルベースの電源要求APIを使ってください。
Windows 7以降には、同じ目的のより新しいAPIとして電源要求(PowerCreateRequest / PowerSetRequest / PowerClearRequest)もあります。こちらは要求作成時に REASON_CONTEXT で理由の文字列を渡せるのが実務上の利点で、要求種別には PowerRequestSystemRequired のほか、Modern Standby機でのプロセスサスペンドを抑止する PowerRequestExecutionRequired があります。1413 公式のベストプラクティスは「シナリオ直前にSet、終わったら即Clear、プロセス終了前にハンドルを後始末」です。13
ただしModern Standby機には重要な制限があります。バッテリー駆動のModern Standbyシステムでは、SystemRequired/ExecutionRequired要求はスリープタイムアウト超過の5分後に打ち切られます。また電源方式を問わず、ユーザー操作(電源ボタン・ふた閉じ・スタートメニューのスリープ)によるスリープ突入時には要求は終了します。13 つまり「ノートPCで、ふたを閉じられても、バッテリーでも動き続ける」はアプリの努力では実現できません。そういう要件は電源設定と運用(ふたを閉じてもスリープしない設定、AC給電)で担保するものです。
抑止が実際に効いているかは、管理者権限のコマンドプロンプトで確認できます。
> powercfg /requests
SYSTEM:
[PROCESS] \Device\HarddiskVolume3\Apps\SensorLogger.exe
powercfg /requests はスリープ・画面オフを妨げている電源要求を列挙するコマンドで、「なぜかスリープしないPC」の調査にも、自アプリの抑止確認にも使えます。12 逆に、管理者が powercfg /requestsoverride で特定プロセスの要求を無視する設定を入れられることも知っておいてください。12 抑止APIは「お願い」であって絶対ではない、というのが設計の前提です。
最後に行儀の話です。アプリ起動中ずっと ES_CONTINUOUS | ES_SYSTEM_REQUIRED を立てっぱなしにする実装は、ユーザーが設定した電源プランを常駐アプリが恒久的に殺すことを意味します。ノートPCならバッテリーを消耗させ、共有PCなら他の用途にも影響します。抑止は「スリープされては困る処理が実際に走っている区間」だけに絞るのが原則です(公式ドキュメントの例も「録画開始で設定、録画完了でクリア」です10)。なお、ユーザー側の一時的な回避策としてはPowerToys Awakeがあり、これも内部的には同じ仕組み(実行状態を要求するスレッド)で動いています。24 アプリに抑止を実装するか、運用ツールに任せるかの線引きにも使えます。
5. スリープを「前提にする」 ── 検知・再接続・欠測記録
常駐監視や収集アプリの多くは、スリープを禁止するよりもスリープと共存するほうが筋のよい設計になります。必要なのは「入る前に知る」「復帰を知る」「復帰後に立て直す」の3点です。
.NETでは Microsoft.Win32.SystemEvents.PowerModeChanged が入口です。15
using Microsoft.Win32;
SystemEvents.PowerModeChanged += OnPowerModeChanged;
private void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
switch (e.Mode)
{
case PowerModes.Suspend:
// 猶予は短い: バッファをフラッシュし、計測停止時刻を記録するだけに絞る
_logger.Info("suspend at {0:O}", DateTimeOffset.Now);
_collector.Pause();
break;
case PowerModes.Resume:
// 1) 欠測区間をデータとして残す
_logger.Info("resume at {0:O}", DateTimeOffset.Now);
// 2) 接続は死んでいる前提で破棄して再接続
_connection.Reset();
// 3) 壁時計基準でスケジュールを再計算してタイマーを張り直す
_scheduler.Rebase(DateTimeOffset.Now);
// 4) 立て直しが済んでから収集を明示的に再開する(Pauseしたままにしない)
_collector.Resume();
break;
}
}
このイベントには2つの注意点が公式に明記されています。メッセージポンプが回っていないと発生しないこと(Windowsサービスでは隠しフォーム等が必要)、そしてstaticイベントなので購読解除を怠るとリークすることです。15 GUIアプリなら素直に使えますが、コンソール/サービス型の収集アプリでは、Win32の WM_POWERBROADCAST を受けるメッセージウィンドウを自前で用意するか、HWNDなしでコールバックを受けられる PowerRegisterSuspendResumeNotification を使います(DAM環境での通知もこの経路です)。416
Win32レベルのイベントの意味も押さえておきましょう。
- PBT_APMSUSPEND: スリープ直前の通知。1アプリあたり約2秒しか猶予がなく、超過するとシステムに中断されることがあります。ここでやるのはフラッシュと時刻記録程度に絞り、ネットワーク越しの後始末のような時間のかかる処理を書いてはいけません。1718
- PBT_APMRESUMEAUTOMATIC: 復帰のたびに必ず届く通知。再接続・再スケジュールはここに書きます。25
- PBT_APMRESUMESUSPEND: ユーザーの操作で(またはユーザーが戻ってきて)復帰した場合に、PBT_APMRESUMEAUTOMATICの後に届きます。リモートウェイク等の自動復帰では届かないため、「復帰処理」をこちらだけに書くと無人復帰時に立て直しが走りません。26
- さらに、バッテリー切迫などのクリティカルなスリープ突入では事前通知そのものが来ません。18 Suspendイベントを受け取れなかったケースでも復帰処理が成立するよう、Resume側を冪等に書いておきます。
もう1つ、復帰対応と同じくらい大事なのが欠測を欠測として記録することです。スリープをまたいだ収集データは「値がない」のではなく「システムが止まっていたので測っていない」のであり、その区間をsuspend/resumeの時刻つきでログとデータの両方に残しておくと、後からグラフの空白を見た人が障害と混同しなくなります。長期稼働アプリのログに何を残すべきかという観点は「産業用カメラ長期稼働クラッシュ調査 - ハンドルリーク編」でも扱っています。
なお、スリープと似た「気づいたら遅くなっていた」系の問題として、Windows 11の効率モード(EcoQoS)による抑制もあります。こちらは「Windows効率モードとは - 緑の葉アイコンとオフにする方法」を参照してください。
6. 決まった時刻に確実に動かす ── タスクスケジューラの起床実行
「深夜2時に集計して転送する」のような時刻起点の処理を、常駐アプリのタイマー+スリープ抑止で実現するのは筋がよくありません。夜通しスリープを殺すことになるからです。この用途はタスクスケジューラの「タスクの実行時にスリープを解除する」(WakeToRun)が本命です。
WakeToRunを有効にしたタスクは、実行時刻にスリープ・休止からコンピューターを起床させ、タスクが完了するまでシステムを起きたままにします(すでに起きていた場合も完了まで維持を要求します)。起床時に画面は消えたままのことがありますが、それで正常です。19
ただし、起床が成立するには条件があります。公式のトラブルシューティングにも挙げられているとおり、電源オプションの「スリープ解除タイマーの許可」(Allow Wake Timer)が有効であること、BIOS側のウェイク設定が有効であることが前提で、近年のノートPCは省電力設計上ウェイクを許可しない構成も珍しくありません。20 powercfg /waketimers で現在有効なウェイクタイマーを列挙できるので12、導入先の実機で「本当に起きるか」を必ず検証してください。自前アプリで起床させたい場合は、SetWaitableTimer の fResume にTRUEを渡すウェイク可能タイマーという手段もあります。このときシステムは自動起床後、無人アイドルタイマー(最低2分)の間だけ起きており、アプリが SetThreadExecutionState で「使用中」を宣言しなければ速やかに再スリープします。起床後の処理が長い場合は第4章の抑止と組み合わせる、というのが正しい合わせ技です。27
タスク自体の実行アカウント・0x1で終わる問題・多重起動防止といった運用設計は「タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計」にまとめています。
7. 判断表 ── 抑止か、復帰対応か、起床か
3つの設計は排他ではなく、アプリ種別ごとに主・従を決めて組み合わせるものです。
| アプリ種別 | 第一候補 | 組み合わせ・補足 |
|---|---|---|
| 計測・データ収集(数時間〜数日の連続測定) | 測定区間だけ ES_SYSTEM_REQUIRED で抑止 |
復帰対応も必ず実装(ユーザー操作のスリープは防げない10)。バッテリー駆動のModern Standby機は5分打ち切りがあるためAC給電を要件に13 |
| 夜間バッチ・定時転送 | タスクスケジューラ + WakeToRun19 | 常駐+抑止より省電力で確実。ウェイクタイマー許可の確認が前提20 |
| 常駐監視・通知エージェント | スリープ前提(PowerModeChangedで検知→再接続・再スケジュール・欠測記録)15 | 監視が主目的の専用機なら、アプリでなく電源プラン側でスリープを無効化する |
| デスクトップ操作ツール(プレゼン・ダッシュボード表示等) | 表示中だけ ES_DISPLAY_REQUIRED を ES_SYSTEM_REQUIRED と併用10 |
表示終了で必ずクリア。常時表示端末なら電源設定で対応 |
| 24/7の装置制御・ラインPC | 電源設定でスリープ自体を無効化(運用で担保) | アプリの抑止APIを保険にしない。powercfg /requests を定期点検に使う12 |
判断の軸は2つです。「止まってよい時間帯があるか」(あるならタスクスケジューラ、ないなら電源設定)と、「誰のPCで動くか」(ユーザーの私物・共用ノートで動くアプリほど、抑止ではなく復帰対応に寄せる)です。
8. まとめ
- スリープにはS3・休止(S4)・Modern Standby(S0 low power idle)があり、
powercfg /aで判別できます。Modern Standby機でもデスクトップアプリはDAMでサスペンドされるため、「スリープ中も動く」前提は成立しません。 - スリープ中はスレッドもタイマーも進みません。Windows 8以降、相対タイマー・待機はスリープ時間を数えず残り時間を持ち越し、.NETのタイマーも .NET 11 から同じ挙動になります(.NET 10までは復帰直後に発火し得ます)。経過時間APIはスリープ時間を含む/含まないが混在します。経過はStopwatch、壁時計はDateTimeで持ち、復帰時に基準を取り直してください。
- TCP接続は中間機器のアイドルタイムアウトで黙って死にます。復帰イベントで破棄・再接続が定石です。
- 抑止は
SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED)を必要区間だけ。ユーザー操作のスリープは防げず、Modern Standby機のバッテリー駆動では5分で打ち切られます。確認はpowercfg /requests。 - 復帰対応は
SystemEvents.PowerModeChanged/WM_POWERBROADCASTで。サスペンド通知の猶予は約2秒、通知なしのスリープもあるため、Resume側を冪等に書き、欠測区間を記録します。 - 定時実行はタスクスケジューラのWakeToRunが本命。ウェイクタイマーの電源設定と実機での起床確認まで含めて設計してください。
関連記事
- タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計
- WindowsでSleep(1)よりイベント待機を優先すべき理由
- TCP再送で産業用カメラ通信が止まる原因と切り分け
- 産業用カメラ長期稼働クラッシュ調査 - ハンドルリーク編
- Windows効率モードとは - 緑の葉アイコンとオフにする方法
関連する相談領域
合同会社小村ソフトでは、計測・監視・データ収集など長時間稼働するWindowsアプリの設計と実装、「夜中に止まっていた」「記録が歯抜けになる」といった長期稼働特有の不具合の調査を扱っています。スリープ・電源管理が絡む再現しづらい症状の切り分けもご相談ください。
参考リンク
-
Microsoft Learn, System Sleeping States. S1〜S4がスリープ状態であり計算タスクを実行しないこと、S3はメモリのみ保持・S4は休止ファイルへ保存すること、powercfg /a で利用可能なスリープ状態を列挙できることについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, System power states. S0 low power idle(Modern Standby)では低電力のままシステムが部分的に動作し続けること、Modern Standby対応SoCシステムはS1〜S3を使わないこと、クリティカルな遷移では通知が行われないことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Overview of Modern Standby Testing and Diagnostics. powercfg /a でModern Standby対応(Standby (S0 Low Power Idle) の表示)を判別できることについて。 ↩ ↩2
-
Microsoft Learn, Desktop Activity Moderator. DAMがデスクトップアプリの実行をS3同等に抑え込むこと、対話セッションのプロセスは全スレッドサスペンド・セッション0はスロットリングされること、サスペンド前のWM_POWERBROADCAST通知、タイマー挙動や稼働時間と壁時計の不整合、接続寿命への考慮が必要なことについて。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, SetWaitableTimerEx function. 相対時間指定のタイマーが、Windows 7以前は低電力状態の時間を含んで(スリープ中もカウントダウンが進んで)いたのに対し、Windows 8以降は含まない(スリープ中はカウントダウンが進まない)ことについて。 ↩ ↩2
-
Microsoft Learn, Environment.TickCount made consistent with Windows timeout behavior. Environment.TickCount/TickCount64が.NET 10まではGetTickCount64ベース(スリープ時間を含む)で、.NET 11からQueryUnbiasedInterruptTimeベース(含まない)に変更される破壊的変更、Windows 8以降でタイムアウトを指定する待機API(SleepEx/WaitForMultipleObjectsEx)が非稼働時間をカウントしなくなっていたこと、この変更により復帰直後にタイマーが発火しなくなるコードがあり得ることについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, Windows Time. GetTickCount/GetTickCount64の経過時間がスリープ・休止の時間を含むこと、QueryUnbiasedInterruptTimeはworking stateの時間のみを含むことについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Acquiring high-resolution time stamps. マネージドコードのSystem.Diagnostics.StopwatchがQPCを時刻基盤とすること、QueryPerformanceCounterがstandby・hibernate・connected standby中の時間を含むティック数を返すことについて。 ↩ ↩2
-
Microsoft Learn, Load Balancer TCP Reset and Idle Timeout. ロードバランサーの既定動作がアイドルタイムアウト(既定4分)到達時にフローをサイレントにドロップすることであり、TCPリセット送信は明示的に有効化する機能であること、対策としてTCP keep-aliveが用いられることについて。 ↩ ↩2
-
Microsoft Learn, SetThreadExecutionState function. ES_CONTINUOUS/ES_SYSTEM_REQUIRED/ES_DISPLAY_REQUIREDの意味、ES_CONTINUOUSなしではアイドルタイマーのリセットのみであること、ユーザーによるスリープ操作は防げないこと、必要な処理の間だけ設定し完了後にクリアする使用例について。 ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8
-
Microsoft Learn, System Sleep Criteria. システムがSetThreadExecutionStateを呼んだアプリ/スレッドをカウントし、カウントがゼロでユーザー入力がなければスリープに入ることについて。 ↩ ↩2
-
Microsoft Learn, Powercfg command-line options. /requests がスリープや画面オフを妨げる電源要求を列挙すること、/requestsoverride で特定プロセスの要求を無視できること、/waketimers で有効なウェイクタイマーを列挙できることについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, PowerSetRequest function. PowerRequestSystemRequired/PowerRequestExecutionRequired等の要求種別、Modern StandbyのDC電源では要求がスリープタイムアウト超過の5分後に打ち切られること、ユーザー起因のスリープ突入で要求が終了すること、理由文字列を付け直前にSet・直後にClearするベストプラクティスについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, PowerCreateRequest function. REASON_CONTEXTを指定して電源要求オブジェクトを作成し、不要になったらCloseHandleで解放することについて。 ↩ ↩2
-
Microsoft Learn, SystemEvents.PowerModeChanged Event. サスペンド/レジューム時に発生するイベントであること、メッセージポンプが動いていないと発生しないこと(サービスでは隠しフォーム等が必要)、staticイベントのため購読解除しないとリークすることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, WM_POWERBROADCAST message. 電源管理イベントがWM_POWERBROADCASTメッセージ(PBT_APMSUSPEND/PBT_APMRESUMEAUTOMATIC/PBT_APMRESUMESUSPEND等)としてウィンドウに通知されることについて。 ↩ ↩2
-
Microsoft Learn, PBT_APMSUSPEND event. サスペンド直前に通知されること、処理の猶予が約2秒であり超過するとシステムに中断されうることについて。 ↩ ↩2
-
Microsoft Learn, System Power Management Events. クリティカルバッテリー等による緊急サスペンドでは事前通知が行われないこと、サスペンド通知の処理はアプリごとに最大2秒でタイムアウトすることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, ITaskSettings::get_WakeToRun method. WakeToRunがタスク実行時にコンピューターを起床させ、タスク完了まで起きたままにすること、起床時に画面が消えたままの場合があることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Automatic maintenance. 定時起床が動作しない場合の確認項目として、BIOSのウェイク設定、電源オプションの「Allow Wake Timer」、タスクのWakeToRun設定が挙げられていること、近年のノートPCではS3起床を許可しない構成が一般的であることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, What is Modern Standby. Modern StandbyがS0低電力アイドルモデルでネットワーク接続を維持したまま瞬時のオン/オフを実現すること、復帰(電源ボタンから画面点灯)が1秒未満であることについて。 ↩
-
Microsoft Learn, QueryUnbiasedInterruptTime function. unbiased interrupt timeがworking stateの時間のみを数え、スリープ・休止の時間を含まないことについて。 ↩
-
Microsoft Learn, Modern standby network connectivity. Adaptive Connected Standbyにより、バッテリー駆動時は必要とするシナリオがない限りスリープ中のネットワーク活動が静止されることについて。 ↩
-
Microsoft Learn, PowerToys Awake utility. 電源プランを変更せずにPCを起きたままにするユーティリティであり、マシン状態を要求するバックグラウンドスレッドを生成する仕組みで動作すること、終了すると通常の電源プラン動作に戻ることについて。 ↩
-
Microsoft Learn, PBT_APMRESUMEAUTOMATIC event. 復帰のたびに必ず配信されるイベントであり、ユーザーの存在を示すものではないこと、ユーザー活動を検出するとその後にPBT_APMRESUMESUSPENDが配信されることについて。 ↩
-
Microsoft Learn, PBT_APMRESUMESUSPEND event. ユーザー起因・ユーザー検出時の復帰でPBT_APMRESUMEAUTOMATICの後に配信されること、リモートウェイクではPBT_APMRESUMEAUTOMATICのみが配信されることについて。 ↩
-
Microsoft Learn, System Wake-up Events. SetWaitableTimerのfResumeをTRUEにするとタイマーでシステムを起床できること、自動起床後は最低2分の無人アイドルタイマーが設定され、SetThreadExecutionStateで使用中を示さなければ再スリープすることについて。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
MAX_PATHとWindowsのパス・ファイル名の落とし穴 ── 260文字制限、予約名、末尾ドット、大文字小文字
Windowsの「ファイルが見つかりません」障害の定番原因であるパス・ファイル名の制限を整理します。MAX_PATH=260文字の内訳、\\?\プレフィックスとLongPathsEnabled+マニフェストによる長パス有効化、.NET Framework / .NET(Co...
ネットワークドライブとUNCパスの落とし穴 ── 業務アプリでファイルサーバー(共有フォルダ)を扱う実務
業務アプリからファイルサーバー(共有フォルダ)へ出力・取り込み・監視を行うときの定番トラブルを整理します。ドライブ文字(Z:)がログオンセッション単位でありサービスや昇格プロセスから見えない理由、Windowsサービスの実行アカウントごとに共有側で必要な権限、資格情報とエラ...
Windowsアプリのタスクトレイ常駐とトースト通知 ── NotifyIconの落とし穴とAppNotificationの選び方
業務Windowsアプリをタスクトレイに常駐させ、トースト通知でユーザーへ知らせる実装を整理します。NotifyIconの正しい使い方と「閉じるでトレイへ」の設計、Explorer再起動時の再登録、トーストAPI3種(Windows App SDK AppNotificat...
自社開発のWindowsアプリがウイルス扱いされたら ── Microsoft Defenderの誤検知対応と、性能影響との付き合い方
配布した自社開発のWindowsアプリがMicrosoft Defenderにウイルスとして検知・隔離されたときの正規の対処を整理します。機械学習・クラウド保護・レピュテーションという現代のウイルス対策の仕組み、Microsoftへの誤検知報告(ファイル申請)、隔離からの復...
Arm版Windowsで業務アプリは動くのか ── x64エミュレーション(Prism)とネイティブDLL・COMの現実
Snapdragon搭載のCopilot+ PC導入で増える「Arm機で業務アプリは動くのか」という質問に、開発者・情シス向けに答えます。Windows 11のx64エミュレーション(Prism)の仕組み、ドライバー・シェル拡張など動かない層、x64とArm64をプロセス内...
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
UI スレッド / タイマーテーマ
WPF / WinForms、UI スレッド、async/await、タイマー設計を整理するトピックです。
不具合調査 / 長期稼働テーマ
再現しにくい不具合、通信停止、長期稼働障害、失敗パス検証を整理するトピックです。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
不具合調査・原因解析
再現しにくい障害、長期稼働後の不具合、通信停止などの調査を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- アプリ実行中だけPCをスリープさせないようにするには?
- SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED) を処理の開始時に呼び、終了時に SetThreadExecutionState(ES_CONTINUOUS) でクリアするのが基本です。画面も点けたままにしたい場合だけ ES_DISPLAY_REQUIRED を足します。効くのは無操作タイムアウトによる自動スリープだけで、ユーザーが電源ボタンやふたを閉じて指示したスリープは防げません。抑止が効いているかは powercfg /requests で確認できます。
- Modern Standbyとは何ですか? 従来のスリープと何が違いますか?
- S0 low power idleとも呼ばれる新しいスリープ方式で、システムは低電力ながら部分的に動作し続け、瞬時に復帰できるのが特徴です。Modern Standby対応機は従来のS3スリープをサポートしません。ただし「動き続ける」のはOSが許可した活動だけで、デスクトップアプリはDAM(Desktop Activity Moderator)によりスレッドごとサスペンドされるため、アプリ視点ではS3と同様に止まります。自分のPCがどちらの方式かは powercfg /a で確認できます。
- スリープ復帰後にTCP接続が使えなくなるのはなぜですか?
- スリープ中はアプリが通信できないため接続がアイドル状態になり、経路上のNAT・ファイアウォール・ロードバランサーなどの中間機器がアイドルタイムアウトでフローを破棄するためです。多くの機器は破棄を通知せず黙って落とすので、アプリ側のソケットは一見正常なまま、復帰後の最初の送受信で初めてエラーになるか、タイムアウトまで固まります。復帰イベントを受けたら接続を疑って作り直すのが定石です。
- 夜間バッチを確実に動かすにはスリープ抑止とタスクスケジューラのどちらがよいですか?
- タスクスケジューラの「タスクの実行時にスリープを解除する」(WakeToRun)が第一候補です。実行時刻にPCを起床させ、タスク完了まで起きたままにしてくれるため、夜通しスリープを殺しておく必要がありません。ただしウェイクタイマーが電源オプションで無効だと起床しないので、「スリープ解除タイマーの許可」の設定と実機での起床確認が必須です。常時スリープ抑止は、その間の電力を無駄にするうえユーザーの電源設定を上書きする行儀の悪い設計になります。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク