Насколько корректен этот AsyncLock?
От: IObserver Ниоткуда  
Дата: 27.09.12 06:57
Оценка:
В блоге нашел реализацию 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);
        }
    }
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.