jellyfin-plugin-anidb/Jellyfin.Plugin.AniDB/AsyncLock.cs

91 lines
2.5 KiB
C#
Raw Normal View History

2013-10-29 16:26:07 +00:00
// http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
namespace Jellyfin.Plugin.AniDB
2013-10-29 16:26:07 +00:00
{
public class AsyncSemaphore
{
private static readonly Task Completed = Task.FromResult(true);
private readonly Queue<TaskCompletionSource<bool>> _waiters = new Queue<TaskCompletionSource<bool>>();
private int _currentCount;
2017-11-12 14:08:30 +00:00
2013-10-29 16:26:07 +00:00
public AsyncSemaphore(int initialCount)
{
if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
_currentCount = initialCount;
}
public Task WaitAsync()
{
lock (_waiters)
{
if (_currentCount > 0)
{
--_currentCount;
return Completed;
}
var waiter = new TaskCompletionSource<bool>();
_waiters.Enqueue(waiter);
return waiter.Task;
}
}
public void Release()
{
TaskCompletionSource<bool> toRelease = null;
lock (_waiters)
{
if (_waiters.Count > 0)
toRelease = _waiters.Dequeue();
else
++_currentCount;
}
if (toRelease != null)
toRelease.SetResult(true);
}
}
public class AsyncLock
{
private readonly Task<Releaser> _releaser;
private readonly AsyncSemaphore _semaphore;
public AsyncLock()
{
_semaphore = new AsyncSemaphore(1);
_releaser = Task.FromResult(new Releaser(this));
}
public Task<Releaser> LockAsync()
{
Task wait = _semaphore.WaitAsync();
return wait.IsCompleted
? _releaser
2017-11-12 14:08:30 +00:00
: wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
2013-10-29 16:26:07 +00:00
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
public struct Releaser : IDisposable
{
private readonly AsyncLock _toRelease;
internal Releaser(AsyncLock toRelease)
{
_toRelease = toRelease;
}
public void Dispose()
{
if (_toRelease != null)
_toRelease._semaphore.Release();
}
}
}
2019-02-05 12:11:05 +00:00
}