自旋和线程所有权及递归构成混合锁

  1     /// <summary>
  2     /// 自旋、线程所有权、递归
  3     /// 构成混合锁
  4     /// </summary>
  5     internal sealed class AnotherHybridLock : IDisposable
  6     {
  7         //基元用户模式构造(Interlocked的方法)使用
  8         private int m_waiters = 0;
  9 
 10         //基元内核模式构造
 11         //AutoResetEvent通知正在等待的线程已发生事件
 12         // true将初始状态设置为终止状态; false将初始状态设置为非终止
 13         //true有信号(不会阻塞),false无信号
 14         private AutoResetEvent m_waiterLock = new AutoResetEvent(false);
 15 
 16         //控制自旋,希望能提升性能
 17         //选择一个计数
 18         private int m_spinCount = 4000;
 19 
 20         //指出哪个线程拥有锁
 21         private int m_owningThreadId = 0;
 22 
 23         //指出拥有锁的线程拥有了多少次锁
 24         private int m_recursion = 0;
 25 
 26         public void Enter()
 27         {
 28             //获取当前托管线程的唯一标识符
 29             int threadId = Thread.CurrentThread.ManagedThreadId;
 30 
 31             //如果调用线程已经拥有锁
 32             if (threadId == m_owningThreadId)
 33             {
 34                 //递增递归计数并返回
 35                 m_recursion++;
 36                 return;
 37             }
 38 
 39             //调用线程未拥有锁,尝试获取它
 40             //为基于自旋的等待提供支持
 41             SpinWait spinWait = new SpinWait();
 42             for (int spinCount = 0; spinCount < m_spinCount; spinCount++)
 43             {
 44                 //第一个线程时m_waiters始终返回0,直接获得锁
 45                 if (Interlocked.CompareExchange(ref m_waiters, 1, 0) == 0)
 46                 {
 47                     goto GotLock;
 48                 }
 49 
 50                 //给其它线程运行的机会,希望锁会被释放
 51                 spinWait.SpinOnce();
 52             }
 53 
 54             //自旋结束,锁仍未获得,再试一次
 55             //m_waiters若等于0,则1>1不成立,不必WaitOne,直接获得锁
 56             //否则WaitOne
 57             if (Interlocked.Increment(ref m_waiters) > 1)
 58             {
 59                 //仍然是竞争条件,这个线程必须被阻塞
 60                 //等待锁,性能有较大损失
 61                 m_waiterLock.WaitOne();
 62                 //等这个线程醒来时,它拥有锁,设置一些状态并返回
 63             }
 64 
 65             GotLock:
 66             //线程获得锁时,记录线程Id
 67             m_owningThreadId = threadId;
 68             //指出该线程拥有锁1次
 69             m_recursion = 1;
 70         }
 71 
 72         public void Leave()
 73         {
 74             //如果调用线程不拥有锁,则表明存在bug
 75             int threadId = Thread.CurrentThread.ManagedThreadId;
 76             if (threadId != m_owningThreadId)
 77             {
 78                 //当某个方法要求调用方拥有给定 Monitor 上的锁并且该方法由不拥有该锁的调用方调用时引发的异常
 79                 throw new SynchronizationLockException("Lock not owned by calling thread");
 80             }
 81 
 82             //递减递归计数
 83             --m_recursion;
 84             //如果该线程仍然拥有锁
 85             if (m_recursion > 0)
 86             {
 87                 //直接返回
 88                 return;
 89             }
 90 
 91             //执行到这里说明现在没有线程拥有锁
 92             m_owningThreadId = 0;
 93 
 94             //如果没有其它线程在等待则直接返回
 95             if (Interlocked.Decrement(ref m_waiters) == 0)
 96             {
 97                 return;
 98             }
 99 
100             //否则,有其它线程正在等待,唤醒其中一个
101             //这里会有较大的性能损失
102             m_waiterLock.Set();
103         }
104 
105         public void Dispose()
106         {
107             m_waiterLock.Dispose();
108         }
109     }

 

posted on 2018-05-12 11:22  庭前花满留晚照  阅读(269)  评论(0编辑  收藏  举报

导航