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.
75 lines
1.5 KiB
75 lines
1.5 KiB
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);
|
|
}
|
|
}
|