Реализация читателей и писателей с асинхронностью

В общем, есть задача реализовать репозиторий так, что бы читать могли много потоков, а писать один и при этом если чтение идет, то поток записи ждет.

Я набросал вот такую реализацию и мне интересно нет ли в ней подводных камней и можно ли ее улучшить:

В общем:

В классе имею словарь куда сохраняю на каждого читателя свой семафор:

private readonly ConcurrentDictionary<int, SemaphoreSlim> semaphoreDictionary = new ConcurrentDictionary<int, SemaphoreSlim>();

И один общий семафор:

    private readonly SemaphoreSlim _semaphoreSlim = new SemaphoreSlim(1);

Чтение реализовано вот так:

    public async Task<IEnumerable<Data>> Get(CancellationToken token)
    {
        int id = 0;
        SemaphoreSlim semaphore = null;
        try
        {
            id=Interlocked.Increment(ref _readerCount);
            semaphore =await  GetLockObject(id, token);
            return await ReadFromFileAsync(token);
        }
        finally
        {
            semaphore?.Release();
            id = Interlocked.Decrement(ref _readerCount);
        }
    }

    private async Task<SemaphoreSlim> GetLockObject(int id, CancellationToken token)
    {
        var semaphore = new SemaphoreSlim(1, 1);
        await semaphore.WaitAsync(token);
        await _semaphoreSlim.WaitAsync(token);
        semaphoreDictionary.TryAdd(id, semaphore);
        _semaphoreSlim.Release();
        return semaphore;
    }

А запись вот так:

  public async Task Remove(Data job, CancellationToken token)
        {
            try
            {
                await GetWriteLock(token);
                var result = (await ReadFromFileAsync(token)).ToList();
                result.RemoveAt(result.FindIndex(x => x.Id == job.Id));
                await WriteToFile(result, token);
            }
            finally
            {
                _semaphoreSlim.Release();
            }
        }

        private async Task GetWriteLock(CancellationToken token)
        {
            await _semaphoreSlim.WaitAsync(token);
            await Task.WhenAll(semaphoreDictionary.Values.Select(x => x.WaitAsync(token)));
            semaphoreDictionary.Clear();
        }

Вроде, должно работать четко. Что скажете?


Ответы (0 шт):