using System.Collections.Concurrent; using Connected; namespace Connected.Threading; public class AsyncLocker : IDisposable { private ConcurrentDictionary _items = new(); private bool _disposed; private ConcurrentDictionary Items => _items; public async Task LockAsync(int semaphore, Func 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 LockAsync(int semaphore, Func> 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); } }