The C# language (well, more accurately, the BCL)
has
the
ReaderWriterLockSlim
class
which has
a
WaitAsync
method
which returns a task that completes
asynchronously when the lock has been acquired.
I needed an equivalent for the
Parallel Patterns Library (PPL),
and since I couldn't find one, I ended up writing one.
(If you can find one, please let me know!)
// AsyncUILock is a nonrecursive lock that can be waited on
// asynchronously from a UI thread.
class AsyncUILock
{
public:
Concurrency::task<void> WaitAsync()
{
std::lock_guard<std::mutex> guard(mutex);
if (!locked) {
// Lock is available. Acquire it.
locked = true;
return completed_apartment_aware_task();
}// Lock is not available.
return completed_apartment_aware_task()
.then([captured_completion = completion] {
// Wait for it to become available.
return Concurrency::create_task(captured_completion);
}).then([this] {
// Then try again.
return WaitAsync();
});
}void Release()
{
std::lock_guard<std::mutex> guard(mutex);
locked = false;
auto previousCompletion = completion;
completion = Concurrency::task_completion_event<void>();
previousCompletion.set();
}private:
std::mutex mutex;
bool locked = false;
Concurrency::task_completion_event<void> completion;
};
The object consists of a std::mutex
which protects
the internal state,
a flag that indicates whether the object has been claimed,
and a task completion event that we use to signal
anybody waiting on the lock that they should check again.
I could have used an SRWLock
instead of a
std::mutex
,
but I was lazy and wanted to take advantage of the existing
std::lock_guard
.
You can perform async waits on this object in the usual manner.
For example:
AsyncUILock lock;void DoSomething()
{
lock.WaitAsync().then([]{
// do something with the lock held.
lock.Release();
});
}
or if you prefer co_await
(and you probably do):
AsyncUILock lock;void DoSomething()
{
co_await lock.WaitAsync();
// do something with the lock held.
lock.Release();
}
,/PRE>
At this point, you might decide to return an RAII type
to ensure that the lock doesn't leak.
I'll leave that as an exercise.