Skip to content

Instantly share code, notes, and snippets.

@0x49D1
Last active January 21, 2022 10:36
Show Gist options
  • Save 0x49D1/a28eac0c17272c36184f8c4b39c9cc3b to your computer and use it in GitHub Desktop.
Save 0x49D1/a28eac0c17272c36184f8c4b39c9cc3b to your computer and use it in GitHub Desktop.
Locking mechanics with named locks for async operations. After finishing lock code block this code releases semaphore itself. Standard "lock" statement can't be used with async operations: https://stackoverflow.com/a/7612714/47672
// Usage example:
// static readonly SemaphoreLocker _semaphoreLocker = new SemaphoreLocker();
// var values = await _semaphoreLocker.LockAsync(valuesKey, async () => { return await SomeActionAsync(); });
public class SemaphoreLocker
{
static readonly ConcurrentDictionary<string, SemaphoreSlim> lockDictionary = new ConcurrentDictionary<string, SemaphoreSlim>();
public async Task LockAsync(string key, Func<Task> worker)
{
SemaphoreSlim semaphore = lockDictionary.GetOrAdd(key, new SemaphoreSlim(1, 1));
await semaphore.WaitAsync();
try
{
await worker();
}
finally
{
semaphore.Release();
lockDictionary.TryRemove(key, out semaphore);
}
}
// Overloading variant for non-void methods with return type (generic T)
public async Task<T> LockAsync<T>(string key, Func<Task<T>> worker)
{
SemaphoreSlim semaphore = lockDictionary.GetOrAdd(key, new SemaphoreSlim(1, 1));
await semaphore.WaitAsync();
try
{
return await worker();
}
finally
{
semaphore.Release();
lockDictionary.TryRemove(key, out semaphore);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment