Skip to content

Instantly share code, notes, and snippets.

@ntrpnr
Last active June 24, 2018 15:34
Show Gist options
  • Save ntrpnr/a8cd8b31ef24fbd6f9a3277c5bf471f6 to your computer and use it in GitHub Desktop.
Save ntrpnr/a8cd8b31ef24fbd6f9a3277c5bf471f6 to your computer and use it in GitHub Desktop.
Example in C# .NET Core on how to use lock on a specific entity for async operations with SemaphoreSlim
public class GameService
{
// Lock cannot be used async. Instead we use Semaphores.
// We want to avoid race conditions for our game operations.
// With this approach we can make sure that only one operation is performed against a specific game at once.
//This dictionary contains a semaphore for each game's Id.
private readonly Dictionary<Guid, SemaphoreSlim> lockers = new Dictionary<Guid, SemaphoreSlim>();
private SemaphoreSlim GetLocker(Guid id)
{
lock (lockers)
{
if (!lockers.ContainsKey(id))
// If we don't already have a semaphore for this game's Id, create it. It should only have one slot.
lockers.Add(id, new SemaphoreSlim(1));
return lockers[id];
}
}
public async Task<Game> AddUserToGame(User user, Game game)
{
var locker = GetLocker(game.Id);
await locker.WaitAsync();
try
{
if (game.Participants.Contains(user))
return game;
game.Participants.Add(user);
var result = this.storage.InsertOrUpdateAsync(game);
return await result;
}
// Use a finally block to make sure that the Semaphore is ALWAYS released.
finally
{
locker.Release();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment