-
Notifications
You must be signed in to change notification settings - Fork 241
Mutex handles
The unique_mutex
mutex 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 a mutex. There are three variants that can
be chosen based upon the error handling style the calling code desires.
// Create an empty unique_mutex.
wil::unique_mutex m1; // failures throw
wil::unique_mutex_nothrow m2; // failures return HRESULTs
wil::unique_mutex_failfast m3; // failures terminate
// Create during construction (not allowed with unique_mutex_nothrow)
wil::unique_mutex m4(L"MyMutexName");
// Standard operations:
m1.ReleaseMutex();
// Release the mutex when the object goes out of scope.
// Assumes that somebody else has already acquired the mutex.
auto releaseOnExit = m1.ReleaseMutex_scope_exit();
// Acquire the mutex ourselves (blocking if necessary),
// and release when going out of scope.
auto releaseOnExit = m1.acquire();
// Create or Open a mutex
m1.create();
m1.open(L"MyMutexName");
if (m1.try_create(L"MyMutexName")) {}
if (m1.try_open(L"MyMutexName")) {}
The unique_mutex
types inherit all the methods of unique_ptr
:
- Move-only type supports move construction and move assignment.
-
bool is_valid()
returnstrue
if the object is wrapping a mutex. -
void reset(HANDLE other)
closes any currently-wrapped mutex and begins wrapping the passed-in mutex. -
HANDLE get()
returns the wrapped mutex handle, if any. -
HANDLE release()
detaches the wrapped mutex handle and returns it. The caller is responsible for closing the handle. -
HANDLE* addressof()
returns a pointer to the wrapped mutex handle, so that you can call a function that stores a handle. - Destructor closes the wrapped mutex handle, if any. The handle is not unlocked as part of destruction.
-
unique_mutex()
andunique_mutex(nullptr)
create an emptyunique_mutex
object. -
unique_mutex(HANDLE existing)
begins wrapping an existing mutex handle. -
unique_mutex(PCWSTR name)
creates a new mutex handle for a named mutex.
The constructor for unique_mutex
is unusual in
that passing a string creates a new mutex, behavior that is normally
the responsibility of a make_unique_xxx
-style function.
The expression unique_mutex(nullptr)
creates an empty
unique_mutex
, rather than a unique_mutex
containing an
freshly-created anonymous mutex. If you want the latter,
use unique_mutex((wchar_t*)nullptr)
or (better) explicitly
call the create()
method.
Another gotcha is that passing a pointer to an ANSI string will misinterpret the pointer as a mutex handle, rather than as a mutex name.
In the below discussion, "success/failure reported in a type-specific manner" means
Type | Success | Failure |
---|---|---|
unique_mutex |
void |
Throw an exception |
unique_mutex_nothrow |
HRESULT |
HRESULT |
unique_mutex_failfast |
void |
Fail fast |
-
mutex.try_create(PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, PSECURITY_ATTRIBUTES sa = nullptr)
attempts to open or create a named mutex (or an anonymous mutex ifname
isnullptr
). If successful, wraps the resulting mutex handle and returnstrue
. If unsuccessful, returnsfalse
. -
mutex.create(PCWSTR name, DWORD dwFlags = 0, DWORD desiredAccess = MUTEX_ALL_ACCESS, PSECURITY_ATTRIBUTES sa = nullptr)
behaves the same astry_create
except that the success/failure is reported in a type-specific manner. -
mutex.try_open(PCWSTR Name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false)
attempts to open an existing named mutex. If successful, wraps the resulting mutex handle and returnstrue
. If unsuccessful, returnsfalse
. -
mutex.open(PCWSTR Name, DWORD desiredAccess = SYNCHRONIZE | MUTEX_MODIFY_STATE, bool inheritHandle = false)
behaves the same astry_open
except that the success/failure is reported in a type-specific manner.
-
mutex.ReleaseMutex()
releases the wrapped mutex. It assumes that the mutex had already been acquired by somebody else. -
mutex.ReleaseMutex_scope_exit()
returns an RAII object that unlocks the mutex when the object destructs. It assumes that the mutex had already been locked by somebody else. -
mutex.acquire()
locks the mutex, and then returns an RAII object that unlocks the mutex when the object destructs. -
mutex.acquire(DWORD* status = nullptr, DWORD timeout = INFINITE, BOOL alertable = FALSE)
locks the mutex, optionally returning the result ofWaitForSingleObjectEx
instatus
, with an optional timeout, and with the option to wait alertably. If the acquisition times out, then the returned RAII object is empty (does not unlock the mutex at destruction).
When dealing with mutex handles outside of unique_mutex
, WIL defines
some simple methods to emulate the same RAII patterns:
// Release the mutex when the returned value goes out of scope
auto releaseOnExit = wil::ReleaseMutex_scope_exit(handle);
There are some gotchas in the use of the lock guard object
returned by the ReleaseMutex_scope_exit()
and acquire()
methods.
See Lock guard object for details.