Реализация читателей и писателей с асинхронностью
В общем, есть задача реализовать репозиторий так, что бы читать могли много потоков, а писать один и при этом если чтение идет, то поток записи ждет.
Я набросал вот такую реализацию и мне интересно нет ли в ней подводных камней и можно ли ее улучшить:
В общем:
В классе имею словарь куда сохраняю на каждого читателя свой семафор:
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();
}
Вроде, должно работать четко. Что скажете?