Created
March 22, 2019 19:30
-
-
Save pmunin/acb77870ffa28e6d26b4c0ea97506361 to your computer and use it in GitHub Desktop.
AsyncLock
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace AsyncLockExtensions | |
{ | |
/// <summary> | |
/// Virtual critical section for async function. | |
/// Monitor.Enter/Exit and lock{} does not work for async methods and cause deadlocks and exceptions. AsyncLock solves these issues. Implementation copied from Microsoft.EntityFrameworkCore.Internal.AsyncLock (.nuget\packages\microsoft.entityframeworkcore\2.1.4\lib\netstandard2.0\Microsoft.EntityFrameworkCore.dll) | |
/// <seealso cref="https://github.com/neosmart/AsyncLock"/> | |
/// <example> | |
/// using(await _myLock.LockAsync()) | |
/// { | |
/// //critical section code | |
/// } | |
/// </example> | |
/// </summary> | |
public class AsyncLock | |
{ | |
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1); | |
private readonly AsyncLock.Releaser _releaser; | |
private readonly Task<AsyncLock.Releaser> _releaserTask; | |
public AsyncLock() | |
{ | |
this._releaser = new AsyncLock.Releaser(this); | |
this._releaserTask = Task.FromResult<AsyncLock.Releaser>(this._releaser); | |
} | |
public Task<AsyncLock.Releaser> LockAsync(CancellationToken cancellationToken = default(CancellationToken)) | |
{ | |
Task task = this._semaphore.WaitAsync(cancellationToken); | |
if (!task.IsCompleted) | |
return task.ContinueWith<AsyncLock.Releaser>((Func<Task, object, AsyncLock.Releaser>)((_, state) => ((AsyncLock)state)._releaser), (object)this, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); | |
return this._releaserTask; | |
} | |
public AsyncLock.Releaser Lock() | |
{ | |
this._semaphore.Wait(); | |
return this._releaser; | |
} | |
public struct Releaser : IDisposable | |
{ | |
private readonly AsyncLock _toRelease; | |
internal Releaser(AsyncLock toRelease) | |
{ | |
this._toRelease = toRelease; | |
} | |
public void Dispose() | |
{ | |
this._toRelease._semaphore.Release(); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment