I'm wrote Asynchronous Lock provider for reducing lock that breaks async
keyword.
All tasks with async
and await
keywords are chained by GetAwaiter().OnCompleted(Callback)
on I know. But some cases are not, for example: lock
keyword, EventObject.Wait()
, Mutex like objects... etc.
So, I think that if asynchronous chainable lock is possible, it can improve async
performance.
/// <summary>
/// Asynchronous Lock Provider.
/// </summary>
public class AsyncLock
{
private Task m_Current = null;
/// <summary>
/// Wait the lock asynchronously.
/// </summary>
/// <returns></returns>
public async Task<IDisposable> WaitAsync()
{
var Current = new TaskCompletionSource<bool>();
while (true)
{
Task Latest = null;
lock (this)
{
if (m_Current is null || m_Current.IsCompleted)
{
m_Current = Current.Task;
break;
}
Latest = m_Current;
}
await Latest;
}
return new ReleaseOnDispose(() => Current.TrySetResult(true));
}
/// <summary>
/// Release on Dispose.
/// </summary>
private struct ReleaseOnDispose : IDisposable
{
private Action m_Release;
/// <summary>
/// Construct a new ReleaseAsync structure using Release functor.
/// </summary>
/// <param name="Release"></param>
public ReleaseOnDispose(Action Release)
=> m_Release = Release;
/// <summary>
/// Release the Lock on dispose.
/// </summary>
public void Dispose() => m_Release?.Invoke();
}
}
Usage:
/// <summary>
/// Read bytes with buffered.
/// </summary>
/// <param name="Length"></param>
/// <returns></returns>
public async Task<byte[]> ReadAsync(int Length)
{
using (await m_ReadLock.WaitAsync())
{
byte[] Output = m_Buffer.Take(Length);
if (Output.Length <= 0)
{
int Read = await m_Link.ReadAsync(new ArraySegment<byte>(m_ByteBuffer));
if (Read <= 0)
{
await m_Link.CloseAsync();
return null;
}
if (Read > Length)
{
m_Buffer.Append(m_ByteBuffer, Length, Read - Length);
Read = Length;
}
Array.Resize(ref Output, Read);
Array.Copy(m_ByteBuffer, 0, Output, 0, Read);
}
return Output;
}
}
- Is this really better than traditionally used locks?
- Can my code be accepted on commercial development?
-
1\$\begingroup\$ Did I answer your question? \$\endgroup\$aepot– aepot2021年06月17日 20:53:09 +00:00Commented Jun 17, 2021 at 20:53
1 Answer 1
SemaphoreSlim
provides async locking out-of-the-box.
using var semaphore = new SemaphoreSlim(1);
// ...
await semaphore.WaitAsync();
try
{
// critical section code
}
finally
{
semaphore.Release();
}
Is this really better than traditionally used locks?
Nope. Because you're just wrapping monitors with new Task
instance spawn. It could be inefficient in performance.
Can my code be accepted on commercial development?
There's no sense in general to use the provided solution as .NET provides already existent and well-implemented one.