MicrosoftがGitHubでMITライセンス公開しているWILのGitHub Wikiの記事を和訳・改変したものです。素人による翻訳なので、誤訳や著作権上の問題などありましたらご連絡いただけますと幸いです。
シャットダウン認識オブジェクト(原題:Shutdown aware objects)
Chris Guzak、2021/12/11、リビジョン3個
WILのエラーハンドルヘルパーはプロセスのシャットダウン中に動作の変更を許可するヘルパーが含まれます。通常は不要な動作のスキップに使用されます。
全ての関数と型はwil
名前空間内にあります。
これらのヘルパーはDLLのみで必要とされることに注意してください。実行ファイルは動的にアンロードされないためです。実行ファイルの任意のデストラクタはプロセスのシャットダウン時に実行される必要があります。
関数
ProcessShutdownInProgress
bool wil::ProcessShutdownInProgress();
この関数はシャットダウン認識オブジェクトの基礎となります。プロセスのシャットダウン中にtrue
を返します。
WILにプロセスのシャットダウン中を知らせるためにDllMain
関数のDLL_PROCESS_DETACH
ハンドラでwil::DLLMain
(後述)を呼び出す必要があります。
実行ファイルはDLL_PROCESS_DETACH
通知を受け取らないため、この関数は実行ファイルのWILオブジェクトには無効です。しかし、実行ファイルは動的アンロードできないため、シャットダウン認識オブジェクトは不要です。
DLLMain
void wil::DLLMain(HINSTANCE, DWORD reason, void* reserved);
DllMain
関数はwil::DLLMain
関数に全て転送してください。WILのプロセスシャットダウン認識に必要です。
具体例:
BOOL CALLBACK DllMain(HINSTANCE hinst, DWORD reason, void* reserved) { // WILにプロセスのライフタイムを知らせる。 wil::DLLMain(hinst, reason, reserved); ... 通常のDllMainコードをここへ記述します。 ... }
WILのDLLMain
関数は通常のDllMain
関数と大文字小文字が異なることに注意してください。
シャットダウン認識オブジェクト
3種類のシャットダウン認識オブジェクトがあり、複雑です。いずれもT
オブジェクトをラップします。
wil::object_without_destructor_on_shutdown<T>
は自動的にT
を作成します。プロセスのシャットダウン中、T
をデストラクトせずにリークさせます。wil::shutdown_aware_object<T>
は自動的にT
を作成します。プロセスのシャットダウン中、T
をデストラクトさずに特殊なProcessShutdown
メソッドを呼び出します。wil::manually_managed_shutdown_aware_object<T>
は明示に構築及び破壊されます。プロセスのシャットダウン中、T
をデストラクトせずに特殊なProcessShutdown
メソッドを呼び出します。
上記の動作と必要条件を表で示します。
ラッパークラス | object_without_ destructor_on_ shutdown<T> |
shutdown_aware_ object<T> |
manually_managed_ shutdown_aware _object<T> |
---|---|---|---|
T の構築 |
自動 | 自動 | construct() 呼び出し時 |
T の破壊 |
自動 | 自動 | destroy() 呼び出し時 |
プロセスのシャットダウン中 | 何もしない | T::ProcessShutdown() |
T::ProcessShutdown() |
プロセスのシャットダウン中以外 | T の破壊 |
T の破壊 |
T の破壊 |
T の構築 |
public既定コンストラクタ | public既定コンストラクタ | public既定コンストラクタ |
T の破壊 |
publicデストラクタ | publicデストラクタ | publicデストラクタ |
他の必要条件 | publicメソッドvoid ProcessShutdown() |
publicメソッドvoid ProcessShutdown() |
用途を以下に示します。
ラッパークラス | object_without_ destructor_on_ shutdown<T> |
shutdown_aware_ object<T> |
manually_managed_ shutdown_aware _object<T> |
---|---|---|---|
宣言 | グローバル変数として宣言 | グローバル変数として宣言 | グローバル変数として宣言 |
DLL_PROCESS_ATTACH 中 |
construct() の呼び出し |
||
DLL_PROCESS_DETACH 中 |
destroy() の呼び出し |
||
デストラクタ | 全てクリーンアップ | 全てクリーンアップ | 全てクリーンアップ |
ProcessShutdown() |
N/A | 最小限のクリーンアップ | 最小限のクリーンアップ |
T
はリークされるため、アンロード可能なDLL中での使用はアンロード時のリークとなることに注意してください。これらのヘルパーはDLLが決してアンロードされない場合のみ使用してください。
最小限のクリーンアップは遅延書き込みデータのフラッシュ等からなるでしょう。
manually_managed_shutdown_aware_object
の場合、construct()
はオブジェクトが空か破壊済みの場合のみ呼び出されるでしょう。また、destroy()
はオブジェクトが構築済みの場合のみ呼び出されるでしょう。二重構築や二重破壊は未定義動作です。
3つのテンプレートクラスはいずれも以下のメンバー関数を持ちます。
T& get()
ラップするオブジェクトの参照を返します。
具体例:
class FeatureUsageData { public: FeatureUsageData() = default; ~FeatureUsageData() { SaveUsageData(); } void ProcessShutdown() { SaveUsageData(); } void LogUsage(std::string const& feature) { auto guard = m_lock.lock_exclusive(); ++m_usage[feature]; } private: wil::srwlock m_lock; std::map<std::string, int> _usage; }; wil::shutdown_aware_object<FeatureUsageData> featureUsageData;
この架空のクラスは機能の使用状況統計を記録します。使用状況統計はm_usage
マップにキャッシュされます。DLLがアンロードまたはプロセスが終了されるとき、使用状況統計は架空のSaveUsageData
メソッドにより保存されます。プロセスの終了時、使用状況データは保存されますが、マップは破壊されません。それにより、不必要な作業を短絡的に省けます。
著作権表示
この記事は以下の著作物を使用しています。
Copyright (c) Microsoft Corporation. All rights reserved. https://github.com/microsoft/wil/blob/master/LICENSE