You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Framework/Connected.Threading/AsyncLocker.cs

75 lines
1.5 KiB

2 years ago
using System.Collections.Concurrent;
using Connected;
namespace Connected.Threading;
public class AsyncLocker : IDisposable
{
private ConcurrentDictionary<int, AsyncLockerSlim> _items = new();
private bool _disposed;
private ConcurrentDictionary<int, AsyncLockerSlim> Items => _items;
public async Task LockAsync(int semaphore, Func<Task> worker)
{
if (Items.TryGetValue(semaphore, out AsyncLockerSlim? locker))
await locker.LockAsync(worker);
var newLocker = new AsyncLockerSlim();
if (Items.TryAdd(semaphore, newLocker))
await newLocker.LockAsync(worker);
else
{
newLocker.Dispose();
if (!Items.TryGetValue(semaphore, out AsyncLockerSlim? existing))
throw new SysException(this, SR.ErrLock);
await existing.LockAsync(worker);
}
}
public async Task<T> LockAsync<T>(int semaphore, Func<Task<T>> worker)
{
if (Items.TryGetValue(semaphore, out AsyncLockerSlim? locker))
return await locker.LockAsync(worker);
var newLocker = new AsyncLockerSlim();
if (Items.TryAdd(semaphore, newLocker))
return await newLocker.LockAsync(worker);
else
{
newLocker.Dispose();
if (!Items.TryGetValue(semaphore, out AsyncLockerSlim? existing))
throw new SysException(this, SR.ErrLock);
return await existing.LockAsync(worker);
}
}
protected virtual void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
foreach (var slim in Items)
slim.Value.Dispose();
Items.Clear();
}
_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}