C# KeyedSemaphore

Date: 2025-03-31
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;

public class KeyedSemaphore
{
    private readonly ConcurrentDictionary<string, Lazy<SemaphoreSlim>> _semaphores =
        new ConcurrentDictionary<string, Lazy<SemaphoreSlim>>();

    public async Task<IDisposable> LockAsync(string key)
    {
        var semaphore = _semaphores.GetOrAdd(key, k => new Lazy<SemaphoreSlim>(() => new SemaphoreSlim(1, 1))).Value;
        await semaphore.WaitAsync();
        return new Releaser(this, key);
    }

    private void Release(string key)
    {
        if (_semaphores.TryGetValue(key, out var lazySemaphore))
        {
            var semaphore = lazySemaphore.Value;
            semaphore.Release();

            // Opruimen als er geen wachtende taken meer zijn
            if (semaphore.CurrentCount == 1)
            {
                _semaphores.TryRemove(key, out _);
            }
        }
    }

    private class Releaser : IDisposable
    {
        private readonly KeyedSemaphore _keyedSemaphore;
        private readonly string _key;

        public Releaser(KeyedSemaphore keyedSemaphore, string key)
        {
            _keyedSemaphore = keyedSemaphore;
            _key = key;
        }

        public void Dispose()
        {
            _keyedSemaphore.Release(_key);
        }
    }
}

Or use a library like: https://github.com/amoerie/keyed-semaphores

93870cookie-checkC# KeyedSemaphore