В блоге нашел реализацию AsyncLock:
http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx
Сделано не корректно, что видно из примера:
class Program
{
static readonly AsyncLock al = new AsyncLock();
static bool called = false;
static void Main(string[] args)
{
AsyncCaller();
Console.ReadLine();
}
static async void AsyncCaller()
{
await DoItAsync();
Console.WriteLine("Done"); // Программа не завершается
}
static async Task DoItAsync()
{
Console.WriteLine("before lock");
using (await al.LockAsync())
{
Console.WriteLine("after lock"); // Не вызывается второй раз!!!
if (!called)
{
called = true;
await DoItAsync();
}
}
}
}
Согласны ли вы, что реализовано не корректно? И второй вопрос: где взять корректную реализацию?
На всякий случай приведу код этого AsyncLock, чтобы вам не лень было смотреть:
| Скрытый текст |
| class AsyncSemaphore
{
private readonly static Task s_completed = Task.FromResult(true);
public readonly Queue<TaskCompletionSource<bool>> m_waiters = new Queue<TaskCompletionSource<bool>>();
private int m_currentCount;
public AsyncSemaphore(int initialCount)
{
if (initialCount < 0) throw new ArgumentOutOfRangeException("initialCount");
m_currentCount = initialCount;
}
public Task WaitAsync()
{
lock (m_waiters)
{
if (m_currentCount > 0)
{
--m_currentCount;
return s_completed;
}
else
{
var waiter = new TaskCompletionSource<bool>();
m_waiters.Enqueue(waiter);
return waiter.Task;
}
}
}
public void Release()
{
TaskCompletionSource<bool> toRelease = null;
lock (m_waiters)
{
if (m_waiters.Count > 0)
toRelease = m_waiters.Dequeue();
else
++m_currentCount;
}
if (toRelease != null)
toRelease.SetResult(true);
}
}
class AsyncLock
{
public readonly AsyncSemaphore m_semaphore;
private readonly Task<Releaser> m_releaser;
public struct Releaser : IDisposable
{
private readonly AsyncLock m_toRelease;
internal Releaser(AsyncLock toRelease) { m_toRelease = toRelease; }
public void Dispose()
{
if (m_toRelease != null)
m_toRelease.m_semaphore.Release();
}
}
public AsyncLock()
{
m_semaphore = new AsyncSemaphore(1);
m_releaser = Task.FromResult(new Releaser(this));
}
public Task<Releaser> LockAsync()
{
var wait = m_semaphore.WaitAsync();
return wait.IsCompleted ?
m_releaser :
wait.ContinueWith((_, state) => new Releaser((AsyncLock)state),
this, CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);
}
}
|
| |