using System.Collections.Concurrent; using WingServerCommon.Log; namespace WingServerCommon.Utilities { public class LockManager { private bool _isDistributed = false; private static object _acquireLocker = new object(); private ConcurrentDictionary _lockers = new ConcurrentDictionary(); public LockManager() { _isDistributed = false; Logger.WriteLineInfo($"LockManager init success, mode: Alone"); } public LockManager(Func OnGetLock, Func OnReleaseLock) { _isDistributed = true; DistributedLock.OnGetLock = OnGetLock; DistributedLock.OnReleaseLock = OnReleaseLock; Logger.WriteLineInfo($"LockManager init success, mode: Distributed"); } public async Task Acquire(string lockKey) { Logger.WriteLineInfo($"LockManager Acquire locker by key:{lockKey}"); ILocker locker; if (!_lockers.TryGetValue(lockKey, out locker)) { lock (_acquireLocker) { locker = _lockers.GetOrAdd(lockKey, (k) => { if (_isDistributed) { return new DistributedLock(lockKey); } else { return new StandAloneLock(lockKey); } }); } } return await locker.LockAsync(); } public void Release(string lockKey) { Logger.WriteLineInfo($"LockManager Release locker by key:{lockKey}"); if (_lockers.TryGetValue(lockKey, out ILocker locker)) { locker.Dispose(); } } } public interface ILocker : IDisposable { Task LockAsync(); } public class StandAloneLock : ILocker { SemaphoreSlim slimlock = new SemaphoreSlim(1, 1); private string _lockKey; private string _serialNumber; public StandAloneLock(string guid) { _lockKey = guid; } public async Task LockAsync() { await slimlock.WaitAsync(3 * 1000); _serialNumber = Guid.NewGuid().ToString("N"); Logger.WriteLineInfo($"LockManager StandAloneLock waitasync end, lockkey:{_lockKey}, serialNumber:{_serialNumber}"); return this; } public void Dispose() { slimlock.Release(); Logger.WriteLineInfo($"LockManager StandAloneLock release end, lockkey:{_lockKey}, serialNumber:{_serialNumber}"); } } public class DistributedLock : ILocker { public static Func OnGetLock; public static Func OnReleaseLock; private string _lockKey; private string _serialNumber; public DistributedLock(string guid) { _lockKey = guid; } public async Task LockAsync() { OnGetLock.Invoke(_lockKey); _serialNumber = Guid.NewGuid().ToString("N"); Logger.WriteLineInfo($"LockManager DistributedLock waitasync end, lockkey:{_lockKey}, serialNumber:{_serialNumber}"); return this; } public void Dispose() { OnReleaseLock.Invoke(_lockKey); Logger.WriteLineInfo($"LockManager DistributedLock release end, lockkey:{_lockKey}, serialNumber:{_serialNumber}"); } } }