Skip to content
Raymond Chen edited this page Feb 25, 2021 · 3 revisions

The unique_event event handle wrapper is defined in wil/resource.h as part of the RAII resource wrappers library. It is a unique_any specialization that adds methods specific to the typical needs of dealing with events. There are three variants that can be chosen based upon the error handling style the calling code desires.

wil::unique_event e1;           // failures throw
wil::unique_event_nothrow e2;   // failures return HRESULTs
wil::unique_event_failfast e3;  // failures terminate

// Create during construction (not allowed with unique_event_nothrow)
wil::unique_event e4(wil::EventOptions::ManualReset);

// Standard operations:
e1.ResetEvent();
e1.SetEvent();

// Standard operations when going out of scope:
auto setOnExit = e1.SetEvent_scope_exit();
auto resetOnExit = e1.ResetEvent_scope_exit();

// Check if a manual reset event is signaled
if (e1.is_signaled()) {}

// Wait for an (optional) amount of time
if (e1.wait(5000)) {}

// Create or Open an event
e1.create(wil::EventOptions::ManualReset);
e1.open(L"MyEventName");
if (e1.try_create(wil::EventOptions::ManualReset, L"MyEventName")) {}
if (e1.try_open(L"MyEventName")) {}

// close the event handle prior to destruction
e1.reset();

Note that the unique_event class is purposefully the same size as that of a HANDLE so that an array of the smart pointer type can be cast for use in handle functions requiring multiple objects.

When dealing with event handles outside of unique_event, WIL defines some simple methods to emulate the same patterns:

// Standard operations when going out of scope:
auto setOnExit = SetEvent_scope_exit(handle);
auto resetOnExit = ResetEvent_scope_exit(handle);

// Check if a manual reset event is signaled
if (event_is_signaled(handle)) {}

// Wait for an (optional) amount of time
if (handle_wait(5000)) {}

unique_event has a lightweight variant wil::slim_event. See below for details.

Watching events

WIL also defines unique_event_watcher which makes it easy to subscribe to signals of an event and execute a provided function when an event is signaled. It can create the event handle for you, take ownership of an existing event handle, or duplicate a provided handle. Note that multiple signals may coalesce into a single callback.

wil::unique_event_watcher watcher;            // Failures throw exceptions
wil::unique_event_watcher_nothrow watcher;    // Failures return HRESULTs (or nullptr)
wil::unique_event_watcher_failfast watcher;   // Failures terminate the process

// Duplicates the given event handle and runs the given lambda when the event is signaled
watcher.create(event, []
{
    // code ...
});

// Takes ownership of the given unique_event and runs the given lambda when the event is signaled
watcher.create(std::move(event), []
{
    // code ...
});

// Creates an event handle (retrievable through get_event()) and runs the given lambda when signaled
watcher.create([]
{
    // code ...
});

// Retrieve the unique_event_nothrow used internally to hold the event handle
// (Exposes the full contract shown above for unique_event)
auto handle& = watcher.get_event();

// Set the event being watched
void SetEvent() const WI_NOEXCEPT { get()->m_event.SetEvent(); }

The make_event_watcher routine and its many varying flavors (multiple overloads, including make_event_watcher_nothrow and make_event_watcher_failfast) make it simple to construct an event watcher for local use:

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

Note that the watcher object (and unique_event_watcher itself) is a specialized instance of the unique_any class, allowing operations such as reset() to release the subscription.

Traps

Two methods have confusingly similar names. The reset() method closes the event handle. (This name is consistent with std::unique_ptr::reset().) If you want to reset the event, use the ResetEvent() method.

See also