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


      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     }
  • 相关阅读:
    截取
    逃避系统警察
    刷题
    排队
    侦察兵
    朋友
    楼层
    解码
    倒水
    魔法阵
  • 原文地址:https://www.cnblogs.com/xuejietong/p/8994357.html
Copyright © 2020-2023  润新知