potisanのプログラミングメモ

趣味のプログラマーがプログラミング関係で気になったことや調べたことをいつでも忘れられるようにメモするブログです。はてなブログ無料版なので記事の上の方はたぶん広告です。記事中にも広告挿入されるみたいです。

WIL GitHub Wiki イベントハンドラの和訳・改変

MicrosoftがGitHubでMITライセンス公開しているWILのGitHub Wikiの記事を和訳・改変したものです。素人による翻訳なので、誤訳や著作権上の問題などありましたらご連絡いただけますと幸いです。

イベントハンドラ(原題:Event handles)

Raymond Chen、2020/8/25、リビジョン2個

unique_eventイベントハンドルラッパーはRAII resource wrappers(原文)の一部としてwil/resource.hに定義されています。これはイベント処理に特有のメソッドを追加した特殊化unique_any(原文)です。呼び出し側コードの要求するエラー処理スタイルに基づいて3つの版があります。

wil::unique_event e1;           // 失敗は例外をスローする。
wil::unique_event_nothrow e2;   // 失敗は`HRESULT`を返す。
wil::unique_event_failfast e3;  // 失敗はプロセスを強制終了する。

// コンストラクタの中で作成される(unique_event_nothrowの使用は許可されない)。
wil::unique_event e4(wil::EventOptions::ManualReset);

// 標準操作
e1.ResetEvent();
e1.SetEvent();

// スコープから出るときの標準操作
auto setOnExit = e1.SetEvent_scope_exit();
auto resetOnExit = e1.ResetEvent_scope_exit();

// 手動リセットイベントがシグナルされているかチェックする。
if (e1.is_signaled()) {}

// ある(オプション)時間だけ待機する。
if (e1.wait(5000)) {}

// イベントを作成または開く。
e1.create(wil::EventOptions::ManualReset);
e1.open(L"MyEventName");
if (e1.try_create(wil::EventOptions::ManualReset, L"MyEventName")) {}
if (e1.try_open(L"MyEventName")) {}

unique_eventクラスは意図的にHANDLEと同じサイズであり、その配列はキャストにより複数オブジェクトを要求する処理関数で使えることに注意してください。

unique_eventの外部でイベントハンドルを扱う場合、WILは同様のパターンをまねたいくつかの簡単な関数を定義しています。

// スコープから出る場合の標準操作
auto setOnExit = SetEvent_scope_exit(handle);
auto resetOnExit = ResetEvent_scope_exit(handle);

// 手動リセットイベントがシグナルされているかチェックする。
if (event_is_signaled(handle)) {}

// ある(オプション)時間だけ待機する。
if (handle_wait(5000)) {}

unique_eventには軽量版のwil::slim_eventがあります。詳細は以下を参照してください(訳註:記述中?)。

イベントの監視

WILはさらにunique_event_watcherを定義しています。これはイベントシグナルのサブスクライブとシグナル時の提供された関数の実行を簡単にします。また、イベントハンドルの作成、既存イベントハンドルの所有権取得、提供されたハンドルの複製を可能とします。複数のシグナルがひとつのコールバックに合体することには注意してください。

wil::unique_event_watcher watcher;            // 失敗は例外をスローする。
wil::unique_event_watcher_nothrow watcher;    // 失敗はHRESULT(またはnullptr)を返す。
wil::unique_event_watcher_failfast watcher;   // 失敗はプロセスを強制終了する。

// 与えられたイベントハンドルを複製して、イベントのシグナル時に与えられたラムダ式を実行する。
watcher.create(event, []
{
    // code ...
});

// 与えられたunique_eventの所有権を取得して、イベントのシグナル時に与えられたラムダ式を実行する。
watcher.create(std::move(event), []
{
    // code ...
});

// イベントハンドルを作成して(get_eventで取得可能)、イベントのシグナル時に与えられたラムダ式を実行する。
watcher.create([]
{
    // code ...
});

// イベントハンドルの保持に内部で使用されるunique_event_nothrowを取得する。
// (前掲のunique_eventのフルコントラクトを公開する)
auto handle& = watcher.get_event();

// イベントの監視を開始する。
void SetEvent() const WI_NOEXCEPT { get()->m_event.SetEvent(); }

make_event_watcherルーチンとその多様なフレーバー(複数のオーバーロードmake_event_watcher_nothrowmake_event_watcher_failfastを含む)はローカルで使用するイベントウォッチャーの作成を簡単にします。

auto watcher = wil::make_event_watcher(handle, []
{
    // code ...
});

ウォッチャーオブジェクト(およびunique_event_watcher自体)はunique_any class(原文)の特殊化インスタンスであり、サブスクリプションの解除にresetのような操作を使えることに注意してください。

See also

著作権表示

この記事は以下の著作物を使用しています。

Copyright (c) Microsoft Corporation. All rights reserved. https://github.com/microsoft/wil/blob/master/LICENSE