Skip to content

Commit

Permalink
Separate locks for different objects (sync + async)
Browse files Browse the repository at this point in the history
  • Loading branch information
o.nadymov committed Feb 27, 2024
1 parent 8c08cb0 commit cba6229
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 0 deletions.
32 changes: 32 additions & 0 deletions src/Spoleto.Common/Locks/AsyncLock.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using System;
using System.Threading;
using System.Threading.Tasks;

namespace Spoleto.Common.Locks
{
/// <summary>
/// The special lock for async body.
/// </summary>
public class AsyncLock : IDisposable
{
private readonly SemaphoreSlim _semaphoreSlim = new(1, 1);

/// <summary>
/// Creates the lock.
/// </summary>
/// <returns></returns>
public async Task<AsyncLock> LockAsync()
{
await _semaphoreSlim.WaitAsync().ConfigureAwait(false);
return this;
}

/// <summary>
/// Releases the lock.
/// </summary>
public void Dispose()
{
_semaphoreSlim.Release();
}
}
}
109 changes: 109 additions & 0 deletions src/Spoleto.Common/Locks/ObjectAsyncLocks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Spoleto.Common.Locks
{
/// <summary>
/// The static class for separate async locks for objects.
/// </summary>
/// <remarks>
/// Example:
/// var lockObject = ObjectAsyncLocks.GetObjectLock(lockObjetKey);<br/>
/// using (await lockObject.LockAsync())<br/>
/// {<br/>
/// try<br/>
/// {<br/>
/// // code<br/>
/// }<br/>
/// finally<br/>
/// {<br/>
/// ObjectAsyncLocks.ReleaseObjectLock(lockObjetKey);<br/>
/// }<br/>
/// }<br/>
/// </remarks>
public static class ObjectAsyncLocks
{
/// <summary>
/// The class of async locks with deep.
/// </summary>
public class AsyncIntLock : IDisposable
{
/// <summary>
/// The async lock object.
/// </summary>
private readonly AsyncLock _asyncLock;

/// <summary>
/// Default constructor.
/// </summary>
public AsyncIntLock()
{
_asyncLock = new AsyncLock();
}

/// <summary>
/// Locks deep.
/// </summary>
public int Deep { get; set; }

/// <summary>
/// Releases the lock.
/// </summary>
public void Dispose() => _asyncLock.Dispose();

/// <summary>
/// Creates the lock.
/// </summary>
public async Task<AsyncIntLock> LockAsync()
{
await _asyncLock.LockAsync().ConfigureAwait(false);
return this;
}

/// <summary>
/// Return text representation.
/// </summary>
/// <returns></returns>
public override string ToString() => $"Deep = {Deep}";
}


private static readonly Dictionary<string, AsyncIntLock> ObjectLocksDic = new();
private static readonly object CacheLock = new();

/// <summary>
/// Returns lock for object.
/// </summary>
public static AsyncIntLock GetObjectLock(string key)
{
lock (CacheLock)
{
if (!ObjectLocksDic.TryGetValue(key, out var cachedItem))
{
cachedItem = new AsyncIntLock();
ObjectLocksDic.Add(key, cachedItem);
}

cachedItem.Deep++;
return cachedItem;
}
}

/// <summary>
/// Release object.
/// </summary>
public static void ReleaseObjectLock(string key)
{
lock (CacheLock)
{
if (ObjectLocksDic.TryGetValue(key, out var cachedItem))
{
cachedItem.Deep--;
if (cachedItem.Deep == 0)
ObjectLocksDic.Remove(key);
}
}
}
}
}
80 changes: 80 additions & 0 deletions src/Spoleto.Common/Locks/ObjectLocks.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System.Collections.Generic;

namespace Spoleto.Common.Locks
{
/// <summary>
/// The static class for separate locks for objects.
/// </summary>
/// <remarks>
/// Example:
/// object lockObj = ObjectLocks.GetObjectLock(lockObjetKey);<br/>
/// lock (lockObj)
/// {<br/>
/// try<br/>
/// {<br/>
/// // code<br/>
/// }<br/>
/// finally<br/>
/// {<br/>
/// ObjectLocks.ReleaseObjectLock(lockObjetKey);<br/>
/// }<br/>
/// }<br/>
/// </remarks>
public static class ObjectLocks
{
/// <summary>
/// The class of locks with deep.
/// </summary>
private class IntLock
{
/// <summary>
/// Locks deep.
/// </summary>
public int Deep { get; set; }

/// <summary>
/// Return text representation.
/// </summary>
/// <returns></returns>
public override string ToString() => $"Deep = {Deep}";
}


private static readonly Dictionary<string, IntLock> ObjectLocksDic = new Dictionary<string, IntLock>();
private static readonly object CacheLock = new object();

/// <summary>
/// Returns lock for object.
/// </summary>
public static object GetObjectLock(string key)
{
lock (CacheLock)
{
if (!ObjectLocksDic.TryGetValue(key, out var cachedItem))
{
cachedItem = new IntLock();
ObjectLocksDic.Add(key, cachedItem);
}

cachedItem.Deep++;
return cachedItem;
}
}

/// <summary>
/// Release object.
/// </summary>
public static void ReleaseObjectLock(string key)
{
lock (CacheLock)
{
if (ObjectLocksDic.TryGetValue(key, out var cachedItem))
{
cachedItem.Deep--;
if (cachedItem.Deep == 0)
ObjectLocksDic.Remove(key);
}
}
}
}
}

0 comments on commit cba6229

Please sign in to comment.