none
如果在lock块中使用await RRS feed

  • 问题

  • 代码中用到了多线程,其中一段代码我想这样实现

    lock(locker){
    
    	//do something
    
    	await Run();
    
           //do something
    
    }

    但编译器告知不能在lock块中用await.

    如果我改成这样:

    Monitor.Enter(locker);
    
    //do something
    
    await Run();
    
    //do something
    
    Monitor.Exit(locker);
    
    
    这样虽然可以编译过,但我想知道这样会有什么影响?

    2012年8月15日 6:00

答案

  • 根据此文,http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266983.aspx and http://blogs.msdn.com/b/pfxteam/archive/2012/02/12/10266988.aspx

    我们可以通过自己设计信号量操作,来实现异步下的同步锁。原理很简单,通过计数器来判定资源是否被占用,然后异步等待其有效后,进行lock ,使用完毕进行释放。Blogs中的两个类型的实现如下:

        public class AsyncSemaphore
        {
            private readonly static Task s_completed = Task.FromResult(true);
            private 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);
            }
        }
        public class AsyncLock
        {
            private readonly AsyncSemaphore m_semaphore;
            private readonly Task<Releaser> m_releaser;
            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);
            }
            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();
                }
            }
        }

    使用:

    private readonly AsyncLock m_lock = new AsyncLock();
    using (await m_lock.LockAsync())
    {
        await Run();
    }


    Bob Bao [MSFT]
    MSDN Community Support | Feedback to us

    • 已标记为答案 troyou 2012年8月17日 2:19
    2012年8月16日 3:58
    版主