• 锁定与并发


         在多线程程序中,我们经常需要对要访问的资源进行加锁。加锁的目的是为了同步对资源的访问,但是,加锁不可避免的会降低应用的并发量。那么如何在需要加锁的时候,尽可能地提高并发量了?下面是我的一些经验,仅供参考。

     1.首先,我们要控制好锁的粒度。

         锁的粒度越大,能支持的并发就越小。

         我们只需要将真正需要同步的代码块lock住,而不需要同步的代码块不要放在lock块中。

         当然,锁的粒度也不是越小越好,粒度太细的锁会导致编程很繁琐,而且需要足够的细心和全面考虑方可保证锁不会出现问题。

         在这点上,有一个特别需要注意的是 -- 事件。事件最好不要在lock块中触发,因为你无法确定组件应用者的事件处理函数会执行多久。除非,你对一切了然于胸。

                lock (this.locker)
                {
                    
    //

                    
    this.OnSomeEvent(); //触发事件
                }

    2.杜绝死锁的发生。当发生死锁时,并发将降到最低。

    3.区分读写。

         我们经常使用lock关键字来锁定资源,然而,lock没有办法区分读写。比如,如果当前同时有三个线程在访问资源,且三个都是读取资源,如果使用lock,那么,在读取资源上,它们也会被同步处理。幸运的是,.NET为我们提供了读写锁 -- ReaderWriterLock ,使用它,上面的例子便是三个线程可以同时读取资源。

         对于那种读取多于修改的资源,区分读写可以极大地提升并发量。

         ReaderWriterLock的使用不如lock来得方便,为此,我封装了SmartRWLocker,它提供了和ReaderWriterLock一样的功能,但是我们可以像使用lock一样来使用它,如: 

                using(this.smartRWLocker.Lock(AccessMode.Read))
                {
                    
    //do something
                }

         SmartRWLocker的实现也相当简单,如下所示:

         /// <summary>
        
    /// SmartRWLocker 简化了ReaderWriterLock的使用。zhuweisky 2008.11.25
        
    /// </summary>
        public class SmartRWLocker
        {
            
    private ReaderWriterLock readerWriterLock = new ReaderWriterLock();

            
    public LockingObject Lock(AccessMode accessMode)
            {
                
    return new LockingObject(this.readerWriterLock, accessMode);
            }
        }   

        
    /// <summary>
        
    /// AccessMode 访问锁定资源的方式。
        
    /// </summary>
        public enum AccessMode
        {       
            Read 
    = 0,
            Write
        }

    public class LockingObject : IDisposable
        {
            
    private ReaderWriterLock readerWriterLock;
            
    private AccessMode accessMode = AccessMode.Read;

            
    #region Ctor
            
    public LockingObject(ReaderWriterLock _lock, AccessMode _lockMode)
            {
                
    this.readerWriterLock = _lock;
                
    this.accessMode = _lockMode;

                
    if (this.accessMode == AccessMode.Read)
                {
                    
    this.readerWriterLock.AcquireReaderLock(-1);
                }
                
    else
                {
                    
    this.readerWriterLock.AcquireWriterLock(-1);
                }
            }
            
    #endregion

            
    #region IDisposable 成员

            
    public void Dispose()
            {
                
    if (this.accessMode == AccessMode.Read)
                {
                    
    this.readerWriterLock.ReleaseReaderLock();
                }
                
    else
                {
                    
    this.readerWriterLock.ReleaseWriterLock();
                }
            }
            
    #endregion
        }

     2009.02.23 附加:

         我们都知道,对于集合类,如Lits<>,Dictionary<,>等,

    (1)如果其它线程在对其中的元素进行修改(如添加或删除元素)时,正在对集合进行枚举的线程会抛出异常。

    (2)如果有一个线程正在对集合进行修改,另外一个线程调用Contains/ContainsKey,会抛出异常吗?答案是不会

  • 相关阅读:
    YAML 语法小结
    小程序之脚本语言
    小程序WXML 使用小结
    微信小程序 js逻辑
    小程序开发1
    联想Y7000安装Ubuntu16.04/Win10双系统,wifi问题,显卡驱动和CUDA10安装
    VS2015中配置Eigen
    联想Y700安装显卡驱动和CUDA8.0
    php微信生成微信公众号二维码扫描进入公众号带参数
    Y7000 (1)安装ubuntu1604遇到的问题
  • 原文地址:https://www.cnblogs.com/zhuweisky/p/1341154.html
Copyright © 2020-2023  润新知