-
Notifications
You must be signed in to change notification settings - Fork 236
Event handles
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.
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.
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.