zoukankan      html  css  js  c++  java
  • (译)构建Async同步基元,Part 6 AsyncLock

    传送门:异步编程系列目录……

    最近在学习.NET4.5关于“并行任务”的使用。“并行任务”有自己的同步机制,没有显示给出类似如旧版本的:事件等待句柄、信号量、lockReaderWriterLock……等同步基元对象,但我们可以沿溪这一编程习惯,那么这系列翻译就是给“并行任务”封装同步基元对象。翻译资源来源《(译)关于AsyncAwaitFAQ

    1.         构建Async同步基元,Part 1 AsyncManualResetEvent

    2.         构建Async同步基元,Part 2 AsyncAutoResetEvent

    3.         构建Async同步基元,Part 3 AsyncCountdownEvent

    4.         构建Async同步基元,Part 4 AsyncBarrier

    5.         构建Async同步基元,Part 5 AsyncSemaphore

    6.         构建Async同步基元,Part 6 AsyncLock

    7.         构建Async同步基元,Part 7 AsyncReaderWriterLock

     

    源码:构建Async同步基元.rar

    开始:构建Async同步基元,Part 6 AsyncLock

             最近,我们刚刚构建了一个AsyncSemphore,现在,我们来构建一个在using块中支持异步互斥机制的类型。

             正如前面帖子所述,信号量非常适用于限流及资源访问管理。你可以给信号量一个初始计数,然后它将只允许指定数量的消费者成功获得信号,强迫多余的请求等待直到资源被释放内部信号计数大于0信号量可以用来保护正确进入特定代码区域,并且内部计数可以设置为1。通过这种方式,你能使用信号量来达到互斥目的,比如:

    private readonly AsyncSemaphore m_lock = new AsyncSemaphore(1); 
    … 
    await m_lock.WaitAsync(); 
    try 
    { 
        … // protected code here 
    }  
    finally
    { 
        m_lock.Release();
    }

             我们可以通过创建一个AsyncLock类型来支持使用using关键字来简化编码。我们的目的是和上面片段一致的,但是通过类似下面的代码来实现:

    private readonly AsyncLock m_lock = new AsyncLock(); 
    … 
    using(var releaser = await m_lock.LockAsync()) 
    { 
        … // protected code here 
    }

    为了达到这样的效果,我们将构建下面这样的类型:

    public class AsyncLock 
    { 
        public AsyncLock();
        public Task<Releaser> LockAsync();
        public struct Releaser : IDisposable 
        { 
            public void Dispose(); 
        } 
    }

    在内部,我们将维护两个成员。我们使用AsyncSemaphore对象来处理大部分逻辑,使用m_releaser变量缓存的Task<Releaser>实例,当访问的锁没有竞争时,可以直接返回从而避免不必要的分配。

    private readonly AsyncSemaphore m_semaphore; 
    private readonly Task<Releaser> m_releaser;

    Releaser结构仅仅是实现了IDisposable接口的Dispose()方法,该方法将释放底层的信号量。这是允许我们在using块中使用Releaser构造的原因,由using自动生成的finally块将调用Dispose()方法,即Seamphore实例的Release()方法来进行释放。

    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(); 
        } 
    }

    我们的AsyncLock的构造函数仅仅是初始化成员,使用数值为1的参数创建一个Semaphore,并且创建一个缓存的Task<Releaser>

    public AsyncLock() 
    { 
        m_semaphore = new AsyncSemaphore(1); 
        m_releaser = Task.FromResult(new Releaser(this)); 
    }

    最后,构建我们的LockAsync方法。我们首先调用SemaphoreWaitAsync()获得一个Task,用于指代我们获得的锁。如果Task已经完成,则同步返回缓存的Task<Releaser>,这也意味着如果锁没有竞争就不需要分配。如果Task没有完成,则返回一个Task<Releaser>的延续任务。

    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); 
    }

     

    这就是本节要讲的AsyncLock

    完整源码如下:

        public class AsyncLock
        {
            private readonly AsyncSemaphore m_semaphore;
            // 缓存Task<Releaser>实例,当访问的锁没有竞争时,可以直接返回从而避免不必要的分配。
            private readonly Task<Releaser> m_releaser;
    
            public AsyncLock()
            {
                // 信号量为1,用于实现互斥
                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;
                }
                // using块生成的finally块调用IDisposable接口的Dispose()方法
                public void Dispose()
                {
                    if (m_toRelease != null)
                        m_toRelease.m_semaphore.Release();
    
                }
            }
        }
    
        /// <summary>
        /// 使用方式
        /// </summary>
        public class AsyncLock_Test
        {
            private readonly AsyncLock m_lock = new AsyncLock();
            public async void Test()
            {
                using (var releaser = await m_lock.LockAsync())
                {
                    // 限制访问代码
                }
            }
        }

     

    下一节,我将实现一个异步版本的 read/writer 锁。

                                                                                                                    

    推荐阅读:

                       异步编程:同步基元对象(上)

                       异步编程:同步基元对象(下)

     

    感谢你的观看……

    原文:Building Async Coordination Primitives, Part 6: AsyncLock

    作者:Stephen Toub – MSFT

     

  • 相关阅读:
    2015百度之星 放盘子
    2015百度之星 IP聚合
    2015百度之星 列变位法解密
    2015百度之星 大搬家
    数论 --- 费马小定理 + 快速幂 HDU 4704 Sum
    组合数(Lucas定理) + 快速幂 --- HDU 5226 Tom and matrix
    Linux
    概率论 --- Uva 11181 Probability|Given
    JAVA
    网络爬虫-原理篇(二)
  • 原文地址:https://www.cnblogs.com/heyuquan/p/2863094.html
Copyright © 2011-2022 走看看